| File: | butc/dump.c |
| Location: | line 1207, column 2 |
| Description: | Assigned value is always the same as the existing value |
| 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; | ||||
| 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 |