This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
tsmpipe/lib/dsmsendrecv.c

503 lines
13 KiB
C

/*
* The recommended buffer size is n*TCPBUFFLEN - 4 bytes.
* To get your buffer size, do: dsmc query options|grep TCPBUF
* 32kB seems to be the new default, 31kB was the old.
*
* An additional factor is the pipe buffer size. Since we don't do threading
* (yet), we hide a little bit of latency if we don't read more than the pipe
* buffer can hold at a time. On Linux 2.6 this is 64kB.
*
* So, I would recommend a BUFLEN of 64kB if your TCPBUFLEN is above the
* 64kB + 4 bytes limit or if your TCPBUFLEN is lower, the
* n*TCPBUFFLEN - 4 bytes that gets you closest to 64kB.
*
* For a default tuned TSM client on Linux, BUFLEN should thus be 64*1024-4.
*/
#define BUFLEN (64*1024-4)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "dsmrc.h"
#include "dsmapitd.h"
#include "dsmapifp.h"
#include "../tsmpipe.h"
#ifdef USE_DIGEST
#include <openssl/evp.h>
#endif
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(&regFS, 0, sizeof(regFS));
regFS.fsName = fsname;
regFS.fsType = "TSMPIPE";
rc = dsmRegisterFS(dsmHandle,&regFS);
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
int tsm_sendfile(dsUint32_t dsmHandle, char *fsname, char *filename, long long length, char *description, dsmSendType sendtype, char *digest) {
#else
int tsm_sendfile(dsUint32_t dsmHandle, char *fsname, char *filename, long long length, char *description, dsmSendType sendtype) {
#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
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);
// 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;
}
if (verbose) {
printf("Total bytes sent: %5.3f\n",dsmSizeToNum(dsmEndSendObjExOut.totalBytesSent));
if (dsmEndSendObjExOut.objDeduplicated)
printf("Deduplicated size: %5.3f\n",dsmSizeToNum(dsmEndSendObjExOut.totalDedupSize));
if (dsmEndSendObjExOut.objCompressed)
printf("Compressed size: %5.3f\n",dsmSizeToNum(dsmEndSendObjExOut.totalCompressSize));
if (dsmSizeToNum(dsmEndSendObjExOut.totalLFBytesSent))
printf("LAN-free bytes sentsize: %5.3f\n",dsmSizeToNum(dsmEndSendObjExOut.totalLFBytesSent));
if (dsmEndSendObjExOut.encryptionType) {
printf("Encryption: %s\n",dsmEndSendObjExOut.encryptionType & DSM_ENCRYPT_CLIENTENCRKEY ? "CLIENTENCRKEY" : dsmEndSendObjExOut.encryptionType & DSM_ENCRYPT_USER ? "USER" : "NO");
printf("Encryption Strength: %s\n",dsmEndSendObjExOut.encryptionType & DSM_ENCRYPT_AES_128BIT ? "AES_128BIT" : dsmEndSendObjExOut.encryptionType & DSM_ENCRYPT_DES_56BIT ? "DES_56BIT" : "NONE");
}
}
#ifdef USE_DIGEST
if (digest) {
EVP_DigestFinal_ex(&mdctx, md_value, &md_len);
EVP_MD_CTX_cleanup(&mdctx);
fprintf(stderr,"%s: ",digest);
for(i=0; i<md_len; i++) fprintf(stderr,"%02x",md_value[i]);
fprintf(stderr,"\n");
}
#endif
return 1;
}
/* Get data from TSM for restore */
int tsm_restorefile(dsUint32_t dsmHandle, dsmQueryType qType, qryArchiveData qaData, qryBackupData qbData) {
extern int verbose;
dsInt16_t rc=0;
struct matchone_cb_data cbdata;
dsmGetList getList;
DataBlk dataBlk;
dsmGetType gType;
memset(&cbdata,0x00,sizeof(cbdata));
cbdata.numfound = 0;
if (qType == qtArchive) {
if (verbose)
fprintf(stderr,"tsm_restorefile: Starting to receive %s via stdin\n",dsmObjnameToStr(*qaData.objName));
gType = gtArchive;
rc = tsm_queryfile(dsmHandle,qType,tsm_matchone_cb,&cbdata,qaData,qbData);
} else if (qType == qtBackup) {
if (verbose)
fprintf(stderr,"tsm_restorefile: Starting to receive %s via stdin\n",dsmObjnameToStr(*qbData.objName));
gType = gtBackup;
rc = tsm_queryfile(dsmHandle,qType,tsm_matchone_cb,&cbdata,qaData,qbData);
} else {
fprintf(stderr,"tsm_restorefile: Internal error: Unknown qType %d\n",qType);
return -1;
}
if (rc != DSM_RC_OK)
return 0;
if (cbdata.numfound == 0) {
fprintf(stderr,"tsm_restorefile: FAILED: The file specification did not match any file.\n");
return 0;
}
memset(&getList,0x00,sizeof(dsmGetList));
getList.stVersion = dsmGetListVersion;
getList.numObjId = 1;
getList.objId = &cbdata.objId;
getList.partialObjData = NULL;
rc = dsmBeginGetData(dsmHandle,bTrue,gType,&getList);
if (rc != DSM_RC_OK) {
tsm_printerr(dsmHandle,rc,"tsm_restorefile: dsmBeginGetData failed");
return 0;
}
memset(&dataBlk,0x00,sizeof(DataBlk));
dataBlk.stVersion = DataBlkVersion;
dataBlk.bufferPtr = malloc(BUFLEN);
if (!dataBlk.bufferPtr) {
perror("tsm_restorefile: malloc");
return 0;
}
dataBlk.bufferLen = BUFLEN;
dataBlk.numBytes = 0;
rc = dsmGetObj(dsmHandle,&cbdata.objId,&dataBlk);
while (rc == DSM_RC_MORE_DATA) {
if (rw_full(STDOUT_FILENO,dataBlk.bufferPtr,dataBlk.numBytes) < 0) {
perror("tsm_restorefile: write");
return 0;
}
dataBlk.numBytes = 0;
rc = dsmGetData(dsmHandle,&dataBlk);
}
if (rc != DSM_RC_FINISHED) {
tsm_printerr(dsmHandle,rc,"tsm_restorefile: dsmGetObj/dsmGetData failed");
return 0;
}
if (rw_full(STDOUT_FILENO,dataBlk.bufferPtr,dataBlk.numBytes) < 0) {
perror("tsm_restorefile: write");
return 0;
}
rc = dsmEndGetObj(dsmHandle);
if (rc != DSM_RC_OK) {
tsm_printerr(dsmHandle,rc,"tsm_restorefile: dsmEndGetObj failed");
return 0;
}
rc = dsmEndGetData(dsmHandle);
if (rc != DSM_RC_OK) {
tsm_printerr(dsmHandle,rc,"tsm_restorefile: dsmEndGetData failed");
return 0;
}
return 1;
}
/* Delete data in TSM */
int tsm_deletefile(dsUint32_t dsmHandle, dsmQueryType qType, qryArchiveData qaData, qryBackupData qbData) {
extern int verbose;
dsInt16_t rc=0;
dsUint16_t reason=0;
dsmDelInfo *dInfoP;
dsmDelType dType;
struct matchone_cb_data cbdata;
cbdata.numfound = 0;
rc = tsm_queryfile(dsmHandle,qType,tsm_matchone_cb,&cbdata,qaData,qbData);
if (rc != DSM_RC_OK) {
return 0;
}
if (cbdata.numfound == 0) {
fprintf(stderr,"tsm_deletefile: FAILED: The file specification did not match any file.\n");
return 0;
}
if (qType == qtArchive) {
if (verbose)
fprintf(stderr,"tsm_deletefile: Deleting archive file %s\n",dsmObjnameToStr(*qaData.objName));
dType = dtArchive;
delArch daInfo;
daInfo.stVersion = delArchVersion;
daInfo.objId = cbdata.objId;
dInfoP = (dsmDelInfo *) &daInfo;
} else if (qType == qtBackup) {
if (verbose)
fprintf(stderr,"tsm_deletefile: Deleting backup file %s\n",dsmObjnameToStr(*qbData.objName));
dType = dtBackup;
delBack dbInfo;
dbInfo.stVersion = delBackVersion;
dbInfo.objNameP = qbData.objName;
dbInfo.copyGroup = cbdata.copyGroup;
dInfoP = (dsmDelInfo *) &dbInfo;
} else {
fprintf(stderr,"tsm_matchone_cb: Internal error: Unknown qType %d\n",qType);
return -1;
}
rc = dsmBeginTxn(dsmHandle);
if (rc != DSM_RC_OK) {
tsm_printerr(dsmHandle,rc,"tsm_deletefile: dsmBeginTxn failed");
return 0;
}
rc = dsmDeleteObj(dsmHandle,dType,*dInfoP);
if (rc != DSM_RC_OK) {
tsm_printerr(dsmHandle,rc,"tsm_deletefile: dsmDeleteObj 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_deletefile: dsmEndTxn failed, reason");
return 0;
} else if (rc != DSM_RC_OK) {
tsm_printerr(dsmHandle,rc,"tsm_deletefile: dsmEndTxn failed");
return 0;
}
return 1;
}