/* * 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) { struct matchone_cb_data *cbdata = userdata; 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,"tsm_matchone_cb: Internal error: Unknown qType %d\n",qType); return -1; } if (cbdata->numfound > 1) { fprintf(stderr,"tsm_matchone_cb: FAILED: The file specification matched multiple files.\n"); 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; while (count) { ssize_t len; if (fd == STDIN_FILENO) { len = read(fd,buf+done,count); } else if (fd == STDOUT_FILENO) { len = write(fd,buf+done,count); } else { fprintf(stderr,"rw_full: rw_full: Unknown FD\n"); exit(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) { tsm_printerr(dsmHandle,rc,"tsm_regfs: dsmRegisterFS failed"); 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; if (digest) { OpenSSL_add_all_digests(); md = EVP_get_digestbyname(digest); if (! md) { printf("tsm_sendfile: Unknown message digest %s\n", 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,"tsm_sendfile: WARNING: Size (%i) too small for compression/de-duplication, even though it is enabled",(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) { tsm_printerr(dsmHandle,rc,"tsm_sendfile: dsmBeginTxn failed"); return 0; } memset(&objName,0x00,sizeof(objName)); objName = dsmNameToObjname(fsname,filename); if (verbose) fprintf(stderr,"tsm_sendfile: Starting to send stdin as %s\n",dsmObjnameToStr(objName)); memset(&mcBindKey,0x00,sizeof(mcBindKey)); mcBindKey.stVersion = mcBindKeyVersion; rc = dsmBindMC(dsmHandle,&objName,sendtype,&mcBindKey); if (rc != DSM_RC_OK) { tsm_printerr(dsmHandle,rc,"tsm_sendfile: dsmBindMC failed"); return 0; } if (verbose > 1) { char *cgdest=NULL; fprintf(stderr,"tsm_sendfile: Bound to Management Class: %s\n",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,"tsm_sendfile: Internal error: Unknown qType %d\n",sendtype); return -1; } if (cgdest) fprintf(stderr,"tsm_sendfile: Destination Copy Group: %s\n",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) { tsm_printerr(dsmHandle,rc,"tsm_sendfile: dsmSendObj failed"); return(0); } #ifdef USE_DIGEST if (digest) { EVP_MD_CTX_init(&mdctx); 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) { tsm_printerr(dsmHandle,rc,"tsm_sendfile: dsmSendData failed"); 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) { tsm_printerr(dsmHandle,rc,"tsm_sendfile: dsmEndSendObjEx failed"); return 0; } rc = dsmEndTxn(dsmHandle,DSM_VOTE_COMMIT,&reason); if (rc == DSM_RC_CHECK_REASON_CODE || (rc == DSM_RC_OK && reason != DSM_RC_OK)) { tsm_printerr(dsmHandle,reason,"tsm_sendfile: dsmEndTxn failed, reason"); return 0; } else if(rc != DSM_RC_OK) { tsm_printerr(dsmHandle,rc,"tsm_sendfile: dsmEndTxn failed"); return 0; } #ifdef USE_DIGEST if (digest) { EVP_DigestFinal_ex(&mdctx, md_value, &md_len); EVP_MD_CTX_cleanup(&mdctx); for(i=0; i> 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) { tsm_printerr(dsmHandle,rc,"tsm_updatefs: dsmUpdateFS failed"); 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) { tsm_printerr(dsmHandle,rc,"tsm_datefs: dsmUpdateFS failed"); return 0; } return 1; }