| File: | butc/dump.c |
| Location: | line 299, column 6 |
| Description: | Value stored to 'bytesread' is never read |
| 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 | #include <roken.h> |
| 14 | |
| 15 | #include <rx/xdr.h> |
| 16 | #include <rx/rx.h> |
| 17 | #include <lwp.h> |
| 18 | #include <lock.h> |
| 19 | #include <afs/tcdata.h> |
| 20 | #include <afs/bubasics.h> |
| 21 | #include <afs/budb_client.h> |
| 22 | #include <afs/butm_prototypes.h> |
| 23 | #include <afs/vldbint.h> |
| 24 | #include <afs/ktime.h> |
| 25 | #include <afs/vlserver.h> |
| 26 | #include <afs/volser.h> |
| 27 | #include <afs/volser_prototypes.h> |
| 28 | #include <afs/volint.h> |
| 29 | #include <afs/cellconfig.h> |
| 30 | #include <afs/bucoord_prototypes.h> |
| 31 | |
| 32 | #include "butc_internal.h" |
| 33 | #include "error_macros.h" |
| 34 | #include "butc_xbsa.h" |
| 35 | #include "afs/butx.h" |
| 36 | |
| 37 | /* GLOBAL CONFIGURATION PARAMETERS */ |
| 38 | extern int dump_namecheck; |
| 39 | extern int queryoperator; |
| 40 | extern int isafile; |
| 41 | extern int forcemultiple; |
| 42 | |
| 43 | extern struct ubik_client *cstruct; |
| 44 | dlqlinkT savedEntries; |
| 45 | dlqlinkT entries_to_flush; |
| 46 | |
| 47 | extern afs_int32 groupId; |
| 48 | extern afs_int32 BufferSize; |
| 49 | extern afs_int32 statusSize; |
| 50 | extern FILE *centralLogIO; |
| 51 | afs_int32 lastPass = 0; |
| 52 | #ifdef xbsa |
| 53 | extern afs_int32 xbsaType; |
| 54 | char *butcdumpIdStr = "/backup_afs_volume_dumps"; |
| 55 | extern struct butx_transactionInfo butxInfo; |
| 56 | extern char *xbsaObjectOwner; |
| 57 | extern char *appObjectOwner; |
| 58 | extern char *xbsaSecToken; |
| 59 | extern char *xbsalGName; |
| 60 | extern char *globalButcLog; |
| 61 | #endif /*xbsa */ |
| 62 | |
| 63 | afs_int32 dataSize; /* Size of data to read on each rx_Read() call */ |
| 64 | afs_int32 tapeblocks; /* Number of 16K tape datablocks in buffer (!CONF_XBSA) */ |
| 65 | |
| 66 | /* TBD |
| 67 | * |
| 68 | * Done 1) dump id generation |
| 69 | * Done xx) volume fragment number accounting !! I think. |
| 70 | * 2) check abort - check after subroutine calls |
| 71 | * Done 3) trailer anomaly |
| 72 | * 4) trailer damage indicator after partial dumps ( affects scandump ) |
| 73 | * Done 5) Ensure mount failure logged |
| 74 | * 6) Ensure bucoord status calls work |
| 75 | * |
| 76 | * notes |
| 77 | * pass 3: |
| 78 | * keep token timeout. If no user reponse (idle time > some period) |
| 79 | * and tokens about to time out, terminate dump. This provides at |
| 80 | * least something usable. |
| 81 | */ |
| 82 | |
| 83 | #define DUMPNAME(dumpname, name, dbDumpId)if (dbDumpId == 0) sprintf(dumpname, "%s", name); else sprintf (dumpname, "%s (DumpId %u)", name, dbDumpId); \ |
| 84 | if (dbDumpId == 0) \ |
| 85 | sprintf(dumpname, "%s", name); \ |
| 86 | else \ |
| 87 | sprintf(dumpname, "%s (DumpId %u)", name, dbDumpId); |
| 88 | |
| 89 | struct dumpRock { |
| 90 | /* status only */ |
| 91 | int tapeSeq; |
| 92 | int curVolume; /* index in dumpNode of volume */ |
| 93 | int curVolumeStatus; /* more explicit dump state */ |
| 94 | afs_uint32 curVolStartPos; /* Starting position of the current volume */ |
| 95 | afs_uint32 databaseDumpId; /* real dump id, for db */ |
| 96 | afs_uint32 initialDumpId; /* the initial dump, for appended dumps */ |
| 97 | afs_int32 volumesDumped; /* # volumes successfully dumped */ |
| 98 | afs_int32 volumesFailed; /* # volumes that failed to dump */ |
| 99 | afs_int32 volumesNotDumped; /* # volumes that were not dumped (didn't fail) */ |
| 100 | |
| 101 | /* tape management */ |
| 102 | char tapeName[TC_MAXTAPENAMELEN100]; |
| 103 | struct butm_tapeInfo *tapeInfoPtr; |
| 104 | struct butm_tapeLabel tapeLabel; |
| 105 | int wroteLabel; /* If the tape label is written */ |
| 106 | |
| 107 | /* database information */ |
| 108 | struct budb_dumpEntry lastDump; /* the last dump of this volset */ |
| 109 | struct budb_dumpEntry dump; /* current dump */ |
| 110 | struct budb_tapeEntry tape; /* current tape, not used -VA */ |
| 111 | |
| 112 | /* links to existing info */ |
| 113 | struct dumpNode *node; |
| 114 | }; |
| 115 | |
| 116 | /* Forward declarations */ |
| 117 | |
| 118 | int makeVolumeHeader(struct volumeHeader *, struct dumpRock *, int); |
| 119 | int volumeHeader_hton(struct volumeHeader *, struct volumeHeader *); |
| 120 | char retryPrompt(char *, afs_int32, afs_uint32); |
| 121 | int getDumpTape(struct dumpRock *, int, afs_int32); |
| 122 | int getXBSATape(struct dumpRock *); |
| 123 | afs_int32 createDump(struct dumpRock *); |
| 124 | |
| 125 | /* configuration variables */ |
| 126 | #define HITEOT(code)((code == (156568837L)) || (code == (156568842L)) || (code == (156568848L))) ((code == BUTM_IO(156568837L)) || (code == BUTM_EOT(156568842L)) || (code == BUTM_IOCTL(156568848L))) |
| 127 | extern int autoQuery; |
| 128 | extern int maxpass; |
| 129 | |
| 130 | afs_int32 tc_EndMargin; |
| 131 | afs_int32 tc_KEndMargin; |
| 132 | static char *bufferBlock; |
| 133 | |
| 134 | /* compute the absolute expiration date */ |
| 135 | afs_int32 |
| 136 | calcExpirationDate(afs_int32 expType, afs_int32 expDate, afs_int32 createTime) |
| 137 | { |
| 138 | struct ktime_date kd; |
| 139 | |
| 140 | switch (expType) { |
| 141 | case BC_REL_EXPDATE2: |
| 142 | /* expiration date is relative to the creation time of the dump. |
| 143 | * This is the only case that requires any work |
| 144 | */ |
| 145 | Int32To_ktimeRelDate(expDate, &kd); |
| 146 | return (Add_RelDate_to_Time(&kd, createTime)); |
| 147 | |
| 148 | case BC_ABS_EXPDATE1: |
| 149 | return (expDate); |
| 150 | |
| 151 | case BC_NO_EXPDATE0: |
| 152 | default: |
| 153 | return (0); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | afs_uint32 curr_bserver = 0; |
| 158 | struct rx_connection *curr_fromconn = (struct rx_connection *)0; |
| 159 | |
| 160 | struct rx_connection * |
| 161 | Bind(afs_uint32 server) |
| 162 | { |
| 163 | if (curr_fromconn) { |
| 164 | if (curr_bserver == server) /* Keep connection if have it */ |
| 165 | return (curr_fromconn); |
| 166 | |
| 167 | rx_DestroyConnection(curr_fromconn); /* Otherwise get rid of it */ |
| 168 | curr_fromconn = (struct rx_connection *)0; |
| 169 | curr_bserver = 0; |
| 170 | } |
| 171 | |
| 172 | if (server) { |
| 173 | curr_fromconn = UV_Bind(server, AFSCONF_VOLUMEPORT7005); /* Establish new connection */ |
| 174 | if (curr_fromconn) |
| 175 | curr_bserver = server; |
| 176 | } |
| 177 | |
| 178 | return (curr_fromconn); |
| 179 | } |
| 180 | |
| 181 | /* notes |
| 182 | * 1) save the chunksize or otherwise ensure tape space remaining is |
| 183 | * check frequently enough |
| 184 | * 2) This is called once. For partial dumps, need to |
| 185 | * ensure that the tape device is left in the correct state for |
| 186 | * further dumps. |
| 187 | * |
| 188 | */ |
| 189 | #define BIGCHUNK102400 102400 |
| 190 | |
| 191 | afs_int32 |
| 192 | dumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr) |
| 193 | { |
| 194 | struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr; |
| 195 | struct dumpNode *nodePtr = dparamsPtr->node; |
| 196 | afs_int32 taskId = nodePtr->taskID; |
| 197 | char *buffer; |
| 198 | int fragmentNumber; |
| 199 | afs_int32 volumeFlags; |
| 200 | afs_int32 kRemaining; |
| 201 | afs_int32 rc, code = 0; |
| 202 | afs_int32 toread; |
| 203 | afs_uint32 volBytesRead; |
| 204 | afs_uint32 chunkSize; |
| 205 | afs_int32 bytesread; /* rx reads */ |
| 206 | int endofvolume = 0; /* Have we read all volume data */ |
| 207 | int indump = 0; |
| 208 | int fragmentvolume; |
| 209 | struct volumeHeader hostVolumeHeader; |
| 210 | |
| 211 | struct rx_call *fromcall = (struct rx_call *)0; |
| 212 | struct rx_connection *fromconn; |
| 213 | afs_int32 updatedate, fromtid = 0; |
| 214 | volEntries volumeInfo; |
| 215 | afs_int32 bytesWritten; |
| 216 | afs_uint32 statuscount = statusSize, tsize = 0; |
| 217 | |
| 218 | dparamsPtr->curVolumeStatus = DUMP_NOTHING6; |
| 219 | |
| 220 | fromconn = Bind(htonl(curDump->hostAddr)(__builtin_constant_p(curDump->hostAddr) ? ((((__uint32_t) (curDump->hostAddr)) >> 24) | ((((__uint32_t)(curDump ->hostAddr)) & (0xff << 16)) >> 8) | ((((__uint32_t )(curDump->hostAddr)) & (0xff << 8)) << 8) | (((__uint32_t)(curDump->hostAddr)) << 24)) : __bswap32_var (curDump->hostAddr))); /* get connection to the server */ |
| 221 | |
| 222 | /* Determine when the volume was last cloned and updated */ |
| 223 | volumeInfo.volEntries_val = (volintInfo *) 0; |
| 224 | volumeInfo.volEntries_len = 0; |
| 225 | rc = AFSVolListOneVolume(fromconn, curDump->partition, curDump->vid, |
| 226 | &volumeInfo); |
| 227 | if (rc) |
| 228 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 229 | updatedate = volumeInfo.volEntries_val[0].updateDate; |
| 230 | curDump->cloneDate = |
| 231 | ((curDump->vtype == |
| 232 | RWVOL0) ? time(0) : volumeInfo.volEntries_val[0].creationDate); |
| 233 | |
| 234 | if (curDump->date >= curDump->cloneDate) |
| 235 | ERROR_EXIT(0)do { code = 0; goto error_exit; } while (0); /* not recloned since last dump */ |
| 236 | if (curDump->date > updatedate) { |
| 237 | dparamsPtr->curVolumeStatus = DUMP_NODUMP7; /* not modified since last dump */ |
| 238 | ERROR_EXIT(0)do { code = 0; goto error_exit; } while (0); |
| 239 | } |
| 240 | |
| 241 | /* Start the volserver transaction and dump */ |
| 242 | rc = AFSVolTransCreate(fromconn, curDump->vid, curDump->partition, ITBusy2, |
| 243 | &fromtid); |
| 244 | if (rc) |
| 245 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 246 | fromcall = rx_NewCall(fromconn); |
| 247 | |
| 248 | rc = StartAFSVolDump(fromcall, fromtid, curDump->date); |
| 249 | if (rc) |
| 250 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 251 | |
| 252 | dparamsPtr->curVolumeStatus = DUMP_PARTIAL2; |
| 253 | dparamsPtr->curVolStartPos = tapeInfoPtr->position; |
| 254 | |
| 255 | /* buffer is place in bufferBlock to write volume data. |
| 256 | * butm_writeFileData() assumes the previous BUTM_HDRSIZE bytes |
| 257 | * is available to write the tape block header. |
| 258 | */ |
| 259 | buffer = bufferBlock + BUTM_HDRSIZE((5*sizeof(afs_int32)) + sizeof(int)); |
| 260 | |
| 261 | /* Dump one volume fragment at a time until we dump the full volume. |
| 262 | * A volume with more than 1 fragment means the volume will 'span' |
| 263 | * 2 or more tapes. |
| 264 | */ |
| 265 | for (fragmentNumber = 1; !endofvolume; fragmentNumber++) { /*frag */ |
| 266 | rc = butm_WriteFileBegin(tapeInfoPtr)(*((tapeInfoPtr)->ops.writeFileBegin))(tapeInfoPtr); |
| 267 | if (rc) { |
| 268 | ErrorLog(1, taskId, rc, tapeInfoPtr->error, |
| 269 | "Can't write FileBegin on tape\n"); |
| 270 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 271 | } |
| 272 | indump = 1; /* first write to tape */ |
| 273 | |
| 274 | /* Create and Write the volume header */ |
| 275 | makeVolumeHeader(&hostVolumeHeader, dparamsPtr, fragmentNumber); |
| 276 | hostVolumeHeader.contd = ((fragmentNumber == 1) ? 0 : TC_VOLCONTD0xffffffff); |
| 277 | volumeHeader_hton(&hostVolumeHeader, (struct volumeHeader *)buffer); |
| 278 | |
| 279 | rc = butm_WriteFileData(tapeInfoPtr, buffer, 1,(*((tapeInfoPtr)->ops.writeFileData))(tapeInfoPtr,buffer,1 ,sizeof(hostVolumeHeader)) |
| 280 | sizeof(hostVolumeHeader))(*((tapeInfoPtr)->ops.writeFileData))(tapeInfoPtr,buffer,1 ,sizeof(hostVolumeHeader)); |
| 281 | if (rc) { |
| 282 | ErrorLog(1, taskId, rc, tapeInfoPtr->error, |
| 283 | "Can't write VolumeHeader on tape\n"); |
| 284 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 285 | } |
| 286 | |
| 287 | bytesWritten = BUTM_BLOCKSIZE16384; /* Wrote one tapeblock */ |
| 288 | tsize += bytesWritten; |
| 289 | |
| 290 | /* Start reading volume data, rx_Read(), and dumping to the tape |
| 291 | * until we've dumped the entire volume (endofvolume == 1). We can |
| 292 | * exit this loop early if we find we are close to the end of the |
| 293 | * tape; in which case we dump the next fragment on the next tape. |
| 294 | */ |
| 295 | volBytesRead = 0; |
| 296 | chunkSize = 0; |
| 297 | fragmentvolume = 0; |
| 298 | while (!endofvolume && !fragmentvolume) { /*w */ |
| 299 | bytesread = 0; |
Value stored to 'bytesread' is never read | |
| 300 | |
| 301 | /* Check for abort in the middle of writing data */ |
| 302 | if (volBytesRead >= chunkSize) { |
| 303 | chunkSize += BIGCHUNK102400; |
| 304 | if (checkAbortByTaskId(taskId)) |
| 305 | ABORT_EXIT(TC_ABORTEDBYREQUEST)do { code = (156566278L); goto abort_exit; } while (0); |
| 306 | |
| 307 | /* set bytes dumped for backup */ |
| 308 | lock_Status(); |
| 309 | nodePtr->statusNodePtr->nKBytes = tapeInfoPtr->kBytes; |
| 310 | unlock_Status(); |
| 311 | } |
| 312 | |
| 313 | /* Determine how much data to read in upcoming RX_Read() call */ |
| 314 | toread = dataSize; |
| 315 | /* Check if we are close to the EOT. There should at least be some |
| 316 | * data on the tape before it is switched. HACK: we have to split a |
| 317 | * volume across tapes because the volume trailer says the dump |
| 318 | * continues on the next tape (and not the filemark). This could |
| 319 | * result in a volume starting on one tape (no volume data dumped) and |
| 320 | * continued on the next tape. It'll work, just requires restore to |
| 321 | * switch tapes. This allows many small volumes (<16K) to be dumped. |
| 322 | */ |
| 323 | kRemaining = butm_remainingKSpace(tapeInfoPtr)((tapeInfoPtr)->tapeSize - ((tapeInfoPtr)->kBytes*(tapeInfoPtr )->coefBytes )); |
| 324 | if ((kRemaining < tc_KEndMargin) |
| 325 | && (volBytesRead |
| 326 | || (tapeInfoPtr->position > (isafile ? 3 : 2)))) { |
| 327 | fragmentvolume = 1; |
| 328 | } |
| 329 | |
| 330 | |
| 331 | /* Guess at how much data to read. So we don't write off end of tape */ |
| 332 | if (kRemaining < (tapeblocks * 16)) { |
| 333 | if (kRemaining < 0) { |
| 334 | toread = BUTM_BLKSIZE(16384 - ((5*sizeof(afs_int32)) + sizeof(int))); |
| 335 | } else { |
| 336 | toread = ((kRemaining / 16) + 1) * BUTM_BLKSIZE(16384 - ((5*sizeof(afs_int32)) + sizeof(int))); |
| 337 | if (toread > dataSize) |
| 338 | toread = dataSize; |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | #ifdef xbsa |
| 343 | /* Set aside space for the trailing volume header when using large buffers. */ |
| 344 | if (XBSAMAXBUFFER < toread + sizeof(hostVolumeHeader)) { |
| 345 | toread = XBSAMAXBUFFER - sizeof(hostVolumeHeader); |
| 346 | } |
| 347 | #endif |
| 348 | |
| 349 | /* Read some volume data. */ |
| 350 | if (fragmentvolume) { |
| 351 | bytesread = 0; |
| 352 | } else { |
| 353 | bytesread = rx_Read(fromcall, buffer, toread)rx_ReadProc(fromcall, buffer, toread); |
| 354 | volBytesRead += bytesread; |
| 355 | if (bytesread != toread) { |
| 356 | /* Make sure were at end of volume and not a communication error */ |
| 357 | rc = rx_Error(fromcall)((fromcall)->error); |
| 358 | if (rc) |
| 359 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 360 | endofvolume = 1; |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | if (fragmentvolume || endofvolume) { |
| 365 | /* Create a volume trailer appending it to this data block */ |
| 366 | makeVolumeHeader(&hostVolumeHeader, dparamsPtr, |
| 367 | fragmentNumber); |
| 368 | hostVolumeHeader.contd = (endofvolume ? 0 : TC_VOLCONTD0xffffffff); |
| 369 | hostVolumeHeader.magic = TC_VOLENDMAGIC0x9167345a; |
| 370 | hostVolumeHeader.endTime = (endofvolume ? time(0) : 0); |
| 371 | volumeHeader_hton(&hostVolumeHeader, (struct volumeHeader *)&buffer[bytesread]); |
| 372 | bytesread += sizeof(hostVolumeHeader); |
| 373 | } |
| 374 | |
| 375 | /* Write the datablock out */ |
| 376 | /* full data buffer - write it to tape */ |
| 377 | rc = butm_WriteFileData(tapeInfoPtr, buffer, tapeblocks,(*((tapeInfoPtr)->ops.writeFileData))(tapeInfoPtr,buffer,tapeblocks ,bytesread) |
| 378 | bytesread)(*((tapeInfoPtr)->ops.writeFileData))(tapeInfoPtr,buffer,tapeblocks ,bytesread); |
| 379 | if (rc) { |
| 380 | ErrorLog(1, taskId, rc, tapeInfoPtr->error, |
| 381 | "Can't write VolumeData on tape\n"); |
| 382 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 383 | } |
| 384 | bytesWritten = tapeblocks * BUTM_BLOCKSIZE16384; |
| 385 | tsize += bytesWritten; |
| 386 | |
| 387 | /* Display a status line every statusSize or at end of volume */ |
| 388 | if (statusSize |
| 389 | && ((tsize >= statuscount) || endofvolume |
| 390 | || fragmentvolume)) { |
| 391 | time_t t = time(0); |
| 392 | struct tm tm; |
| 393 | localtime_r(&t, &tm); |
| 394 | printf("%02d:%02d:%02d: Task %u: %u KB: %s: %u B\n", |
| 395 | tm.tm_hour, tm.tm_min, tm.tm_sec, taskId, |
| 396 | tapeInfoPtr->kBytes, hostVolumeHeader.volumeName, |
| 397 | tsize); |
| 398 | statuscount = tsize + statusSize; |
| 399 | } |
| 400 | } /*w */ |
| 401 | |
| 402 | /* End the dump before recording it in BUDB as successfully dumped */ |
| 403 | rc = butm_WriteFileEnd(tapeInfoPtr)(*((tapeInfoPtr)->ops.writeFileEnd))(tapeInfoPtr); |
| 404 | indump = 0; |
| 405 | if (rc) { |
| 406 | ErrorLog(1, taskId, rc, tapeInfoPtr->error, |
| 407 | "Can't write FileEnd on tape\n"); |
| 408 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 409 | } |
| 410 | |
| 411 | /* Record in BUDB the volume fragment as succcessfully dumped */ |
| 412 | volumeFlags = ((fragmentNumber == 1) ? BUDB_VOL_FIRSTFRAG(1<<3) : 0); |
| 413 | if (endofvolume) |
| 414 | volumeFlags |= BUDB_VOL_LASTFRAG(1<<4); |
| 415 | rc = addVolume(0, dparamsPtr->databaseDumpId, dparamsPtr->tapeName, |
| 416 | nodePtr->dumps[dparamsPtr->curVolume].name, |
| 417 | nodePtr->dumps[dparamsPtr->curVolume].vid, |
| 418 | nodePtr->dumps[dparamsPtr->curVolume].cloneDate, |
| 419 | dparamsPtr->curVolStartPos, volBytesRead, |
| 420 | (fragmentNumber - 1), volumeFlags); |
| 421 | if (rc) |
| 422 | ABORT_EXIT(rc)do { code = rc; goto abort_exit; } while (0); |
| 423 | |
| 424 | /* If haven't finished dumping the volume, end this |
| 425 | * tape and get the next tape. |
| 426 | */ |
| 427 | if (!endofvolume) { |
| 428 | /* Write an EOT marker. |
| 429 | * Log the error but ignore it since the dump is effectively done. |
| 430 | * Scantape will detect continued volume and not read the EOT. |
| 431 | */ |
| 432 | rc = butm_WriteEOT(tapeInfoPtr)(*((tapeInfoPtr)->ops.writeEOT))(tapeInfoPtr); |
| 433 | if (rc) |
| 434 | TapeLog(1, taskId, rc, tapeInfoPtr->error, |
| 435 | "Warning: Can't write End-Of-Dump on tape\n"); |
| 436 | |
| 437 | /* Unmount the tape */ |
| 438 | unmountTape(taskId, tapeInfoPtr); |
| 439 | |
| 440 | /* Tell the database the tape is complete (and ok) */ |
| 441 | rc = finishTape(&dparamsPtr->tape, |
| 442 | dparamsPtr->tapeInfoPtr->kBytes + |
| 443 | (dparamsPtr->tapeInfoPtr->nBytes ? 1 : 0)); |
| 444 | if (rc) |
| 445 | ABORT_EXIT(rc)do { code = rc; goto abort_exit; } while (0); |
| 446 | |
| 447 | /* get the next tape. Prompt, mount, and add it into the database */ |
| 448 | dparamsPtr->tapeSeq++; |
| 449 | rc = getDumpTape(dparamsPtr, 1, 0); /* interactive - no append */ |
| 450 | if (rc) |
| 451 | ABORT_EXIT(rc)do { code = rc; goto abort_exit; } while (0); |
| 452 | |
| 453 | dparamsPtr->curVolStartPos = tapeInfoPtr->position; |
| 454 | } |
| 455 | } /*frag */ |
| 456 | |
| 457 | dparamsPtr->curVolumeStatus = DUMP_SUCCESS3; |
| 458 | |
| 459 | error_exit: |
| 460 | /* |
| 461 | * If we hit the end, see if this is the first volume on the tape or not. |
| 462 | * Also, mark the tape as finished if the tape contains other dumps. |
| 463 | */ |
| 464 | if (!code) |
| 465 | code = rc; |
| 466 | if (HITEOT(code)((code == (156568837L)) || (code == (156568842L)) || (code == (156568848L)))) { |
| 467 | ErrorLog(2, taskId, code, tapeInfoPtr->error, |
| 468 | "Warning: Dump (%s) hit end-of-tape inferred\n", |
| 469 | nodePtr->dumpSetName); |
| 470 | |
| 471 | if (tapeInfoPtr->position == 2) { |
| 472 | dparamsPtr->curVolumeStatus = DUMP_NORETRYEOT5; |
| 473 | } else { |
| 474 | dparamsPtr->curVolumeStatus = DUMP_RETRY4; |
| 475 | rc = finishTape(&dparamsPtr->tape, |
| 476 | dparamsPtr->tapeInfoPtr->kBytes + |
| 477 | (dparamsPtr->tapeInfoPtr->nBytes ? 1 : 0)); |
| 478 | if (rc) |
| 479 | ABORT_EXIT(rc)do { code = rc; goto abort_exit; } while (0); |
| 480 | } |
| 481 | } |
| 482 | |
| 483 | /* |
| 484 | * This is used when an error occurs part way into a volume dump. Clean |
| 485 | * the tape state by writing an FileEnd mark. Forgo this action if we hit |
| 486 | * the end of tape. |
| 487 | */ |
| 488 | else if (indump) { |
| 489 | rc = butm_WriteFileEnd(tapeInfoPtr)(*((tapeInfoPtr)->ops.writeFileEnd))(tapeInfoPtr); |
| 490 | indump = 0; |
| 491 | if (rc) { |
| 492 | ErrorLog(1, taskId, rc, tapeInfoPtr->error, |
| 493 | "Can't write FileEnd on tape\n"); |
| 494 | } |
| 495 | } |
| 496 | |
| 497 | if (fromcall) { |
| 498 | rc = rx_EndCall(fromcall, 0); |
| 499 | if (!code) |
| 500 | code = rc; |
| 501 | } |
| 502 | |
| 503 | if (fromtid) { |
| 504 | afs_int32 rcode; |
| 505 | rc = AFSVolEndTrans(fromconn, fromtid, &rcode); |
| 506 | if (!code) |
| 507 | code = (rc ? rc : rcode); |
| 508 | } |
| 509 | |
| 510 | return (code); |
| 511 | |
| 512 | abort_exit: |
| 513 | dparamsPtr->curVolumeStatus = DUMP_FAILED1; |
| 514 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 515 | } |
| 516 | |
| 517 | afs_int32 |
| 518 | xbsaDumpVolume(struct tc_dumpDesc * curDump, struct dumpRock * dparamsPtr) |
| 519 | { |
| 520 | #ifdef xbsa |
| 521 | struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr; |
| 522 | struct dumpNode *nodePtr = dparamsPtr->node; |
| 523 | char *buffer = bufferBlock; |
| 524 | afs_int32 taskId = nodePtr->taskID; |
| 525 | afs_int32 rc, code = 0; |
| 526 | afs_int32 toread; |
| 527 | afs_uint32 volBytesRead; |
| 528 | afs_uint32 chunkSize; |
| 529 | afs_int32 bytesread; /* rx reads */ |
| 530 | int endofvolume = 0; /* Have we read all volume data */ |
| 531 | int begindump = 0, indump = 0; /* if dump transaction started; if dumping data */ |
| 532 | struct volumeHeader hostVolumeHeader; |
| 533 | |
| 534 | struct rx_call *fromcall = (struct rx_call *)0; |
| 535 | struct rx_connection *fromconn; |
| 536 | afs_int32 updatedate, fromtid = 0; |
| 537 | volEntries volumeInfo; |
| 538 | afs_int32 bytesWritten; |
| 539 | afs_uint32 statuscount = statusSize, tsize = 0, esize; |
| 540 | afs_hyper_t estSize; |
| 541 | |
| 542 | char dumpIdStr[XBSA_MAX_OSNAME]; |
| 543 | char volumeNameStr[XBSA_MAX_PATHNAME]; |
| 544 | static char *dumpDescription = "AFS volume dump"; |
| 545 | static char *objectDescription = "XBSA - butc"; |
| 546 | |
| 547 | dparamsPtr->curVolumeStatus = DUMP_NOTHING6; |
| 548 | |
| 549 | fromconn = Bind(htonl(curDump->hostAddr)(__builtin_constant_p(curDump->hostAddr) ? ((((__uint32_t) (curDump->hostAddr)) >> 24) | ((((__uint32_t)(curDump ->hostAddr)) & (0xff << 16)) >> 8) | ((((__uint32_t )(curDump->hostAddr)) & (0xff << 8)) << 8) | (((__uint32_t)(curDump->hostAddr)) << 24)) : __bswap32_var (curDump->hostAddr))); /* get connection to the server */ |
| 550 | |
| 551 | /* Determine when the volume was last cloned and updated */ |
| 552 | volumeInfo.volEntries_val = (volintInfo *) 0; |
| 553 | volumeInfo.volEntries_len = 0; |
| 554 | rc = AFSVolListOneVolume(fromconn, curDump->partition, curDump->vid, |
| 555 | &volumeInfo); |
| 556 | if (rc) |
| 557 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 558 | updatedate = volumeInfo.volEntries_val[0].updateDate; |
| 559 | curDump->cloneDate = |
| 560 | ((curDump->vtype == |
| 561 | RWVOL0) ? time(0) : volumeInfo.volEntries_val[0].creationDate); |
| 562 | |
| 563 | /* Get the volume size (in KB) and increase by 25%. Then set as a hyper */ |
| 564 | esize = volumeInfo.volEntries_val[0].size; |
| 565 | esize += (esize / 4) + 1; |
| 566 | |
| 567 | if (curDump->date >= curDump->cloneDate) |
| 568 | ERROR_EXIT(0)do { code = 0; goto error_exit; } while (0); /* not recloned since last dump */ |
| 569 | if (curDump->date > updatedate) { |
| 570 | dparamsPtr->curVolumeStatus = DUMP_NODUMP7; /* not modified since last dump */ |
| 571 | ERROR_EXIT(0)do { code = 0; goto error_exit; } while (0); |
| 572 | } |
| 573 | |
| 574 | /* Start a new XBSA Transaction */ |
| 575 | rc = xbsa_BeginTrans(&butxInfo); |
| 576 | if (rc != XBSA_SUCCESS) { |
| 577 | ErrorLog(1, taskId, rc, 0, "Unable to create a new transaction\n"); |
| 578 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 579 | } |
| 580 | begindump = 1; /* Will need to do an xbsa_EndTrans */ |
| 581 | |
| 582 | /* Start the volserver transaction and dump. Once started, the |
| 583 | * volume status is "partial dump". Also, the transaction with |
| 584 | * the volserver is idle until the first read. An idle transaction |
| 585 | * will time out in 600 seconds. After the first rx_Read, |
| 586 | * the transaction is not idle. See GCTrans(). |
| 587 | */ |
| 588 | rc = AFSVolTransCreate(fromconn, curDump->vid, curDump->partition, ITBusy2, |
| 589 | &fromtid); |
| 590 | if (rc) |
| 591 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 592 | fromcall = rx_NewCall(fromconn); |
| 593 | |
| 594 | rc = StartAFSVolDump(fromcall, fromtid, curDump->date); |
| 595 | if (rc) |
| 596 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 597 | |
| 598 | dparamsPtr->curVolumeStatus = DUMP_PARTIAL2; |
| 599 | dparamsPtr->curVolStartPos = tapeInfoPtr->position; |
| 600 | |
| 601 | /* Tell XBSA what the name and size of volume to write */ |
| 602 | strcpy(dumpIdStr, butcdumpIdStr); /* "backup_afs_volume_dumps" */ |
| 603 | sprintf(volumeNameStr, "/%d", dparamsPtr->databaseDumpId); |
| 604 | strcat(volumeNameStr, "/"); |
| 605 | strcat(volumeNameStr, curDump->name); /* <dumpid>/<volname> */ |
| 606 | hset32(estSize, esize)((estSize).high = 0, (estSize).low = (esize)); |
| 607 | hshlft(estSize, 10){ int s = sizeof((estSize).low) * 8; if ((10) <= 0) { } else if ((10) >= 2*s) { (estSize).high = (estSize).low = 0; } else if ((10) < s) { (estSize).high = ((estSize).high<<( 10)) | (((estSize).low>>(s-(10))) & (1<<(10)) -1); (estSize).low = (estSize).low << (10); } else if ( (10) >= s) { (estSize).high = (estSize).low << ((10) -s); (estSize).low=0; } }; /* Multiply by 1024 so its in KB */ |
| 608 | |
| 609 | rc = xbsa_WriteObjectBegin(&butxInfo, dumpIdStr, volumeNameStr, |
| 610 | xbsalGName, estSize, dumpDescription, |
| 611 | objectDescription); |
| 612 | if (rc != XBSA_SUCCESS) { |
| 613 | ErrorLog(1, taskId, rc, 0, |
| 614 | "Unable to begin writing of the fileset data to the server\n"); |
| 615 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 616 | } |
| 617 | indump = 1; /* Will need to do an xbsa_WriteObjectEnd */ |
| 618 | |
| 619 | /* Create and Write the volume header */ |
| 620 | makeVolumeHeader(&hostVolumeHeader, dparamsPtr, 1); |
| 621 | hostVolumeHeader.contd = 0; |
| 622 | volumeHeader_hton(&hostVolumeHeader, (struct volumeHeader *)buffer); |
| 623 | |
| 624 | rc = xbsa_WriteObjectData(&butxInfo, (struct volumeHeader *)buffer, |
| 625 | sizeof(struct volumeHeader), &bytesWritten); |
| 626 | if (rc != XBSA_SUCCESS) { |
| 627 | ErrorLog(1, taskId, rc, 0, |
| 628 | "Unable to write VolumeHeader data to the server\n"); |
| 629 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 630 | } |
| 631 | /* There is a bug in the ADSM library where the bytesWritten is |
| 632 | * not filled in, so we set it as correct anyway. |
| 633 | */ |
| 634 | bytesWritten = sizeof(struct volumeHeader); |
| 635 | if (bytesWritten != sizeof(struct volumeHeader)) { |
| 636 | ErrorLog(1, taskId, rc, 0, |
| 637 | "The size of VolumeHeader written (%d) does not equal its actual size (%d)\n", |
| 638 | bytesWritten, sizeof(struct volumeHeader)); |
| 639 | ERROR_EXIT(TC_INTERNALERROR)do { code = (156566288L); goto error_exit; } while (0); |
| 640 | } |
| 641 | |
| 642 | incSize(tapeInfoPtr, sizeof(struct volumeHeader)); /* Increment amount we've written */ |
| 643 | tsize += bytesWritten; |
| 644 | |
| 645 | /* Start reading volume data, rx_Read(), and dumping to the tape |
| 646 | * until we've dumped the entire volume (endofvolume == 1). |
| 647 | */ |
| 648 | volBytesRead = 0; |
| 649 | chunkSize = 0; |
| 650 | while (!endofvolume) { /*w */ |
| 651 | bytesread = 0; |
| 652 | |
| 653 | /* Check for abort in the middle of writing data */ |
| 654 | if (volBytesRead >= chunkSize) { |
| 655 | chunkSize += BIGCHUNK102400; |
| 656 | if (checkAbortByTaskId(taskId)) |
| 657 | ABORT_EXIT(TC_ABORTEDBYREQUEST)do { code = (156566278L); goto abort_exit; } while (0); |
| 658 | |
| 659 | /* set bytes dumped for backup */ |
| 660 | lock_Status(); |
| 661 | nodePtr->statusNodePtr->nKBytes = tapeInfoPtr->kBytes; |
| 662 | unlock_Status(); |
| 663 | } |
| 664 | |
| 665 | /* Determine how much data to read in upcoming RX_Read() call */ |
| 666 | toread = dataSize; |
| 667 | |
| 668 | /* Read some volume data. */ |
| 669 | bytesread = rx_Read(fromcall, buffer, toread)rx_ReadProc(fromcall, buffer, toread); |
| 670 | volBytesRead += bytesread; |
| 671 | if (bytesread != toread) { |
| 672 | afs_int32 rcode; |
| 673 | |
| 674 | /* Make sure were at end of volume and not a communication error */ |
| 675 | rc = rx_Error(fromcall)((fromcall)->error); |
| 676 | if (rc) |
| 677 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 678 | |
| 679 | endofvolume = 1; |
| 680 | |
| 681 | /* Create a volume trailer appending it to this data block (if not XBSA) */ |
| 682 | makeVolumeHeader(&hostVolumeHeader, dparamsPtr, 1); |
| 683 | hostVolumeHeader.contd = 0; |
| 684 | hostVolumeHeader.magic = TC_VOLENDMAGIC0x9167345a; |
| 685 | hostVolumeHeader.endTime = time(0); |
| 686 | volumeHeader_hton(&hostVolumeHeader, &buffer[bytesread]); |
| 687 | bytesread += sizeof(hostVolumeHeader); |
| 688 | |
| 689 | /* End the dump and transaction with the volserver. We end it now, before |
| 690 | * we make the XBSA call because if XBSA blocks, we could time out on the |
| 691 | * volserver (After last read, the transaction with the volserver is idle). |
| 692 | */ |
| 693 | rc = rx_EndCall(fromcall, 0); |
| 694 | fromcall = 0; |
| 695 | if (rc) |
| 696 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 697 | |
| 698 | rc = AFSVolEndTrans(fromconn, fromtid, &rcode); |
| 699 | fromtid = 0; |
| 700 | if (rc) |
| 701 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 702 | } |
| 703 | |
| 704 | /* Write the datablock out */ |
| 705 | rc = xbsa_WriteObjectData(&butxInfo, buffer, bytesread, |
| 706 | &bytesWritten); |
| 707 | if (rc != XBSA_SUCCESS) { |
| 708 | ErrorLog(1, taskId, rc, 0, |
| 709 | "Unable to write data to the server\n"); |
| 710 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 711 | } |
| 712 | /* There is a bug in the ADSM library where the bytesWritten is |
| 713 | * not filled in, so we set it as correct anyway. |
| 714 | */ |
| 715 | bytesWritten = bytesread; |
| 716 | if (bytesWritten != bytesread) { |
| 717 | ErrorLog(1, taskId, rc, 0, |
| 718 | "The size of data written (%d) does not equal size read (%d)\n", |
| 719 | bytesWritten, bytesread); |
| 720 | ERROR_EXIT(TC_INTERNALERROR)do { code = (156566288L); goto error_exit; } while (0); |
| 721 | } |
| 722 | |
| 723 | incSize(tapeInfoPtr, bytesread); /* Increment amount we've written */ |
| 724 | tsize += bytesWritten; |
| 725 | |
| 726 | /* Display a status line every statusSize or at end of volume */ |
| 727 | if (statusSize && ((tsize >= statuscount) || endofvolume)) { |
| 728 | time_t t = time(0); |
| 729 | struct tm tm; |
| 730 | localtime_r(&t, &tm); |
| 731 | printf("%02d:%02d:%02d: Task %u: %u KB: %s: %u B\n", tm.tm_hour, |
| 732 | tm.tm_min, tm.tm_sec, taskId, tapeInfoPtr->kBytes, |
| 733 | hostVolumeHeader.volumeName, tsize); |
| 734 | statuscount = tsize + statusSize; |
| 735 | } |
| 736 | } /*w */ |
| 737 | |
| 738 | /* End the XBSA transaction before recording it in BUDB as successfully dumped */ |
| 739 | rc = xbsa_WriteObjectEnd(&butxInfo); |
| 740 | indump = 0; |
| 741 | if (rc != XBSA_SUCCESS) { |
| 742 | ErrorLog(1, taskId, rc, 0, |
| 743 | "Unable to terminate writing of the volume data to the server"); |
| 744 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 745 | } |
| 746 | rc = xbsa_EndTrans(&butxInfo); |
| 747 | begindump = 0; |
| 748 | tapeInfoPtr->position++; |
| 749 | if (rc != XBSA_SUCCESS) { |
| 750 | ErrorLog(1, taskId, rc, 0, |
| 751 | "Unable to terminate the current transaction"); |
| 752 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 753 | } |
| 754 | |
| 755 | /* Record in BUDB the volume fragment as succcessfully dumped */ |
| 756 | rc = addVolume(0, dparamsPtr->databaseDumpId, dparamsPtr->tapeName, |
| 757 | nodePtr->dumps[dparamsPtr->curVolume].name, |
| 758 | nodePtr->dumps[dparamsPtr->curVolume].vid, |
| 759 | nodePtr->dumps[dparamsPtr->curVolume].cloneDate, |
| 760 | dparamsPtr->curVolStartPos, volBytesRead, 0 /*frag0 */ , |
| 761 | (BUDB_VOL_FIRSTFRAG(1<<3) | BUDB_VOL_LASTFRAG(1<<4))); |
| 762 | if (rc) |
| 763 | ABORT_EXIT(rc)do { code = rc; goto abort_exit; } while (0); |
| 764 | |
| 765 | dparamsPtr->curVolumeStatus = DUMP_SUCCESS3; |
| 766 | |
| 767 | error_exit: |
| 768 | /* Cleanup after an error occurs part way into a volume dump */ |
| 769 | if (fromcall) { |
| 770 | rc = rx_EndCall(fromcall, 0); |
| 771 | if (!code) |
| 772 | code = rc; |
| 773 | } |
| 774 | |
| 775 | if (fromtid) { |
| 776 | afs_int32 rcode; |
| 777 | rc = AFSVolEndTrans(fromconn, fromtid, &rcode); |
| 778 | if (!code) |
| 779 | code = (rc ? rc : rcode); |
| 780 | } |
| 781 | |
| 782 | /* If this dump failed, what happens to successive retries |
| 783 | * of the volume? How do they get recorded in the XBSA database |
| 784 | * (overwritten)? If not, we don't record this in the BUDB database |
| 785 | * so it will not be removed when we delete the dump. What to do? |
| 786 | * Also if the volume was never recorded in the DB (partial dump). |
| 787 | */ |
| 788 | if (indump) { |
| 789 | /* End the Write */ |
| 790 | rc = xbsa_WriteObjectEnd(&butxInfo); |
| 791 | indump = 0; |
| 792 | if (rc != XBSA_SUCCESS) { |
| 793 | ErrorLog(1, taskId, rc, 0, |
| 794 | "Unable to terminate writing of the volume data to the server"); |
| 795 | } |
| 796 | tapeInfoPtr->position++; |
| 797 | } |
| 798 | |
| 799 | if (begindump) { |
| 800 | /* End the XBSA Transaction */ |
| 801 | rc = xbsa_EndTrans(&butxInfo); |
| 802 | begindump = 0; |
| 803 | if (rc != XBSA_SUCCESS) { |
| 804 | ErrorLog(1, taskId, rc, 0, |
| 805 | "Unable to terminate the current transaction"); |
| 806 | } |
| 807 | } |
| 808 | |
| 809 | return (code); |
| 810 | |
| 811 | abort_exit: |
| 812 | dparamsPtr->curVolumeStatus = DUMP_FAILED1; |
| 813 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 814 | #else |
| 815 | return 0; |
| 816 | #endif |
| 817 | } |
| 818 | |
| 819 | #define HOSTADDR(sockaddr)(sockaddr)->sin_addr.s_addr (sockaddr)->sin_addr.s_addr |
| 820 | |
| 821 | /* dumpPass |
| 822 | * Go through the list of volumes to dump, dumping each one. The action |
| 823 | * taken when a volume dump fails, depends on the passNumber. At minimum, |
| 824 | * the failed volume is remembered. |
| 825 | * notes: |
| 826 | * flushSavedEntries - inconsistent treatment for errors. What should |
| 827 | * be done for user aborts? |
| 828 | */ |
| 829 | |
| 830 | afs_int32 |
| 831 | dumpPass(struct dumpRock * dparamsPtr, int passNumber) |
| 832 | { |
| 833 | struct dumpNode *nodePtr = dparamsPtr->node; |
| 834 | struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr; |
| 835 | afs_int32 taskId = nodePtr->taskID; |
| 836 | struct tc_dumpDesc *curDump; |
| 837 | int action, e; |
| 838 | afs_int32 code = 0, tcode, dvcode; |
| 839 | char ch; |
| 840 | struct vldbentry vldbEntry; |
| 841 | struct sockaddr_in server; |
| 842 | afs_int32 tapepos; |
| 843 | |
| 844 | TapeLog(2, taskId, 0, 0, "Starting pass %d\n", passNumber); |
| 845 | |
| 846 | /* while there are more volumes to dump */ |
| 847 | for (dparamsPtr->curVolume = 0; dparamsPtr->curVolume < nodePtr->arraySize; dparamsPtr->curVolume++) { /*w */ |
| 848 | curDump = &nodePtr->dumps[dparamsPtr->curVolume]; |
| 849 | if (curDump->hostAddr == 0) |
| 850 | continue; |
| 851 | |
| 852 | /* set name of current volume being dumped */ |
| 853 | lock_Status(); |
| 854 | strcpy(nodePtr->statusNodePtr->volumeName, curDump->name); |
| 855 | unlock_Status(); |
| 856 | |
| 857 | /* Determine location of the volume. |
| 858 | * In case the volume moved has moved. |
| 859 | */ |
| 860 | if (passNumber > 1) { /*pass */ |
| 861 | tcode = |
| 862 | bc_GetEntryByID(cstruct, curDump->vid, curDump->vtype, |
| 863 | &vldbEntry); |
| 864 | if (tcode) { |
| 865 | ErrorLog(0, taskId, tcode, 0, |
| 866 | "Volume %s (%u) failed - Can't find volume in VLDB\n", |
| 867 | curDump->name, curDump->vid); |
| 868 | curDump->hostAddr = 0; |
| 869 | dparamsPtr->volumesFailed++; |
| 870 | continue; |
| 871 | } |
| 872 | |
| 873 | switch (curDump->vtype) { |
| 874 | case BACKVOL2: |
| 875 | if (!(vldbEntry.flags & BACK_EXISTS0x4000)) { |
| 876 | ErrorLog(0, taskId, 0, 0, |
| 877 | "Volume %s (%u) failed - Backup volume no longer exists\n", |
| 878 | curDump->name, curDump->vid); |
| 879 | curDump->hostAddr = 0; |
| 880 | dparamsPtr->volumesFailed++; |
| 881 | continue; |
| 882 | } |
| 883 | /* Fall into RWVOL case */ |
| 884 | |
| 885 | case RWVOL0: |
| 886 | for (e = 0; e < vldbEntry.nServers; e++) { /* Find the RW volume */ |
| 887 | if (vldbEntry.serverFlags[e] & ITSRWVOL0x04) |
| 888 | break; |
| 889 | } |
| 890 | break; |
| 891 | |
| 892 | case ROVOL1: |
| 893 | /* Try to use the server and partition we found the volume on |
| 894 | * Otherwise, use the first RO volume. |
| 895 | */ |
| 896 | for (e = 0; e < vldbEntry.nServers; e++) { /* Find the RO volume */ |
| 897 | if ((curDump->hostAddr == vldbEntry.serverNumber[e]) |
| 898 | && (curDump->partition == |
| 899 | vldbEntry.serverPartition[e])) |
| 900 | break; |
| 901 | } |
| 902 | |
| 903 | if (e >= vldbEntry.nServers) { /* Didn't find RO volume */ |
| 904 | for (e = 0; e < vldbEntry.nServers; e++) { /* Find the first RO volume */ |
| 905 | if (vldbEntry.serverFlags[e] & ITSROVOL0x02) |
| 906 | break; |
| 907 | } |
| 908 | } |
| 909 | break; |
| 910 | |
| 911 | default: |
| 912 | ErrorLog(0, taskId, 0, 0, |
| 913 | "Volume %s (%u) failed - Unknown volume type\n", |
| 914 | curDump->name, curDump->vid); |
| 915 | curDump->hostAddr = 0; |
| 916 | continue; |
| 917 | } |
| 918 | |
| 919 | if (e >= vldbEntry.nServers) { |
| 920 | ErrorLog(0, taskId, 0, 0, |
| 921 | "Volume %s (%u) failed - Can't find volume entry in VLDB\n", |
| 922 | curDump->name, curDump->vid); |
| 923 | curDump->hostAddr = 0; |
| 924 | dparamsPtr->volumesFailed++; |
| 925 | continue; |
| 926 | } |
| 927 | |
| 928 | /* Remember the server and partition the volume exists on */ |
| 929 | memset(&server, 0, sizeof(server)); |
| 930 | server.sin_addr.s_addr = vldbEntry.serverNumber[e]; |
| 931 | server.sin_port = 0; |
| 932 | server.sin_family = AF_INET2; |
| 933 | #ifdef STRUCT_SOCKADDR_HAS_SA_LEN1 |
| 934 | server.sin_len = sizeof(struct sockaddr_in); |
| 935 | #endif |
| 936 | curDump->hostAddr = HOSTADDR(&server)(&server)->sin_addr.s_addr; |
| 937 | curDump->partition = vldbEntry.serverPartition[e]; |
| 938 | |
| 939 | /* Determine date from which to do an incremental dump |
| 940 | */ |
| 941 | if (nodePtr->parent) { |
| 942 | tcode = |
| 943 | bcdb_FindClone(nodePtr->parent, curDump->name, |
| 944 | &curDump->date); |
| 945 | if (tcode) |
| 946 | curDump->date = 0; |
| 947 | } else { |
| 948 | curDump->date = 0; /* do a full dump */ |
| 949 | } |
| 950 | } |
| 951 | /*pass */ |
| 952 | if (checkAbortByTaskId(taskId)) |
| 953 | ERROR_EXIT(TC_ABORTEDBYREQUEST)do { code = (156566278L); goto error_exit; } while (0); |
| 954 | |
| 955 | /* Establish connection to volume - UV_ routine expects |
| 956 | * host address in network order |
| 957 | */ |
| 958 | if (CONF_XBSA0) { |
| 959 | dvcode = xbsaDumpVolume(curDump, dparamsPtr); |
| 960 | } else { |
| 961 | dvcode = dumpVolume(curDump, dparamsPtr); |
| 962 | } |
| 963 | action = dparamsPtr->curVolumeStatus; |
| 964 | |
| 965 | /* Flush volume and tape entries to the database */ |
| 966 | tcode = flushSavedEntries(action); |
| 967 | if (tcode) |
| 968 | ERROR_EXIT(tcode)do { code = tcode; goto error_exit; } while (0); |
| 969 | |
| 970 | switch (action) { |
| 971 | case DUMP_SUCCESS3: |
| 972 | TapeLog(1, taskId, 0, 0, "Volume %s (%u) successfully dumped\n", |
| 973 | curDump->name, curDump->vid); |
| 974 | if (dvcode) |
| 975 | ErrorLog(1, taskId, dvcode, 0, |
| 976 | "Warning: Termination processing error on volume %s (%u)\n", |
| 977 | curDump->name, curDump->vid); |
| 978 | |
| 979 | curDump->hostAddr = 0; |
| 980 | dparamsPtr->volumesDumped++; |
| 981 | break; |
| 982 | |
| 983 | case DUMP_PARTIAL2: |
| 984 | case DUMP_NOTHING6: |
| 985 | if (action == DUMP_PARTIAL2) { |
| 986 | ErrorLog(1, taskId, dvcode, 0, |
| 987 | "Volume %s (%u) failed - partially dumped\n", |
| 988 | curDump->name, curDump->vid); |
| 989 | } else if (dvcode) { |
| 990 | ErrorLog(0, taskId, dvcode, 0, "Volume %s (%u) failed\n", |
| 991 | curDump->name, curDump->vid); |
| 992 | } else { |
| 993 | ErrorLog(0, taskId, dvcode, 0, |
| 994 | "Volume %s (%u) not dumped - has not been re-cloned since last dump\n", |
| 995 | curDump->name, curDump->vid); |
| 996 | } |
| 997 | |
| 998 | if (passNumber == maxpass) { |
| 999 | if (!queryoperator) |
| 1000 | ch = 'o'; |
| 1001 | else |
| 1002 | ch = retryPrompt(curDump->name, curDump->vid, taskId); |
| 1003 | |
| 1004 | switch (ch) { |
| 1005 | case 'r': /* retry */ |
| 1006 | dparamsPtr->curVolume--; /* redump this volume */ |
| 1007 | continue; |
| 1008 | case 'o': /* omit */ |
| 1009 | ErrorLog(1, taskId, 0, 0, "Volume %s (%u) omitted\n", |
| 1010 | curDump->name, curDump->vid); |
| 1011 | dparamsPtr->volumesFailed++; |
| 1012 | break; |
| 1013 | case 'a': /* abort */ |
| 1014 | TapeLog(1, taskId, 0, 0, "Dump aborted\n"); |
| 1015 | ERROR_EXIT(TC_ABORTEDBYREQUEST)do { code = (156566278L); goto error_exit; } while (0); |
| 1016 | break; |
| 1017 | default: |
| 1018 | ERROR_EXIT(TC_INTERNALERROR)do { code = (156566288L); goto error_exit; } while (0); |
| 1019 | break; |
| 1020 | } |
| 1021 | } |
| 1022 | break; |
| 1023 | |
| 1024 | case DUMP_RETRY4: |
| 1025 | TapeLog(1, taskId, dvcode, 0, |
| 1026 | "Volume %s (%u) hit end-of-tape inferred - will retry on next tape\n", |
| 1027 | curDump->name, curDump->vid); |
| 1028 | |
| 1029 | /* Get the next tape */ |
| 1030 | unmountTape(taskId, tapeInfoPtr); |
| 1031 | |
| 1032 | dparamsPtr->tapeSeq++; |
| 1033 | tcode = getDumpTape(dparamsPtr, 1, 0); /* interactive - no appends */ |
| 1034 | if (tcode) |
| 1035 | ERROR_EXIT(tcode)do { code = tcode; goto error_exit; } while (0); |
| 1036 | |
| 1037 | dparamsPtr->curVolume--; /* redump this volume */ |
| 1038 | continue; |
| 1039 | |
| 1040 | case DUMP_NORETRYEOT5: |
| 1041 | ErrorLog(1, taskId, 0, 0, |
| 1042 | "Volume %s (%u) failed - volume larger than tape\n", |
| 1043 | curDump->name, curDump->vid); |
| 1044 | |
| 1045 | /* rewrite the label on the tape - rewind - no need to switch tapes */ |
| 1046 | tcode = butm_Create(tapeInfoPtr, &dparamsPtr->tapeLabel, 1)(*((tapeInfoPtr)->ops.create))(tapeInfoPtr,&dparamsPtr ->tapeLabel,1); |
| 1047 | if (tcode) { |
| 1048 | ErrorLog(0, taskId, tcode, tapeInfoPtr->error, |
| 1049 | "Can't relabel tape\n"); |
| 1050 | |
| 1051 | unmountTape(taskId, tapeInfoPtr); |
| 1052 | tcode = getDumpTape(dparamsPtr, 1, 0); /* interactive - no appends */ |
| 1053 | if (tcode) |
| 1054 | ERROR_EXIT(tcode)do { code = tcode; goto error_exit; } while (0); |
| 1055 | } else { /* Record the tape in database */ |
| 1056 | tapepos = tapeInfoPtr->position; |
| 1057 | tcode = |
| 1058 | useTape(&dparamsPtr->tape, dparamsPtr->databaseDumpId, |
| 1059 | dparamsPtr->tapeName, |
| 1060 | (dparamsPtr->tapeSeq + dparamsPtr->dump.tapes.b), |
| 1061 | dparamsPtr->tapeLabel.useCount, |
| 1062 | dparamsPtr->tapeLabel.creationTime, |
| 1063 | dparamsPtr->tapeLabel.expirationDate, tapepos); |
| 1064 | } |
| 1065 | |
| 1066 | curDump->hostAddr = 0; |
| 1067 | dparamsPtr->volumesFailed++; |
| 1068 | break; |
| 1069 | |
| 1070 | case DUMP_NODUMP7: |
| 1071 | TapeLog(1, taskId, dvcode, 0, |
| 1072 | "Volume %s (%u) not dumped - has not been modified since last dump\n", |
| 1073 | curDump->name, curDump->vid); |
| 1074 | |
| 1075 | curDump->hostAddr = 0; |
| 1076 | dparamsPtr->volumesNotDumped++; |
| 1077 | break; |
| 1078 | |
| 1079 | default: |
| 1080 | ErrorLog(1, taskId, dvcode, 0, "Volume %s (%u) failed\n", |
| 1081 | curDump->name, curDump->vid); |
| 1082 | ERROR_EXIT(dvcode)do { code = dvcode; goto error_exit; } while (0); |
| 1083 | break; |
| 1084 | } |
| 1085 | } /*w */ |
| 1086 | |
| 1087 | error_exit: |
| 1088 | /* check if we terminated while processing a volume */ |
| 1089 | if (dparamsPtr->curVolume < nodePtr->arraySize) { |
| 1090 | TapeLog(2, taskId, 0, 0, |
| 1091 | "Terminated while processing Volume %s (%u)\n", curDump->name, |
| 1092 | curDump->vid); |
| 1093 | } |
| 1094 | |
| 1095 | /* print a summary of this pass */ |
| 1096 | TapeLog(2, taskId, 0, 0, "End of pass %d: Volumes remaining = %d\n", |
| 1097 | passNumber, |
| 1098 | nodePtr->arraySize - (dparamsPtr->volumesDumped + |
| 1099 | dparamsPtr->volumesFailed + |
| 1100 | dparamsPtr->volumesNotDumped)); |
| 1101 | return (code); |
| 1102 | } |
| 1103 | |
| 1104 | void * |
| 1105 | Dumper(void *param) |
| 1106 | { |
| 1107 | struct dumpNode *nodePtr = (struct dumpNode *)param; |
| 1108 | struct dumpRock dparams; |
| 1109 | struct butm_tapeInfo tapeInfo; |
| 1110 | int pass; |
| 1111 | int action; |
| 1112 | afs_int32 taskId; |
| 1113 | afs_int32 code = 0; |
| 1114 | |
| 1115 | /* for volume setup */ |
| 1116 | int i; |
| 1117 | int failedvolumes = 0; |
| 1118 | int dumpedvolumes = 0; |
| 1119 | int nodumpvolumes = 0; |
| 1120 | char strlevel[5]; |
| 1121 | char msg[20]; |
| 1122 | char finishedMsg1[50]; |
| 1123 | char finishedMsg2[50]; |
| 1124 | time_t startTime = 0; |
| 1125 | time_t endTime = 0; |
| 1126 | afs_int32 allocbufferSize; |
| 1127 | |
| 1128 | extern struct deviceSyncNode *deviceLatch; |
| 1129 | extern struct tapeConfig globalTapeConfig; |
| 1130 | |
| 1131 | afs_pthread_setname_self("dumper")(void)0; |
| 1132 | taskId = nodePtr->taskID; /* Get task Id */ |
| 1133 | setStatus(taskId, DRIVE_WAIT0x100); |
| 1134 | EnterDeviceQueue(deviceLatch); |
| 1135 | clearStatus(taskId, DRIVE_WAIT0x100); |
| 1136 | |
| 1137 | printf("\n\n"); |
| 1138 | TapeLog(2, taskId, 0, 0, "Dump %s\n", nodePtr->dumpSetName); |
| 1139 | |
| 1140 | /* setup the dump parameters */ |
| 1141 | memset(&dparams, 0, sizeof(dparams)); |
| 1142 | dparams.node = nodePtr; |
| 1143 | dparams.tapeInfoPtr = &tapeInfo; |
| 1144 | dlqInit(&savedEntries); |
| 1145 | |
| 1146 | if (!CONF_XBSA0) { |
| 1147 | /* Instantiate the tape module */ |
| 1148 | tapeInfo.structVersion = BUTM_MAJORVERSION2; |
| 1149 | code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig); |
| 1150 | if (code) { |
| 1151 | ErrorLog(0, taskId, code, tapeInfo.error, |
| 1152 | "Can't initialize the tape module\n"); |
| 1153 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 1154 | } |
| 1155 | } |
| 1156 | |
| 1157 | /* check if abort requested while waiting on device latch */ |
| 1158 | if (checkAbortByTaskId(taskId)) |
| 1159 | ERROR_EXIT(TC_ABORTEDBYREQUEST)do { code = (156566278L); goto error_exit; } while (0); |
| 1160 | |
| 1161 | /* Are there volumes to dump */ |
| 1162 | if (nodePtr->arraySize == 0) { |
| 1163 | TLog(taskId, "Dump (%s), no volumes to dump\n", nodePtr->dumpSetName); |
| 1164 | ERROR_EXIT(0)do { code = 0; goto error_exit; } while (0); |
| 1165 | } |
| 1166 | |
| 1167 | /* Allocate a buffer for the dumps. Leave room for header and vol-trailer. |
| 1168 | * dataSize is amount of data to read in each rx_Read() call. |
| 1169 | */ |
| 1170 | if (CONF_XBSA0) { |
| 1171 | /* XBSA dumps have not header */ |
| 1172 | dataSize = BufferSize; |
| 1173 | allocbufferSize = dataSize + sizeof(struct volumeHeader); |
| 1174 | } else { |
| 1175 | tapeblocks = BufferSize / BUTM_BLOCKSIZE16384; /* # of 16K tapeblocks */ |
| 1176 | dataSize = (tapeblocks * BUTM_BLKSIZE(16384 - ((5*sizeof(afs_int32)) + sizeof(int)))); |
| 1177 | allocbufferSize = |
| 1178 | BUTM_HDRSIZE((5*sizeof(afs_int32)) + sizeof(int)) + dataSize + sizeof(struct volumeHeader); |
| 1179 | } |
| 1180 | bufferBlock = NULL((void *)0); |
| 1181 | bufferBlock = malloc(allocbufferSize); |
| 1182 | if (!bufferBlock) { |
| 1183 | ErrorLog(0, taskId, TC_NOMEMORY(156566290L), 0, |
| 1184 | "Can't allocate BUFFERSIZE for dumps\n"); |
| 1185 | ERROR_EXIT(TC_NOMEMORY)do { code = (156566290L); goto error_exit; } while (0); |
| 1186 | } |
| 1187 | |
| 1188 | /* Determine the dumpid of the most recent dump of this volumeset and dumplevel |
| 1189 | * Used when requesting a tape. Done now because once we create the dump, the |
| 1190 | * routine will then find the newly created dump. |
| 1191 | */ |
| 1192 | sprintf(strlevel, "%d", nodePtr->level); |
| 1193 | code = |
| 1194 | bcdb_FindLatestDump(nodePtr->volumeSetName, strlevel, |
| 1195 | &dparams.lastDump); |
| 1196 | if (code) { |
| 1197 | if (code != BUDB_NODUMPNAME(156303874L)) { |
| 1198 | ErrorLog(0, taskId, code, 0, "Can't read backup database\n"); |
| 1199 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 1200 | } |
| 1201 | memset(&dparams.lastDump, 0, sizeof(dparams.lastDump)); |
| 1202 | } |
| 1203 | |
| 1204 | code = createDump(&dparams); /* enter dump into database */ |
| 1205 | if (code) { |
| 1206 | ErrorLog(0, taskId, code, 0, "Can't create dump in database\n"); |
| 1207 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 1208 | } |
| 1209 | |
| 1210 | TLog(taskId, "Dump %s (DumpID %u)\n", nodePtr->dumpSetName, |
| 1211 | dparams.databaseDumpId); |
| 1212 | |
| 1213 | if (!CONF_XBSA0) { |
| 1214 | /* mount the tape and write its label */ |
| 1215 | code = getDumpTape(&dparams, autoQuery, nodePtr->doAppend); |
| 1216 | } else { |
| 1217 | /* Create a dummy tape to satisfy backup databae */ |
| 1218 | code = getXBSATape(&dparams); |
| 1219 | tapeInfo.position = 1; |
| 1220 | } |
| 1221 | if (code) { |
| 1222 | /* If didn't write the label, remove dump from the database */ |
| 1223 | if (!dparams.wroteLabel) { |
| 1224 | i = bcdb_deleteDump(dparams.databaseDumpId, 0, 0, 0); |
| 1225 | if (i && (i != BUDB_NOENT(156303877L))) |
| 1226 | ErrorLog(1, taskId, i, 0, |
| 1227 | "Warning: Can't delete dump %u from database\n", |
| 1228 | dparams.databaseDumpId); |
| 1229 | else |
| 1230 | dparams.databaseDumpId = 0; |
| 1231 | } |
| 1232 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); /* exit with code from getTape */ |
| 1233 | } |
| 1234 | |
| 1235 | startTime = time(0); |
| 1236 | for (pass = 1; pass <= maxpass; pass++) { |
| 1237 | lastPass = (pass == maxpass); |
| 1238 | code = dumpPass(&dparams, pass); |
| 1239 | if (code) |
| 1240 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 1241 | |
| 1242 | /* if no failed volumes, we're done */ |
| 1243 | if ((dparams.volumesDumped + dparams.volumesFailed + |
| 1244 | dparams.volumesNotDumped) == nodePtr->arraySize) |
| 1245 | break; |
| 1246 | } |
| 1247 | |
| 1248 | /* |
| 1249 | * Log the error but ignore it since the dump is effectively done. |
| 1250 | * Scantape may assume another volume and ask for next tape. |
| 1251 | */ |
| 1252 | if (!CONF_XBSA0) { |
| 1253 | code = butm_WriteEOT(&tapeInfo)(*((&tapeInfo)->ops.writeEOT))(&tapeInfo); |
| 1254 | if (code) |
| 1255 | TapeLog(0, taskId, code, tapeInfo.error, |
| 1256 | "Warning: Can't write end-of-dump on tape\n"); |
| 1257 | } |
| 1258 | |
| 1259 | code = |
| 1260 | finishTape(&dparams.tape, |
| 1261 | dparams.tapeInfoPtr->kBytes + |
| 1262 | (dparams.tapeInfoPtr->nBytes ? 1 : 0)); |
| 1263 | if (code) |
| 1264 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 1265 | |
| 1266 | code = finishDump(&dparams.dump); |
| 1267 | if (code) |
| 1268 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 1269 | |
| 1270 | action = dparams.curVolumeStatus; |
| 1271 | code = flushSavedEntries(action); |
| 1272 | if (code) |
| 1273 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 1274 | |
| 1275 | error_exit: |
| 1276 | endTime = time(0); |
| 1277 | Bind(0); |
| 1278 | if (bufferBlock) |
| 1279 | free(bufferBlock); |
| 1280 | |
| 1281 | if (!CONF_XBSA0) { |
| 1282 | unmountTape(taskId, &tapeInfo); |
| 1283 | } |
| 1284 | waitDbWatcher(); |
| 1285 | |
| 1286 | dumpedvolumes = dparams.volumesDumped; |
| 1287 | nodumpvolumes = dparams.volumesNotDumped; |
| 1288 | failedvolumes = nodePtr->arraySize - (dumpedvolumes + nodumpvolumes); |
| 1289 | |
| 1290 | /* pass back the number of volumes we failed to dump */ |
| 1291 | lock_Status(); |
| 1292 | nodePtr->statusNodePtr->volsFailed = failedvolumes; |
| 1293 | unlock_Status(); |
| 1294 | |
| 1295 | lastPass = 1; /* In case we aborted */ |
| 1296 | |
| 1297 | DUMPNAME(finishedMsg1, nodePtr->dumpSetName, dparams.databaseDumpId)if (dparams.databaseDumpId == 0) sprintf(finishedMsg1, "%s", nodePtr ->dumpSetName); else sprintf(finishedMsg1, "%s (DumpId %u)" , nodePtr->dumpSetName, dparams.databaseDumpId);; |
| 1298 | sprintf(finishedMsg2, "%d volumes dumped", dumpedvolumes); |
| 1299 | if (failedvolumes) { |
| 1300 | sprintf(msg, ", %d failed", failedvolumes); |
| 1301 | strcat(finishedMsg2, msg); |
| 1302 | } |
| 1303 | if (nodumpvolumes) { |
| 1304 | sprintf(msg, ", %d unchanged", nodumpvolumes); |
| 1305 | strcat(finishedMsg2, msg); |
| 1306 | } |
| 1307 | |
| 1308 | if (code == TC_ABORTEDBYREQUEST(156566278L)) { |
| 1309 | ErrorLog(0, taskId, 0, 0, "%s: Aborted by request. %s\n", |
| 1310 | finishedMsg1, finishedMsg2); |
| 1311 | clearStatus(taskId, ABORT_REQUEST0x2); |
| 1312 | setStatus(taskId, ABORT_DONE0x8); |
| 1313 | } else if (code) { |
| 1314 | ErrorLog(0, taskId, code, 0, "%s: Finished with errors. %s\n", |
| 1315 | finishedMsg1, finishedMsg2); |
| 1316 | setStatus(taskId, TASK_ERROR0x80); |
| 1317 | } else { |
| 1318 | TLog(taskId, "%s: Finished. %s\n", finishedMsg1, finishedMsg2); |
| 1319 | } |
| 1320 | lastPass = 0; |
| 1321 | |
| 1322 | /* Record how long the dump took */ |
| 1323 | if (centralLogIO && startTime) { |
| 1324 | long timediff; |
| 1325 | afs_int32 hrs, min, sec, tmp; |
| 1326 | char line[1024]; |
| 1327 | struct tm tmstart, tmend; |
| 1328 | |
| 1329 | localtime_r(&startTime, &tmstart); |
| 1330 | localtime_r(&endTime, &tmend); |
| 1331 | timediff = (int)endTime - (int)startTime; |
| 1332 | hrs = timediff / 3600; |
| 1333 | tmp = timediff % 3600; |
| 1334 | min = tmp / 60; |
| 1335 | sec = tmp % 60; |
| 1336 | |
| 1337 | sprintf(line, |
| 1338 | "%-5d %02d/%02d/%04d %02d:%02d:%02d " |
| 1339 | "%02d/%02d/%04d %02d:%02d:%02d " "%02d:%02d:%02d " |
| 1340 | "%s %d of %d volumes dumped (%lu KB)\n", taskId, |
| 1341 | tmstart.tm_mon + 1, tmstart.tm_mday, tmstart.tm_year + 1900, |
| 1342 | tmstart.tm_hour, tmstart.tm_min, tmstart.tm_sec, |
| 1343 | tmend.tm_mon + 1, tmend.tm_mday, tmend.tm_year + 1900, |
| 1344 | tmend.tm_hour, tmend.tm_min, tmend.tm_sec, hrs, min, sec, |
| 1345 | nodePtr->volumeSetName, dumpedvolumes, |
| 1346 | dumpedvolumes + failedvolumes, |
| 1347 | afs_printable_uint32_lu(dparams.tapeInfoPtr->kBytes + 1)); |
| 1348 | |
| 1349 | fwrite(line, strlen(line), 1, centralLogIO); |
| 1350 | fflush(centralLogIO); |
| 1351 | } |
| 1352 | |
| 1353 | setStatus(taskId, TASK_DONE0x20); |
| 1354 | |
| 1355 | FreeNode(taskId); /* free the dump node */ |
| 1356 | LeaveDeviceQueue(deviceLatch); |
| 1357 | return (void *)(intptr_t)(code); |
| 1358 | } |
| 1359 | |
| 1360 | #define BELLTIME60 60 /* 60 seconds before a bell rings */ |
| 1361 | #define BELLCHAR7 7 /* ascii for bell */ |
| 1362 | |
| 1363 | /* retryPrompt |
| 1364 | * prompt the user to decide how to handle a failed volume dump. The |
| 1365 | * volume parameters describe the volume that failed |
| 1366 | * entry: |
| 1367 | * volumeName - name of volume |
| 1368 | * volumeId - volume id |
| 1369 | * taskId - for job contrl |
| 1370 | * fn return: |
| 1371 | * character typed by user, one of r, o or a |
| 1372 | */ |
| 1373 | |
| 1374 | char |
| 1375 | retryPrompt(char *volumeName, afs_int32 volumeId, afs_uint32 taskId) |
| 1376 | { |
| 1377 | afs_int32 start; |
| 1378 | char ch; |
| 1379 | afs_int32 code = 0; |
| 1380 | |
| 1381 | setStatus(taskId, OPR_WAIT0x200); |
| 1382 | printf("\nDump of volume %s (%u) failed\n\n", volumeName, volumeId); |
| 1383 | |
| 1384 | printf("Please select action to be taken for this volume\n"); |
| 1385 | |
| 1386 | again: |
| 1387 | printf("r - retry, try dumping this volume again\n"); |
| 1388 | printf("o - omit, this volume from this dump\n"); |
| 1389 | printf("a - abort, the entire dump\n"); |
| 1390 | |
| 1391 | while (1) { |
| 1392 | FFlushInput(); |
| 1393 | putchar(BELLCHAR)(!__isthreaded ? __sputc(7, __stdoutp) : (putc)(7, __stdoutp) ); |
| 1394 | fflush(stdout__stdoutp); |
| 1395 | |
| 1396 | start = time(0); |
| 1397 | while (1) { |
| 1398 | code = LWP_GetResponseKey(5, &ch); /* ch stores key pressed */ |
| 1399 | if (code == 1) |
| 1400 | break; /* input is available */ |
| 1401 | |
| 1402 | if (checkAbortByTaskId(taskId)) { |
| 1403 | clearStatus(taskId, OPR_WAIT0x200); |
| 1404 | printf |
| 1405 | ("This tape operation has been aborted by the coordinator\n"); |
| 1406 | return 'a'; |
| 1407 | } |
| 1408 | |
| 1409 | if (time(0) > start + BELLTIME60) |
| 1410 | break; |
| 1411 | } |
| 1412 | /* otherwise, we should beep again, check for abort and go back, |
| 1413 | * since the GetResponseKey() timed out. |
| 1414 | */ |
| 1415 | if (code == 1) |
| 1416 | break; /* input is available */ |
| 1417 | } |
| 1418 | clearStatus(taskId, OPR_WAIT0x200); |
| 1419 | if (ch != 'r' && ch != 'o' && ch != 'a') { |
| 1420 | printf("Please select one of the 3 options, r, o or a\n"); |
| 1421 | goto again; |
| 1422 | } |
| 1423 | |
| 1424 | return ch; |
| 1425 | } |
| 1426 | |
| 1427 | /* For testing: it prints the tape label */ |
| 1428 | int |
| 1429 | printTapeLabel(struct butm_tapeLabel *tl) |
| 1430 | { |
| 1431 | printf("Tape Label\n"); |
| 1432 | printf(" structVersion = %d\n", tl->structVersion); |
| 1433 | printf(" creationTime = %u\n", tl->creationTime); |
| 1434 | printf(" expirationDate = %u\n", tl->expirationDate); |
| 1435 | printf(" AFSName = %s\n", tl->AFSName); |
| 1436 | printf(" cell = %s\n", tl->cell); |
| 1437 | printf(" dumpid = %d\n", tl->dumpid); |
| 1438 | printf(" useCount = %d\n", tl->useCount); |
| 1439 | printf(" comment = %s\n", tl->comment); |
| 1440 | printf(" pName = %s\n", tl->pName); |
| 1441 | printf(" size = %u\n", tl->size); |
| 1442 | printf(" dumpPath = %s\n", tl->dumpPath); |
| 1443 | return 0; |
| 1444 | } |
| 1445 | |
| 1446 | /* getXBSATape |
| 1447 | * Create a tape structure to be satisfy the backup database |
| 1448 | * even though we don't really use a tape with XBSA. |
| 1449 | */ |
| 1450 | int |
| 1451 | getXBSATape(struct dumpRock *dparamsPtr) |
| 1452 | { |
| 1453 | struct dumpNode *nodePtr = dparamsPtr->node; |
| 1454 | struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr; |
| 1455 | struct butm_tapeLabel *tapeLabelPtr = &dparamsPtr->tapeLabel; |
| 1456 | afs_int32 code = 0; |
| 1457 | |
| 1458 | tc_MakeTapeName(dparamsPtr->tapeName, &nodePtr->tapeSetDesc,sprintf (dparamsPtr->tapeName, (&nodePtr->tapeSetDesc )->format, (dparamsPtr->tapeSeq) + (&nodePtr->tapeSetDesc )->b) |
| 1459 | dparamsPtr->tapeSeq)sprintf (dparamsPtr->tapeName, (&nodePtr->tapeSetDesc )->format, (dparamsPtr->tapeSeq) + (&nodePtr->tapeSetDesc )->b); |
| 1460 | |
| 1461 | GetNewLabel(tapeInfoPtr, "" /*pName */ , dparamsPtr->tapeName, |
| 1462 | tapeLabelPtr); |
| 1463 | strcpy(tapeLabelPtr->dumpPath, nodePtr->dumpName); |
| 1464 | tapeLabelPtr->dumpid = dparamsPtr->databaseDumpId; |
| 1465 | tapeLabelPtr->expirationDate = |
| 1466 | calcExpirationDate(nodePtr->tapeSetDesc.expType, |
| 1467 | nodePtr->tapeSetDesc.expDate, time(0)); |
| 1468 | |
| 1469 | /* printTapeLabel(tapeLabelPtr); For testing */ |
| 1470 | |
| 1471 | code = |
| 1472 | useTape(&dparamsPtr->tape, dparamsPtr->databaseDumpId, |
| 1473 | dparamsPtr->tapeName, |
| 1474 | (dparamsPtr->tapeSeq + dparamsPtr->dump.tapes.b), |
| 1475 | tapeLabelPtr->useCount, tapeLabelPtr->creationTime, |
| 1476 | tapeLabelPtr->expirationDate, 0 /*tape position */ ); |
| 1477 | return (code); |
| 1478 | } |
| 1479 | |
| 1480 | /* getDumpTape |
| 1481 | * iterate until the desired tape (as specified by the dump structures) |
| 1482 | * is mounted. |
| 1483 | * entry: |
| 1484 | * interactiveFlag |
| 1485 | * 0 - assume the tape is there. Prompt if assumption false |
| 1486 | * 1 - prompt regardless |
| 1487 | */ |
| 1488 | |
| 1489 | int |
| 1490 | getDumpTape(struct dumpRock *dparamsPtr, int interactiveFlag, |
| 1491 | afs_int32 append) |
| 1492 | { |
| 1493 | struct dumpNode *nodePtr = dparamsPtr->node; |
| 1494 | struct butm_tapeInfo *tapeInfoPtr = dparamsPtr->tapeInfoPtr; |
| 1495 | struct butm_tapeLabel *newTapeLabelPtr = &dparamsPtr->tapeLabel; |
| 1496 | char AFSTapeName[TC_MAXTAPENAMELEN100]; |
| 1497 | afs_int32 taskId = nodePtr->taskID; |
| 1498 | struct butm_tapeLabel oldTapeLabel; |
| 1499 | struct budb_dumpEntry dumpEntry; |
| 1500 | struct budb_tapeEntry tapeEntry; |
| 1501 | struct budb_volumeEntry volEntry; |
| 1502 | Dateafs_uint32 expir; |
| 1503 | afs_int32 doAppend; |
| 1504 | afs_int32 code = 0; |
| 1505 | int askForTape; |
| 1506 | int tapecount = 1; |
| 1507 | char strlevel[5]; |
| 1508 | afs_int32 tapepos, lastpos; |
| 1509 | |
| 1510 | extern struct tapeConfig globalTapeConfig; |
| 1511 | |
| 1512 | askForTape = interactiveFlag; |
| 1513 | dparamsPtr->wroteLabel = 0; |
| 1514 | |
| 1515 | /* Keep prompting for a tape until we get it right */ |
| 1516 | while (1) { |
| 1517 | /* What the name of the tape would be if not appending to it */ |
| 1518 | tc_MakeTapeName(AFSTapeName, &nodePtr->tapeSetDesc,sprintf (AFSTapeName, (&nodePtr->tapeSetDesc)->format , (dparamsPtr->tapeSeq) + (&nodePtr->tapeSetDesc)-> b) |
| 1519 | dparamsPtr->tapeSeq)sprintf (AFSTapeName, (&nodePtr->tapeSetDesc)->format , (dparamsPtr->tapeSeq) + (&nodePtr->tapeSetDesc)-> b); |
| 1520 | |
| 1521 | doAppend = append; |
| 1522 | |
| 1523 | if (askForTape) { |
| 1524 | code = |
| 1525 | PromptForTape((doAppend ? APPENDOPCODE5 : WRITEOPCODE1), |
| 1526 | AFSTapeName, dparamsPtr->databaseDumpId, taskId, |
| 1527 | tapecount); |
| 1528 | if (code) |
| 1529 | ERROR_EXIT(code)do { code = code; goto error_exit; } while (0); |
| 1530 | } |
| 1531 | askForTape = 1; |
| 1532 | tapecount++; |
| 1533 | |
| 1534 | /* open the tape device */ |
| 1535 | code = butm_Mount(tapeInfoPtr, AFSTapeName)(*((tapeInfoPtr)->ops.mount))(tapeInfoPtr,AFSTapeName); |
| 1536 | if (code) { |
| 1537 | TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n"); |
| 1538 | goto getNewTape; |
| 1539 | } |
| 1540 | |
| 1541 | /* Read the tape label */ |
| 1542 | code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1)(*((tapeInfoPtr)->ops.readLabel))(tapeInfoPtr,&oldTapeLabel ,1); /* rewind */ |
| 1543 | if (code) { |
| 1544 | if (tapeInfoPtr->error) { |
| 1545 | ErrorLog(0, taskId, code, tapeInfoPtr->error, |
| 1546 | "Warning: Tape error while reading label (will proceed with dump)\n"); |
| 1547 | } |
| 1548 | memset(&oldTapeLabel, 0, sizeof(oldTapeLabel)); |
| 1549 | } |
| 1550 | |
| 1551 | /* Check if null tape. Prior 3.3, backup tapes have no dump id */ |
| 1552 | if ((strcmp(oldTapeLabel.AFSName, "") == 0) |
| 1553 | && (oldTapeLabel.dumpid == 0)) { |
| 1554 | if (doAppend) { |
| 1555 | TLog(taskId, |
| 1556 | "Dump not found on tape. Proceeding with initial dump\n"); |
| 1557 | doAppend = 0; |
| 1558 | } |
| 1559 | } else if (doAppend) { /* appending */ |
| 1560 | /* Check that we don't have a database dump tape */ |
| 1561 | if (databaseTape(oldTapeLabel.AFSName)) { |
| 1562 | char gotName[BU_MAXTAPELEN32 + 32]; |
| 1563 | |
| 1564 | /* label does not match */ |
| 1565 | LABELNAME(gotName, &oldTapeLabel)if (!strcmp("", ( strcmp((&oldTapeLabel)->pName,"") ? ( &oldTapeLabel)->pName : ( strcmp((&oldTapeLabel)-> AFSName,"") ? (&oldTapeLabel)->AFSName : "<NULL>" ) ))) sprintf(gotName, "<NULL>"); else if ((&oldTapeLabel )->dumpid == 0) sprintf(gotName, "%s", ( strcmp((&oldTapeLabel )->pName,"") ? (&oldTapeLabel)->pName : ( strcmp((& oldTapeLabel)->AFSName,"") ? (&oldTapeLabel)->AFSName : "<NULL>" ) )); else sprintf(gotName, "%s (%u)", ( strcmp ((&oldTapeLabel)->pName,"") ? (&oldTapeLabel)-> pName : ( strcmp((&oldTapeLabel)->AFSName,"") ? (& oldTapeLabel)->AFSName : "<NULL>" ) ), (&oldTapeLabel )->dumpid);; |
| 1566 | TLog(taskId, "Can't append to database tape %s\n", gotName); |
| 1567 | goto getNewTape; |
| 1568 | } |
| 1569 | |
| 1570 | /* Verify that the tape is of version 4 (AFS 3.3) or greater */ |
| 1571 | if (oldTapeLabel.structVersion < TAPE_VERSION_44) { |
| 1572 | TLog(taskId, |
| 1573 | "Can't append: requires tape version %d or greater\n", |
| 1574 | TAPE_VERSION_44); |
| 1575 | goto getNewTape; |
| 1576 | } |
| 1577 | |
| 1578 | /* Verify that the last tape of the dump set is in the drive. |
| 1579 | * volEntry will be zeroed if last dump has no volume entries. |
| 1580 | */ |
| 1581 | code = |
| 1582 | bcdb_FindLastTape(oldTapeLabel.dumpid, &dumpEntry, &tapeEntry, |
| 1583 | &volEntry); |
| 1584 | if (code) { |
| 1585 | ErrorLog(0, taskId, code, 0, |
| 1586 | "Can't append: Can't find last volume of dumpId %u in database\n", |
| 1587 | oldTapeLabel.dumpid); |
| 1588 | printf("Please scan the dump in or choose another tape\n"); |
| 1589 | goto getNewTape; |
| 1590 | } |
| 1591 | lastpos = |
| 1592 | (volEntry.position ? volEntry.position : tapeEntry.labelpos); |
| 1593 | |
| 1594 | if (strcmp(TNAME(&oldTapeLabel)( strcmp((&oldTapeLabel)->pName,"") ? (&oldTapeLabel )->pName : ( strcmp((&oldTapeLabel)->AFSName,"") ? ( &oldTapeLabel)->AFSName : "<NULL>" ) ), tapeEntry.name)) { |
| 1595 | char expName[BU_MAXTAPELEN32 + 32], gotName[BU_MAXTAPELEN32 + 32]; |
| 1596 | |
| 1597 | TAPENAME(expName, tapeEntry.name, oldTapeLabel.dumpid)if (!strcmp("", tapeEntry.name)) sprintf(expName, "<NULL>" ); else if (oldTapeLabel.dumpid == 0) sprintf(expName, "%s", tapeEntry .name); else sprintf(expName, "%s (%u)", tapeEntry.name, oldTapeLabel .dumpid);; |
| 1598 | LABELNAME(gotName, &oldTapeLabel)if (!strcmp("", ( strcmp((&oldTapeLabel)->pName,"") ? ( &oldTapeLabel)->pName : ( strcmp((&oldTapeLabel)-> AFSName,"") ? (&oldTapeLabel)->AFSName : "<NULL>" ) ))) sprintf(gotName, "<NULL>"); else if ((&oldTapeLabel )->dumpid == 0) sprintf(gotName, "%s", ( strcmp((&oldTapeLabel )->pName,"") ? (&oldTapeLabel)->pName : ( strcmp((& oldTapeLabel)->AFSName,"") ? (&oldTapeLabel)->AFSName : "<NULL>" ) )); else sprintf(gotName, "%s (%u)", ( strcmp ((&oldTapeLabel)->pName,"") ? (&oldTapeLabel)-> pName : ( strcmp((&oldTapeLabel)->AFSName,"") ? (& oldTapeLabel)->AFSName : "<NULL>" ) ), (&oldTapeLabel )->dumpid);; |
| 1599 | |
| 1600 | TLog(taskId, |
| 1601 | "Can't append: Last tape in dump-set is %s, label seen %s\n", |
| 1602 | expName, gotName); |
| 1603 | goto getNewTape; |
| 1604 | } |
| 1605 | |
| 1606 | /* After reading the tape label, we now know what it is */ |
| 1607 | strcpy(AFSTapeName, oldTapeLabel.AFSName); /* the real name */ |
| 1608 | strcpy(tapeInfoPtr->name, oldTapeLabel.AFSName); /* the real name */ |
| 1609 | |
| 1610 | /* Position after last volume on the tape */ |
| 1611 | code = butm_SeekEODump(tapeInfoPtr, lastpos)(*((tapeInfoPtr)->ops.seekEODump))(tapeInfoPtr,lastpos); |
| 1612 | if (code) { |
| 1613 | ErrorLog(0, taskId, code, tapeInfoPtr->error, |
| 1614 | "Can't append: Can't position to end of dump on tape %s\n", |
| 1615 | tapeEntry.name); |
| 1616 | goto getNewTape; |
| 1617 | } |
| 1618 | |
| 1619 | /* Track size of tape - set after seek since seek changes the value */ |
| 1620 | tapeInfoPtr->kBytes = tapeEntry.useKBytes; |
| 1621 | } else { /* not appending */ |
| 1622 | |
| 1623 | afs_uint32 tapeid; |
| 1624 | afs_uint32 dmp; |
| 1625 | struct budb_dumpEntry de, de2; |
| 1626 | |
| 1627 | /* Check if tape name is not what expected - null tapes are acceptable |
| 1628 | * Don't do check if the tape has a user defined label. |
| 1629 | */ |
| 1630 | if (dump_namecheck && (strcmp(oldTapeLabel.pName, "") == 0)) { |
| 1631 | if (strcmp(oldTapeLabel.AFSName, "") && /* not null tape */ |
| 1632 | strcmp(oldTapeLabel.AFSName, AFSTapeName)) { /* not expected name */ |
| 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 | /* label does not match */ |
| 1641 | TLog(taskId, |
| 1642 | "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 | /* Do not overwrite a tape that belongs to the dump's dumpset */ |
| 1659 | tapeid = |
| 1660 | (dparamsPtr->initialDumpId ? dparamsPtr-> |
| 1661 | initialDumpId : dparamsPtr->databaseDumpId); |
| 1662 | if (oldTapeLabel.dumpid == tapeid) { |
| 1663 | ErrorLog(0, taskId, 0, 0, |
| 1664 | "Can't overwrite tape containing the dump in progress\n"); |
| 1665 | goto getNewTape; |
| 1666 | } |
| 1667 | |
| 1668 | /* Since the dumpset on this tape will be deleted from database, check if |
| 1669 | * any of the dump's parent-dumps are on this tape. |
| 1670 | */ |
| 1671 | for (dmp = nodePtr->parent; dmp; dmp = de.parent) { |
| 1672 | code = bcdb_FindDumpByID(dmp, &de); |
| 1673 | if (code) { |
| 1674 | ErrorLog(0, taskId, 0, 0, |
| 1675 | "Warning: Can't find parent dump %u in backup database\n", |
| 1676 | dmp); |
| 1677 | break; |
| 1678 | } |
| 1679 | |
| 1680 | tapeid = (de.initialDumpID ? de.initialDumpID : de.id); |
| 1681 | if (oldTapeLabel.dumpid == tapeid) { |
| 1682 | ErrorLog(0, taskId, 0, 0, |
| 1683 | "Can't overwrite the parent dump %s (DumpID %u)\n", |
| 1684 | de.name, de.id); |
| 1685 | goto getNewTape; |
| 1686 | } |
| 1687 | } |
| 1688 | |
| 1689 | /* Since the dumpset on this tape will be deleted from database, check if |
| 1690 | * any of the dumps in this dumpset are most-recent-dumps. |
| 1691 | */ |
| 1692 | for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) { |
| 1693 | if (dmp == dparamsPtr->lastDump.id) { |
| 1694 | memcpy(&de, &dparamsPtr->lastDump, sizeof(de)); |
| 1695 | memcpy(&de2, &dparamsPtr->lastDump, sizeof(de2)); |
| 1696 | } else { |
| 1697 | code = bcdb_FindDumpByID(dmp, &de); |
| 1698 | if (code) |
| 1699 | break; |
| 1700 | sprintf(strlevel, "%d", de.level); |
| 1701 | code = |
| 1702 | bcdb_FindLatestDump(de.volumeSetName, strlevel, |
| 1703 | &de2); |
| 1704 | if (code) |
| 1705 | continue; |
| 1706 | } |
| 1707 | |
| 1708 | /* If dump on the tape is the latest dump at this level */ |
| 1709 | if (de.id == de2.id) { |
| 1710 | if (strcmp(DUMP_TAPE_NAME"Ubik_db_dump", de2.name) == 0) { |
| 1711 | ErrorLog(0, taskId, 0, 0, |
| 1712 | "Warning: Overwriting most recent dump %s (DumpID %u)\n", |
| 1713 | de.name, de.id); |
| 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, |
| 1732 | newTapeLabelPtr); |
| 1733 | strcpy(newTapeLabelPtr->dumpPath, nodePtr->dumpName); |
| 1734 | newTapeLabelPtr->expirationDate = |
| 1735 | calcExpirationDate(nodePtr->tapeSetDesc.expType, |
| 1736 | nodePtr->tapeSetDesc.expDate, time(0)); |
| 1737 | newTapeLabelPtr->dumpid = dparamsPtr->databaseDumpId; |
| 1738 | newTapeLabelPtr->useCount = oldTapeLabel.useCount; |
| 1739 | |
| 1740 | if (!doAppend) { |
| 1741 | newTapeLabelPtr->useCount++; |
| 1742 | if (dparamsPtr->initialDumpId) { |
| 1743 | newTapeLabelPtr->dumpid = dparamsPtr->initialDumpId; |
| 1744 | expir = ExpirationDate(dparamsPtr->initialDumpId); |
| 1745 | if (expir > newTapeLabelPtr->expirationDate) |
| 1746 | newTapeLabelPtr->expirationDate = expir; |
| 1747 | } |
| 1748 | } |
| 1749 | |
| 1750 | /* write the label on the tape - rewind if not appending and vice-versa */ |
| 1751 | code = butm_Create(tapeInfoPtr, newTapeLabelPtr, !doAppend)(*((tapeInfoPtr)->ops.create))(tapeInfoPtr,newTapeLabelPtr ,!doAppend); |
| 1752 | if (code) { |
| 1753 | char gotName[BU_MAXTAPELEN32 + 32]; |
| 1754 | |
| 1755 | LABELNAME(gotName, newTapeLabelPtr)if (!strcmp("", ( strcmp((newTapeLabelPtr)->pName,"") ? (newTapeLabelPtr )->pName : ( strcmp((newTapeLabelPtr)->AFSName,"") ? (newTapeLabelPtr )->AFSName : "<NULL>" ) ))) sprintf(gotName, "<NULL>" ); else if ((newTapeLabelPtr)->dumpid == 0) sprintf(gotName , "%s", ( strcmp((newTapeLabelPtr)->pName,"") ? (newTapeLabelPtr )->pName : ( strcmp((newTapeLabelPtr)->AFSName,"") ? (newTapeLabelPtr )->AFSName : "<NULL>" ) )); else sprintf(gotName, "%s (%u)" , ( strcmp((newTapeLabelPtr)->pName,"") ? (newTapeLabelPtr )->pName : ( strcmp((newTapeLabelPtr)->AFSName,"") ? (newTapeLabelPtr )->AFSName : "<NULL>" ) ), (newTapeLabelPtr)->dumpid );; |
| 1756 | TapeLog(0, taskId, code, tapeInfoPtr->error, |
| 1757 | "Can't label tape as %s\n", gotName); |
| 1758 | goto getNewTape; |
| 1759 | } |
| 1760 | dparamsPtr->wroteLabel = 1; /* Remember we wrote the label */ |
| 1761 | tapepos = tapeInfoPtr->position - 1; |
| 1762 | |
| 1763 | strcpy(dparamsPtr->tapeName, TNAME(newTapeLabelPtr)( strcmp((newTapeLabelPtr)->pName,"") ? (newTapeLabelPtr)-> pName : ( strcmp((newTapeLabelPtr)->AFSName,"") ? (newTapeLabelPtr )->AFSName : "<NULL>" ) )); |
| 1764 | |
| 1765 | /* If appending, set dumpentry in the database as appended. */ |
| 1766 | if (doAppend) { |
| 1767 | char gotName[BU_MAXTAPELEN32 + 32]; |
| 1768 | |
| 1769 | nodePtr->tapeSetDesc.b = extractTapeSeq(AFSTapeName); |
| 1770 | dparamsPtr->dump.tapes.b = nodePtr->tapeSetDesc.b; |
| 1771 | dparamsPtr->initialDumpId = oldTapeLabel.dumpid; |
| 1772 | strcpy(nodePtr->tapeSetDesc.format, dumpEntry.tapes.format); |
| 1773 | |
| 1774 | code = |
| 1775 | bcdb_MakeDumpAppended(dparamsPtr->databaseDumpId, |
| 1776 | dparamsPtr->initialDumpId, |
| 1777 | nodePtr->tapeSetDesc.b); |
| 1778 | if (code) |
| 1779 | ErrorLog(2, taskId, code, 0, |
| 1780 | "Warning: Can't append dump %u to dump %u in database\n", |
| 1781 | dparamsPtr->databaseDumpId, |
| 1782 | dparamsPtr->initialDumpId); |
| 1783 | |
| 1784 | LABELNAME(gotName, &oldTapeLabel)if (!strcmp("", ( strcmp((&oldTapeLabel)->pName,"") ? ( &oldTapeLabel)->pName : ( strcmp((&oldTapeLabel)-> AFSName,"") ? (&oldTapeLabel)->AFSName : "<NULL>" ) ))) sprintf(gotName, "<NULL>"); else if ((&oldTapeLabel )->dumpid == 0) sprintf(gotName, "%s", ( strcmp((&oldTapeLabel )->pName,"") ? (&oldTapeLabel)->pName : ( strcmp((& oldTapeLabel)->AFSName,"") ? (&oldTapeLabel)->AFSName : "<NULL>" ) )); else sprintf(gotName, "%s (%u)", ( strcmp ((&oldTapeLabel)->pName,"") ? (&oldTapeLabel)-> pName : ( strcmp((&oldTapeLabel)->AFSName,"") ? (& oldTapeLabel)->AFSName : "<NULL>" ) ), (&oldTapeLabel )->dumpid);; |
| 1785 | TLog(taskId, "Appending dump %s (DumpID %u) to tape %s\n", |
| 1786 | nodePtr->dumpSetName, dparamsPtr->databaseDumpId, gotName); |
| 1787 | } |
| 1788 | |
| 1789 | /* If not appending, delete overwritten dump from the database */ |
| 1790 | else { |
| 1791 | if ((oldTapeLabel.structVersion >= TAPE_VERSION_33) |
| 1792 | && oldTapeLabel.dumpid) { |
| 1793 | code = bcdb_deleteDump(oldTapeLabel.dumpid, 0, 0, 0); |
| 1794 | if (code && (code != BUDB_NOENT(156303877L))) |
| 1795 | ErrorLog(0, taskId, code, 0, |
| 1796 | "Warning: Can't delete old dump %u from database\n", |
| 1797 | oldTapeLabel.dumpid); |
| 1798 | } |
| 1799 | } |
| 1800 | |
| 1801 | code = |
| 1802 | useTape(&dparamsPtr->tape, dparamsPtr->databaseDumpId, |
| 1803 | dparamsPtr->tapeName, |
| 1804 | (dparamsPtr->tapeSeq + dparamsPtr->dump.tapes.b), |
| 1805 | newTapeLabelPtr->useCount, newTapeLabelPtr->creationTime, |
| 1806 | newTapeLabelPtr->expirationDate, tapepos); |
| 1807 | |
| 1808 | /* |
| 1809 | * The margin of space to check for end of tape is set to the |
| 1810 | * amount of space used to write an end-of-tape multiplied by 2. |
| 1811 | * The amount of space is size of a 16K volume trailer, a 16K File |
| 1812 | * End mark, its EOF marker, a 16K EODump marker, its EOF marker, |
| 1813 | * and up to two EOF markers done on close (3 16K blocks + 4 EOF |
| 1814 | * markers). |
| 1815 | */ |
| 1816 | tc_EndMargin = (3 * 16384 + 4 * globalTapeConfig.fileMarkSize) * 2; |
| 1817 | tc_KEndMargin = tc_EndMargin / 1024; |
| 1818 | break; |
| 1819 | |
| 1820 | getNewTape: |
| 1821 | unmountTape(taskId, tapeInfoPtr); |
| 1822 | } |
| 1823 | |
| 1824 | error_exit: |
| 1825 | return (code); |
| 1826 | } |
| 1827 | |
| 1828 | int |
| 1829 | makeVolumeHeader(struct volumeHeader *vhptr, 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_VOLBEGINMAGIC0xb0258191; |
| 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_VERSION4; |
| 1853 | strcpy(vhptr->dumpSetName, nodePtr->dumpSetName); |
| 1854 | strcpy(vhptr->preamble, "H++NAME#"); |
| 1855 | strcpy(vhptr->postamble, "T--NAME#"); |
| 1856 | |
| 1857 | return (code); |
| 1858 | } |
| 1859 | |
| 1860 | int |
| 1861 | volumeHeader_hton(struct volumeHeader *hostPtr, struct volumeHeader *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)(__builtin_constant_p(hostPtr->volumeID) ? ((((__uint32_t) (hostPtr->volumeID)) >> 24) | ((((__uint32_t)(hostPtr ->volumeID)) & (0xff << 16)) >> 8) | ((((__uint32_t )(hostPtr->volumeID)) & (0xff << 8)) << 8) | (((__uint32_t)(hostPtr->volumeID)) << 24)) : __bswap32_var (hostPtr->volumeID)); |
| 1870 | volHdr.server = htonl(hostPtr->server)(__builtin_constant_p(hostPtr->server) ? ((((__uint32_t)(hostPtr ->server)) >> 24) | ((((__uint32_t)(hostPtr->server )) & (0xff << 16)) >> 8) | ((((__uint32_t)(hostPtr ->server)) & (0xff << 8)) << 8) | (((__uint32_t )(hostPtr->server)) << 24)) : __bswap32_var(hostPtr-> server)); |
| 1871 | volHdr.part = htonl(hostPtr->part)(__builtin_constant_p(hostPtr->part) ? ((((__uint32_t)(hostPtr ->part)) >> 24) | ((((__uint32_t)(hostPtr->part)) & (0xff << 16)) >> 8) | ((((__uint32_t)(hostPtr ->part)) & (0xff << 8)) << 8) | (((__uint32_t )(hostPtr->part)) << 24)) : __bswap32_var(hostPtr-> part)); |
| 1872 | volHdr.from = htonl(hostPtr->from)(__builtin_constant_p(hostPtr->from) ? ((((__uint32_t)(hostPtr ->from)) >> 24) | ((((__uint32_t)(hostPtr->from)) & (0xff << 16)) >> 8) | ((((__uint32_t)(hostPtr ->from)) & (0xff << 8)) << 8) | (((__uint32_t )(hostPtr->from)) << 24)) : __bswap32_var(hostPtr-> from)); |
| 1873 | volHdr.frag = htonl(hostPtr->frag)(__builtin_constant_p(hostPtr->frag) ? ((((__uint32_t)(hostPtr ->frag)) >> 24) | ((((__uint32_t)(hostPtr->frag)) & (0xff << 16)) >> 8) | ((((__uint32_t)(hostPtr ->frag)) & (0xff << 8)) << 8) | (((__uint32_t )(hostPtr->frag)) << 24)) : __bswap32_var(hostPtr-> frag)); |
| 1874 | volHdr.magic = htonl(hostPtr->magic)(__builtin_constant_p(hostPtr->magic) ? ((((__uint32_t)(hostPtr ->magic)) >> 24) | ((((__uint32_t)(hostPtr->magic )) & (0xff << 16)) >> 8) | ((((__uint32_t)(hostPtr ->magic)) & (0xff << 8)) << 8) | (((__uint32_t )(hostPtr->magic)) << 24)) : __bswap32_var(hostPtr-> magic)); |
| 1875 | volHdr.contd = htonl(hostPtr->contd)(__builtin_constant_p(hostPtr->contd) ? ((((__uint32_t)(hostPtr ->contd)) >> 24) | ((((__uint32_t)(hostPtr->contd )) & (0xff << 16)) >> 8) | ((((__uint32_t)(hostPtr ->contd)) & (0xff << 8)) << 8) | (((__uint32_t )(hostPtr->contd)) << 24)) : __bswap32_var(hostPtr-> contd)); |
| 1876 | volHdr.dumpID = htonl(hostPtr->dumpID)(__builtin_constant_p(hostPtr->dumpID) ? ((((__uint32_t)(hostPtr ->dumpID)) >> 24) | ((((__uint32_t)(hostPtr->dumpID )) & (0xff << 16)) >> 8) | ((((__uint32_t)(hostPtr ->dumpID)) & (0xff << 8)) << 8) | (((__uint32_t )(hostPtr->dumpID)) << 24)) : __bswap32_var(hostPtr-> dumpID)); |
| 1877 | volHdr.level = htonl(hostPtr->level)(__builtin_constant_p(hostPtr->level) ? ((((__uint32_t)(hostPtr ->level)) >> 24) | ((((__uint32_t)(hostPtr->level )) & (0xff << 16)) >> 8) | ((((__uint32_t)(hostPtr ->level)) & (0xff << 8)) << 8) | (((__uint32_t )(hostPtr->level)) << 24)) : __bswap32_var(hostPtr-> level)); |
| 1878 | volHdr.parentID = htonl(hostPtr->parentID)(__builtin_constant_p(hostPtr->parentID) ? ((((__uint32_t) (hostPtr->parentID)) >> 24) | ((((__uint32_t)(hostPtr ->parentID)) & (0xff << 16)) >> 8) | ((((__uint32_t )(hostPtr->parentID)) & (0xff << 8)) << 8) | (((__uint32_t)(hostPtr->parentID)) << 24)) : __bswap32_var (hostPtr->parentID)); |
| 1879 | volHdr.endTime = htonl(hostPtr->endTime)(__builtin_constant_p(hostPtr->endTime) ? ((((__uint32_t)( hostPtr->endTime)) >> 24) | ((((__uint32_t)(hostPtr-> endTime)) & (0xff << 16)) >> 8) | ((((__uint32_t )(hostPtr->endTime)) & (0xff << 8)) << 8) | (((__uint32_t)(hostPtr->endTime)) << 24)) : __bswap32_var (hostPtr->endTime)); |
| 1880 | volHdr.versionflags = htonl(hostPtr->versionflags)(__builtin_constant_p(hostPtr->versionflags) ? ((((__uint32_t )(hostPtr->versionflags)) >> 24) | ((((__uint32_t)(hostPtr ->versionflags)) & (0xff << 16)) >> 8) | ( (((__uint32_t)(hostPtr->versionflags)) & (0xff << 8)) << 8) | (((__uint32_t)(hostPtr->versionflags)) << 24)) : __bswap32_var(hostPtr->versionflags)); |
| 1881 | volHdr.cloneDate = htonl(hostPtr->cloneDate)(__builtin_constant_p(hostPtr->cloneDate) ? ((((__uint32_t )(hostPtr->cloneDate)) >> 24) | ((((__uint32_t)(hostPtr ->cloneDate)) & (0xff << 16)) >> 8) | (((( __uint32_t)(hostPtr->cloneDate)) & (0xff << 8)) << 8) | (((__uint32_t)(hostPtr->cloneDate)) << 24)) : __bswap32_var (hostPtr->cloneDate)); |
| 1882 | |
| 1883 | memcpy(netPtr, &volHdr, sizeof(struct volumeHeader)); |
| 1884 | return 0; |
| 1885 | } |
| 1886 | |
| 1887 | /* database related routines */ |
| 1888 | |
| 1889 | afs_int32 |
| 1890 | createDump(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_XBSA0) { |
| 1905 | if (xbsaType == XBSA_SERVER_TYPE_ADSM0x02) { |
| 1906 | strcpy(dumpPtr->tapes.tapeServer, butxInfo.serverName); |
| 1907 | dumpPtr->flags = BUDB_DUMP_ADSM(1<<12); |
| 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(1<<8); |
| 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) |
| 1941 | dparamsPtr->databaseDumpId = dumpPtr->id; |
| 1942 | |
| 1943 | return (code); |
| 1944 | } |
| 1945 | |
| 1946 | #ifdef xbsa |
| 1947 | /* InitToServer: |
| 1948 | * Initialize to a specific server. The first time, we remember the |
| 1949 | * server as the original server and go back to it each time we pass 0 |
| 1950 | * as the server. |
| 1951 | */ |
| 1952 | afs_int32 |
| 1953 | InitToServer(afs_int32 taskId, struct butx_transactionInfo * butxInfoP, |
| 1954 | char *server) |
| 1955 | { |
| 1956 | static char origserver[BSA_MAX_DESC]; |
| 1957 | static int init = 0; |
| 1958 | afs_int32 rc, code = 0; |
| 1959 | |
| 1960 | if (!init) { |
| 1961 | strcpy(origserver, ""); |
| 1962 | init = 1; |
| 1963 | } |
| 1964 | |
| 1965 | if (!server) |
| 1966 | server = origserver; /* return to original server */ |
| 1967 | if (strcmp(server, "") == 0) |
| 1968 | return 0; /* No server, do nothing */ |
| 1969 | if (strcmp(butxInfoP->serverName, server) == 0) |
| 1970 | return 0; /* same server, do nothing */ |
| 1971 | if (strcmp(origserver, "") == 0) |
| 1972 | strcpy(origserver, server); /* remember original server */ |
| 1973 | |
| 1974 | if (strcmp(butxInfoP->serverName, "") != 0) { |
| 1975 | /* If already connected to a server, disconnect from it. |
| 1976 | * Check to see if our server does not support switching. |
| 1977 | */ |
| 1978 | if (!(butxInfo.serverType & XBSA_SERVER_FLAG_MULTIPLE)) { |
| 1979 | ErrorLog(0, taskId, TC_BADTASK(156566293L), 0, |
| 1980 | "This version of XBSA libraries does not support switching " |
| 1981 | "from server %s to server %s\n", butxInfoP->serverName, |
| 1982 | server); |
| 1983 | return (TC_BADTASK(156566293L)); |
| 1984 | } |
| 1985 | |
| 1986 | rc = xbsa_Finalize(&butxInfo); |
| 1987 | if (rc != XBSA_SUCCESS) { |
| 1988 | ErrorLog(0, taskId, rc, 0, |
| 1989 | "InitToServer: Unable to terminate the connection to server %s\n", |
| 1990 | butxInfoP->serverName); |
| 1991 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 1992 | } |
| 1993 | } |
| 1994 | |
| 1995 | /* initialize to the new server */ |
| 1996 | rc = xbsa_Initialize(&butxInfo, xbsaObjectOwner, appObjectOwner, |
| 1997 | xbsaSecToken, server); |
| 1998 | if (rc != XBSA_SUCCESS) { |
| 1999 | ErrorLog(0, taskId, rc, 0, |
| 2000 | "InitToServer: Unable to initialize the XBSA library to server %s\n", |
| 2001 | server); |
| 2002 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 2003 | } |
| 2004 | |
| 2005 | error_exit: |
| 2006 | return (code); |
| 2007 | } |
| 2008 | |
| 2009 | |
| 2010 | /* DeleteDump |
| 2011 | * |
| 2012 | */ |
| 2013 | void * |
| 2014 | DeleteDump(void *param) |
| 2015 | { |
| 2016 | struct deleteDumpIf *ptr = (struct deleteDumpIf *)param; |
| 2017 | |
| 2018 | afs_int32 taskId; |
| 2019 | afs_int32 rc, code = 0; |
| 2020 | afs_uint32 dumpid; |
| 2021 | afs_int32 index, next, dbTime; |
| 2022 | budb_volumeList vl; |
| 2023 | struct budb_dumpEntry dumpEntry; |
| 2024 | char tapeName[BU_MAXTAPELEN32]; |
| 2025 | char dumpIdStr[XBSA_MAX_OSNAME]; |
| 2026 | char volumeNameStr[XBSA_MAX_PATHNAME]; |
| 2027 | afs_int32 i; |
| 2028 | int intrans = 0; |
| 2029 | int allnotfound = 1, onenotfound = 0; |
| 2030 | extern struct udbHandleS udbHandle; |
| 2031 | extern struct deviceSyncNode *deviceLatch; |
| 2032 | |
| 2033 | afs_pthread_setname_self("deletedump")(void)0; |
| 2034 | setStatus(taskId, DRIVE_WAIT0x100); |
| 2035 | EnterDeviceQueue(deviceLatch); |
| 2036 | clearStatus(taskId, DRIVE_WAIT0x100); |
| 2037 | |
| 2038 | dumpid = ptr->dumpID; |
| 2039 | taskId = ptr->taskId; /* Get task Id */ |
| 2040 | |
| 2041 | printf("\n\n"); |
| 2042 | TapeLog(2, taskId, 0, 0, "Delete Dump %u\n", dumpid); |
| 2043 | |
| 2044 | vl.budb_volumeList_len = 0; |
| 2045 | vl.budb_volumeList_val = 0; |
| 2046 | tapeName[0] = '\0'; |
| 2047 | |
| 2048 | /* Get the dump info for the dump we are deleting */ |
| 2049 | rc = bcdb_FindDumpByID(dumpid, &dumpEntry); |
| 2050 | if (rc) { |
| 2051 | ErrorLog(0, taskId, rc, 0, |
| 2052 | "Unable to locate dump ID %u in database\n", dumpid); |
| 2053 | setStatus(taskId, TASK_ERROR0x80); |
| 2054 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 2055 | } |
| 2056 | |
| 2057 | /* we must make sure that we are configured with the correct type of |
| 2058 | * XBSA server for this dump delete! Only those dumped to an ADSM server. |
| 2059 | */ |
| 2060 | if ((xbsaType == XBSA_SERVER_TYPE_ADSM0x02) |
| 2061 | && !((dumpEntry.flags & (BUDB_DUMP_ADSM(1<<12) | BUDB_DUMP_BUTA(1<<11))))) { |
| 2062 | ErrorLog(0, taskId, TC_BADTASK(156566293L), 0, |
| 2063 | "The dump %u requested for deletion is incompatible with this instance of butc\n", |
| 2064 | dumpid); |
| 2065 | setStatus(taskId, TASK_ERROR0x80); |
| 2066 | ERROR_EXIT(TC_BADTASK)do { code = (156566293L); goto error_exit; } while (0); |
| 2067 | } |
| 2068 | |
| 2069 | /* Make sure we are connected to the correct server. If not, switch to it if appropriate */ |
| 2070 | if ((strlen((char *)dumpEntry.tapes.tapeServer) != 0) |
| 2071 | && (strcmp((char *)dumpEntry.tapes.tapeServer, butxInfo.serverName) != |
| 2072 | 0)) { |
| 2073 | |
| 2074 | /* Check to see if the tapeServer name is trustworthy */ |
| 2075 | if ((dumpEntry.flags & (BUDB_DUMP_XBSA_NSS(1<<8) | BUDB_DUMP_BUTA(1<<11))) |
| 2076 | && !forcemultiple) { |
| 2077 | /* The dump was made with a version of the XBSA interface |
| 2078 | * that didn't allow switching of servers, we can't be sure |
| 2079 | * that the servername in the backup database is correct. So, |
| 2080 | * we will check the servername and log it if they don't match; |
| 2081 | * but we will try to do the delete without switching servers. |
| 2082 | */ |
| 2083 | TLog(taskId, |
| 2084 | "The dump %d requested for deletion is on server %s " |
| 2085 | "but butc is connected to server %s " |
| 2086 | "(Attempting to delete the dump anyway)\n", dumpid, |
| 2087 | (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName); |
| 2088 | } else { |
| 2089 | TLog(taskId, |
| 2090 | "The dump %u requested for deletion is on server %s " |
| 2091 | "but butc is connected to server %s " |
| 2092 | "(switching servers)\n", dumpid, |
| 2093 | (char *)dumpEntry.tapes.tapeServer, butxInfo.serverName); |
| 2094 | |
| 2095 | rc = InitToServer(taskId, &butxInfo, |
| 2096 | (char *)dumpEntry.tapes.tapeServer); |
| 2097 | if (rc != XBSA_SUCCESS) { |
| 2098 | setStatus(taskId, TASK_ERROR0x80); |
| 2099 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 2100 | } |
| 2101 | } |
| 2102 | } |
| 2103 | |
| 2104 | /* Start a new Transaction */ |
| 2105 | rc = xbsa_BeginTrans(&butxInfo); |
| 2106 | if (rc != XBSA_SUCCESS) { |
| 2107 | ErrorLog(0, taskId, rc, 0, "Unable to create a new transaction\n"); |
| 2108 | setStatus(taskId, TASK_ERROR0x80); |
| 2109 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 2110 | } |
| 2111 | intrans = 1; |
| 2112 | |
| 2113 | /* Query the backup database for list of volumes to delete */ |
| 2114 | for (index = next = 0; index != -1; index = next) { |
| 2115 | rc = ubik_Call_SingleServer(BUDB_GetVolumes, udbHandle.uh_client, |
| 2116 | UF_SINGLESERVER1, BUDB_MAJORVERSION2, |
| 2117 | BUDB_OP_DUMPID(2<<3), tapeName, dumpid, 0, |
| 2118 | index, &next, &dbTime, &vl); |
| 2119 | if (rc) { |
| 2120 | if (rc == BUDB_ENDOFLIST(156303886L)) |
| 2121 | break; |
| 2122 | ErrorLog(0, taskId, rc, 0, "Can't find volume info for dump %d\n", |
| 2123 | dumpid); |
| 2124 | setStatus(taskId, TASK_ERROR0x80); |
| 2125 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 2126 | } |
| 2127 | |
| 2128 | /* Delete all volumes on the list */ |
| 2129 | for (i = 0; i < vl.budb_volumeList_len; i++) { |
| 2130 | if (dumpEntry.flags & BUDB_DUMP_BUTA(1<<11)) { |
| 2131 | /* dump was from buta, use old buta style names */ |
| 2132 | sprintf(dumpIdStr, "/%d", dumpid); |
| 2133 | strcpy(volumeNameStr, "/"); |
| 2134 | strcat(volumeNameStr, (char *)vl.budb_volumeList_val[i].name); |
| 2135 | } else { /* BUDB_DUMP_ADSM */ |
| 2136 | /* dump was from butc to ADSM, use butc names */ |
| 2137 | strcpy(dumpIdStr, butcdumpIdStr); |
| 2138 | sprintf(volumeNameStr, "/%d", dumpid); |
| 2139 | strcat(volumeNameStr, "/"); |
| 2140 | strcat(volumeNameStr, (char *)vl.budb_volumeList_val[i].name); |
| 2141 | } |
| 2142 | |
| 2143 | rc = xbsa_DeleteObject(&butxInfo, dumpIdStr, volumeNameStr); |
| 2144 | if (rc != XBSA_SUCCESS) { |
| 2145 | ErrorLog(0, taskId, rc, 0, |
| 2146 | "Unable to delete the object %s of dump %s from the server\n", |
| 2147 | volumeNameStr, dumpIdStr); |
| 2148 | /* Don't exit if volume was not found */ |
| 2149 | if (rc != BUTX_DELETENOVOL(156571678L)) { |
| 2150 | allnotfound = 0; |
| 2151 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 2152 | } |
| 2153 | onenotfound = 1; |
| 2154 | } else { |
| 2155 | allnotfound = 0; |
| 2156 | TLog(0, |
| 2157 | "Deleted volume %s (%u) in dumpID %u from the backup server\n", |
| 2158 | vl.budb_volumeList_val[i].name, |
| 2159 | vl.budb_volumeList_val[i].id, dumpid); |
| 2160 | } |
| 2161 | } |
| 2162 | |
| 2163 | /* free the memory allocated by RPC for this list */ |
| 2164 | if (vl.budb_volumeList_val) |
| 2165 | free(vl.budb_volumeList_val); |
| 2166 | vl.budb_volumeList_len = 0; |
| 2167 | vl.budb_volumeList_val = 0; |
| 2168 | } |
| 2169 | |
| 2170 | error_exit: |
| 2171 | if (intrans) { |
| 2172 | rc = xbsa_EndTrans(&butxInfo); |
| 2173 | if (rc != XBSA_SUCCESS) { |
| 2174 | ErrorLog(0, taskId, rc, 0, |
| 2175 | "Unable to terminate the current transaction\n"); |
| 2176 | setStatus(taskId, TASK_ERROR0x80); |
| 2177 | ERROR_EXIT(rc)do { code = rc; goto error_exit; } while (0); |
| 2178 | } |
| 2179 | } |
| 2180 | |
| 2181 | /* Switch back to the original server */ |
| 2182 | rc = InitToServer(taskId, &butxInfo, NULL((void *)0)); |
| 2183 | |
| 2184 | if (vl.budb_volumeList_val) |
| 2185 | free(vl.budb_volumeList_val); |
| 2186 | |
| 2187 | setStatus(taskId, TASK_DONE0x20); |
| 2188 | FreeNode(taskId); /* free the dump node */ |
| 2189 | LeaveDeviceQueue(deviceLatch); |
| 2190 | |
| 2191 | /* If we don't find any dumps on the server, rather than returning |
| 2192 | * a success, return a failure. |
| 2193 | */ |
| 2194 | if (!code && onenotfound && allnotfound) { |
| 2195 | code = BUTX_DELETENOVOL(156571678L); |
| 2196 | setStatus(taskId, TASK_ERROR0x80); |
| 2197 | } |
| 2198 | return (void *)(code); |
| 2199 | } |
| 2200 | #endif |