/* * This function controls our communication with TSM */ #define BUFLEN (64*1024-4) #include #include #include #include #include #include "dsmrc.h" #include "dsmapitd.h" #include "dsmapifp.h" #include "../tsmpipe.h" int tsm_matchone_cb(dsmQueryType qType, DataBlk *qResp, void *userdata, dsmBool_t friendly) { struct matchone_cb_data *cbdata = userdata; if (friendly) debugLog(0,__func__,"ERROR: Friendly is set?",1); cbdata->numfound++; if (qType == qtArchive) { qryRespArchiveData *qr = (void *) qResp->bufferPtr; cbdata->objId = qr->objId; } else if(qType == qtBackup) { qryRespBackupData *qr = (void *) qResp->bufferPtr; cbdata->objId = qr->objId; cbdata->copyGroup = qr->copyGroup; } else { fprintf(stderr,"%s: UNKNOWN Type %d\n",__func__,qType); return -1; } if (cbdata->numfound > 1) { debugLog(0,__func__,"FAILED: The file specification matched multiple files.",0); return -1; } return 1; } /* Read/Write a buffer full of data from file descripter */ ssize_t rw_full(int fd, void *buf, size_t count) { ssize_t done=0; ssize_t len=0; while (count) { if (fd == STDIN_FILENO) { len = read(fd,buf+done,count); } else if (fd == STDOUT_FILENO) { len = write(fd,buf+done,count); } else { debugLog(0,__func__,"ERROR: Unknown FD",4); } if (len == 0) { break; } else if (len < 0) { if (errno == EINTR) { continue; } else { if (done == 0) done = -1; break; } } count -= len; done += len; } return done; } /* Register a filespace in TSM */ int tsm_regfs(dsUint32_t dsmHandle, char *fsname) { dsInt16_t rc=0; regFSData regFS; memset(®FS, 0, sizeof(regFS)); regFS.fsName = fsname; regFS.fsType = "TSMPIPE"; rc = dsmRegisterFS(dsmHandle,®FS); if (rc != DSM_RC_OK && rc != DSM_RC_FS_ALREADY_REGED) { printf("%s: dsmRegisterFS() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } return 1; } /* Send data to TSM for storage */ #ifdef USE_DIGEST double tsm_sendfile(dsUint32_t dsmHandle, char *fsname, char *filename, long long length, char *description, dsmSendType sendtype, dsBool_t startstop, dsBool_t summary, char *digest) { #else double tsm_sendfile(dsUint32_t dsmHandle, char *fsname, char *filename, long long length, char *description, dsmSendType sendtype, dsBool_t startstop, dsBool_t summary) { #endif extern int verbose; char *buffer; dsInt16_t rc=0; dsmObjName objName; mcBindKey mcBindKey; ObjAttr objAttr; DataBlk dataBlk; sndArchiveData archData, *archDataP=NULL; ssize_t nbytes; dsmEndSendObjExIn_t dsmEndSendObjExIn; dsmEndSendObjExOut_t dsmEndSendObjExOut; dsUint16_t reason=0; buffer = malloc(BUFLEN); if (buffer==NULL) { perror("tsm_sendfile: Argh, out of memory?"); exit(255); } #ifdef USE_DIGEST char digest_str[EVP_MAX_MD_SIZE*2]; EVP_MD_CTX *mdctx; const EVP_MD *md=NULL; unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len, i; mdctx = NULL; if (digest) { OpenSSL_add_all_digests(); md = EVP_get_digestbyname(digest); if (! md) { printf("%s: Unknown message digest %s\n",__func__,digest); return 0; } } #endif // Register our filespace if (! tsm_regfs(dsmHandle,fsname)) exit(3); // Warn if we wont do compression if (verbose && compressEnabled && length <= DSM_MIN_COMPRESS_SIZE) fprintf(stderr,"%s: WARNING: Size (%i) too small for compression/de-duplication, even though it is enabled",__func__,(int)length); // Log start backup if (startstop) tsm_datefs(dsmHandle,fsname,DSM_FSUPD_BACKSTARTDATE); // Start a Transaction rc = dsmBeginTxn(dsmHandle); if (rc != DSM_RC_OK) { printf("%s: dsmBeginTxn() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } memset(&objName,0x00,sizeof(objName)); objName = dsmNameToObjname(fsname,filename); if (verbose) fprintf(stderr,"%s: Starting to send stdin as %s\n",__func__,dsmObjnameToStr(objName)); memset(&mcBindKey,0x00,sizeof(mcBindKey)); mcBindKey.stVersion = mcBindKeyVersion; rc = dsmBindMC(dsmHandle,&objName,sendtype,&mcBindKey); if (rc != DSM_RC_OK) { printf("%s: dsmBindMC() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } if (verbose > 1) { char *cgdest=NULL; fprintf(stderr,"%s: Bound to Management Class: %s\n",__func__,mcBindKey.mcName); if ((sendtype == stArchiveMountWait || sendtype == stArchive) && mcBindKey.archive_cg_exists) { cgdest = mcBindKey.archive_copy_dest; } else if ((sendtype == stBackupMountWait || sendtype == stBackup) && mcBindKey.backup_cg_exists) { cgdest = mcBindKey.backup_copy_dest; } else { fprintf(stderr,"%s: UNKNOWN Type %d\n",__func__,sendtype); return -1; } if (cgdest) fprintf(stderr,"%s: Destination Copy Group: %s\n",__func__,cgdest); } memset(&objAttr,0x00,sizeof(ObjAttr)); objAttr.stVersion = ObjAttrVersion; *objAttr.owner = '\0'; objAttr.sizeEstimate.hi = length >> 32; objAttr.sizeEstimate.lo = length & ~0U; objAttr.objCompressed = bFalse; // @todo Could we use the objinfo field? if (sendtype == stArchiveMountWait || sendtype == stArchive) { memset(&archData,0x00,sizeof(sndArchiveData)); archData.stVersion = sndArchiveDataVersion; archData.descr = description; archDataP = &archData; } rc = dsmSendObj(dsmHandle,sendtype,archDataP,&objName,&objAttr,NULL); if (rc != DSM_RC_OK) { printf("%s: dsmSendObj() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return(0); } #ifdef USE_DIGEST if (digest) { mdctx = EVP_MD_CTX_new(); EVP_DigestInit_ex(mdctx, md, NULL); } #endif memset(&dataBlk,0x00,sizeof(DataBlk)); dataBlk.stVersion = DataBlkVersion; while(1) { nbytes = rw_full(STDIN_FILENO,buffer,BUFLEN); if (nbytes < 0) { perror("tsm_sendmail: read"); return 0; } else if (nbytes == 0) { break; } #ifdef USE_DIGEST if (digest) EVP_DigestUpdate(mdctx, buffer, nbytes); #endif dataBlk.bufferLen = nbytes; dataBlk.numBytes = 0; dataBlk.bufferPtr = buffer; rc = dsmSendData(dsmHandle,&dataBlk); if (rc != DSM_RC_OK && rc != DSM_RC_COMPRESS_GREW) { printf("%s: dsmSendData() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } } memset(&dsmEndSendObjExIn,0x00,sizeof(dsmEndSendObjExIn_t)); memset(&dsmEndSendObjExOut,0x00,sizeof(dsmEndSendObjExOut_t)); dsmEndSendObjExIn.stVersion = dsmEndSendObjExInVersion; dsmEndSendObjExIn.dsmHandle = dsmHandle; dsmEndSendObjExOut.stVersion = dsmEndSendObjExOutVersion; if ((rc = dsmEndSendObjEx(&dsmEndSendObjExIn,&dsmEndSendObjExOut)) != DSM_RC_OK) { printf("%s: dsmEndSendObjEx() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } rc = dsmEndTxn(dsmHandle,DSM_VOTE_COMMIT,&reason); if (rc == DSM_RC_CHECK_REASON_CODE || (rc == DSM_RC_OK && reason != DSM_RC_OK)) { printf("%s: dsmEndTxn() failed %s\n",__func__,tsm_printerr(dsmHandle,reason)); return 0; } else if(rc != DSM_RC_OK) { printf("%s: dsmEndTxn() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } #ifdef USE_DIGEST if (digest) { EVP_DigestFinal_ex(mdctx, md_value, &md_len); EVP_MD_CTX_free(mdctx); for(i=0; ifs); strcpy(objName.hl,qbData.objName->hl); strcpy(objName.ll,qbData.objName->ll); objName.objType = DSM_OBJ_FILE; delInfo.backInfo.stVersion = delBackVersion; delInfo.backInfo.objNameP = &objName; delInfo.backInfo.copyGroup = cbdata.copyGroup; /** Our purge function uses qtReserved8 - this will break in a future release of the API **/ } else if (qType == qtReserved8) { if (verbose) fprintf(stderr,"%s: Purging backup file %s with id [%u-%u]\n",__func__,dsmObjnameToStr(*qbData.objName),cbdata.objId.hi,cbdata.objId.lo); dType = dtBackupID; delInfo.backIDInfo.stVersion = delBackIDVersion; delInfo.backIDInfo.objId = cbdata.objId; } else { fprintf(stderr,"%s: UNKNOWN Type %d\n",__func__,qType); return -1; } rc = dsmBeginTxn(dsmHandle); if (rc != DSM_RC_OK) { printf("%s: dsmBeginTxn() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } rc = dsmDeleteObj(dsmHandle,dType,delInfo); if (rc != DSM_RC_OK) { printf("%s: dsmDeleteObj() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } rc = dsmEndTxn(dsmHandle,DSM_VOTE_COMMIT,&reason); if (rc == DSM_RC_CHECK_REASON_CODE || (rc == DSM_RC_OK && reason != DSM_RC_OK)) { printf("%s: dsmEndTxn() failed %s\n",__func__,tsm_printerr(dsmHandle,reason)); return 0; } else if (rc != DSM_RC_OK) { printf("%s: dsmEndTxn() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } return 1; } /* Update the FS capacity and utilsation */ int tsm_updatefs(dsUint32_t dsmHandle, char *fsname, long long size) { dsInt16_t rc=0; dsmFSUpd fsUpdateP; memset(&fsUpdateP,0x00,sizeof(dsmFSUpd)); fsUpdateP.occupancy.hi = size >> 32; fsUpdateP.occupancy.lo = size & ~0U; fsUpdateP.capacity = fsUpdateP.occupancy; rc = dsmUpdateFS(dsmHandle,fsname,&fsUpdateP,DSM_FSUPD_OCCUPANCY | DSM_FSUPD_CAPACITY); if (rc != DSM_RC_OK) { printf("%s: dsmUpdateFS() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } return 1; } int tsm_datefs(dsUint32_t dsmHandle, char *fsname, int startstop) { dsInt16_t rc=0; dsmFSUpd fsUpdateP; memset(&fsUpdateP,0x00,sizeof(dsmFSUpd)); rc = dsmUpdateFS(dsmHandle,fsname,&fsUpdateP,startstop); if (rc != DSM_RC_OK) { printf("%s: dsmUpdateFS() failed %s\n",__func__,tsm_printerr(dsmHandle,rc)); return 0; } return 1; }