diff --git a/Makefile.linux64 b/Makefile.linux64 index ee6e1bb..3202697 100644 --- a/Makefile.linux64 +++ b/Makefile.linux64 @@ -4,13 +4,26 @@ CC=gcc CFLAGS=-g -W -Wall -Wextra -O -I$(TSMAPIDIR) LDFLAGS= -FILES=tsmpipe.c - - all: tsmpipe -tsmpipe: $(FILES:.c=.o) - $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(FILES:.c=.o) $(TSMLIB) -lm +tsmpipe: tsmpipe.o lib/dsmobjects.o lib/dsmsession.o lib/dsmlist.o lib/dsmsendrecv.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $+ $(TSMLIB) -lm + +tsmpipe.c: + echo 'hello' + $(CC) $(CFLAGS) -c -o $(@:.c=.o) $@ $(TSMLIB) + +lib/dsmlist: + $(CC) $(CFLAGS) -c -o lib/$@.o lib/$@.c $(TSMLIB) + +lib/dsmsendrecv: + $(CC) $(CFLAGS) -c -o lib/$@.o lib/$@.c $(TSMLIB) + +lib/dsmsession: + $(CC) $(CFLAGS) -c -o lib/$@.o lib/$@.c $(TSMLIB) + +lib/dsmobjects: + $(CC) $(CFLAGS) -c -o lib/$@.o lib/$@.c $(TSMLIB) clean: - rm tsmpipe *.o + rm tsmpipe *.o lib/*.o diff --git a/lib/dsmlist.c b/lib/dsmlist.c new file mode 100644 index 0000000..97a1fcc --- /dev/null +++ b/lib/dsmlist.c @@ -0,0 +1,114 @@ +/* + * This function will list the contents that we have stored with tsmpipe + */ + +#include +#include +#include + +#include "dsmrc.h" +#include "dsmapitd.h" +#include "../tsmpipe.h" + +dsBool_t headerPrinted=bFalse; // Have we rendered the heading row yet + +extern char *dsmDateToStr(dsmDate date); +extern char *dsmObjnameToStr(dsmObjName objName); +extern double dsmSizeToNum(dsStruct64_t dsStruct64); +extern dsmObjName dsmNameToObjname(char *fsname, char *filename, int verbose); +extern dsInt16_t tsm_queryfile(dsUint32_t sesshandle, dsmObjName *objName, char *description, dsmSendType sendtype, char verbose, tsm_query_callback usercb, void * userdata, char *pitdate, int querytype); + +/* + * Our Callback to show what is in TSM + */ +int tsm_listfile_cb(dsmQueryType qType, DataBlk *qResp, void *userdata) { + char stor[1]="?"; + char state[2]="??"; + char ced[3]="---"; + + qryRespBackupData respBackup; + qryRespArchiveData respArchive; + + if (userdata != NULL ) { + fprintf(stderr, "tsm_listfile_cb: Internal error: userdate != NULL"); + return -1; + } + + if (! headerPrinted++) + printf("%40s %2s %s %3s %19s %10s %s\n", + "NAME", + "ST", + "L", + "CED", + "BACKUP", + "EST SIZE", + "ID" + ); + + if (qType == qtArchive) { + memset(&respArchive,0x00,sizeof(qryRespArchiveData)); + qryRespArchiveData *qr = (void *) qResp->bufferPtr; + respArchive = *qr; + + + } else if (qType ==qtBackup) { + memset(&respBackup,0x00,sizeof(qryRespBackupData)); + qryRespBackupData *qr = (void *) qResp->bufferPtr; + respBackup = *qr; + + // The Object Status + switch (respBackup.objName.objType) { + case (DSM_OBJ_FILE) : strcpy(state,"F"); break; + case (DSM_OBJ_DIRECTORY) : strcpy(state,"D"); break; + default : strcpy(state,"?"); + } + + switch (respBackup.objState) { + case (DSM_ACTIVE) : strcat(state,"A"); break; + case (DSM_INACTIVE) : strcat(state,"I"); break; + default : strcat(state,"?"); + } + + // Location + switch (respBackup.mediaClass) { + case (MEDIA_FIXED) : strcpy(stor,"D"); break; + case (MEDIA_LIBRARY) : strcpy(stor,"T"); break; + default : strcpy(stor,"?"); + } + + // Compression, Encryption, De-Duplication + strcpy(ced,(respBackup.compressType == DSM_OBJ_COMPRESSED_YES ? "C" : + (respBackup.compressType == DSM_OBJ_COMPRESSED_NO ? "-" : "?"))); + + strcat(ced,(respBackup.encryptionType & DSM_ENCRYPT_CLIENTENCRKEY ? "C" : + (respBackup.encryptionType & DSM_ENCRYPT_USER ? "U" : "-"))); + + strcat(ced,respBackup.clientDeduplicated ? "D" : "-"); + + } else { + fprintf(stderr,"tsm_listfile_cb: Internal error: Unknown qType %d\n",qType); + + return -1; + } + + printf("%40s|%2s|%s|%3s|%19s|%7.3f MB|%u-%u\n",dsmObjnameToStr(respBackup.objName),state,stor,ced,dsmDateToStr(respBackup.insDate),dsmSizeToNum(respBackup.sizeEstimate),respBackup.objId.hi,respBackup.objId.lo); + + return 1; +} + +/* + * List objects that are in TSM + */ +int tsm_listfile(dsUint32_t sesshandle, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose, char *pitdate) { + dsInt16_t rc=0; + dsmObjName objName; + + objName = dsmNameToObjname(fsname,filename,verbose); + + rc = tsm_queryfile(sesshandle, &objName, description, sendtype, verbose, tsm_listfile_cb, NULL, pitdate, DSM_ANY_MATCH); + + if (rc != DSM_RC_OK && rc != DSM_RC_ABORT_NO_MATCH) + return 0; + + return 1; +} diff --git a/lib/dsmobjects.c b/lib/dsmobjects.c new file mode 100644 index 0000000..fb94379 --- /dev/null +++ b/lib/dsmobjects.c @@ -0,0 +1,143 @@ +/* + * Date manipulations functions for tsmpipe + */ + +#include +#include +#include + +#include "dsmapitd.h" + +/* + * This function will take a string date entered and convert that to a TSM + * date + * + * The date is passed to this function in the format mmddYYYY + */ +dsmDate dsmStrToDate(char *s,int verbose) { + dsmDate *date; + dsUint32_t x; + + date = (dsmDate*)malloc(sizeof(dsmDate)); + + if (date==NULL) { + perror("Arg, out of memory?"); + exit(255); + } + + memset(date,0x00,sizeof(dsmDate)); + + if (verbose) + printf("dsmStrToDate: Date String: %s\n", s); + + /* if user key in some inputs */ + if (s[0] != '\0') { + x = atol(s); + date->month = x / 1000000; + + x %= 1000000; + date->day = x / 10000; + date->year = x % 10000; + } + + if (verbose) + printf("dsmStrToDate: date = %d, month = %d, year = %d\n", date->day, date->month, date->year); + + return *date; +} + +/* Display the dsmDate value as a string */ +char *dsmDateToStr(dsmDate date) { + char *s; + + s = malloc(19); + + if (s==NULL) { + perror("Arg, out of memory?"); + exit(255); + } + + memset(s,0x00,sizeof(s)); + + sprintf(s,"%02i/%02i/%04i %02i:%02i:%02i", + (dsInt16_t)date.day, + (dsInt16_t)date.month, + date.year, + (dsInt16_t)date.hour, + (dsInt16_t)date.minute, + (dsInt16_t)date.second); + + return s; +} + +dsmObjName dsmNameToObjname(char *fsname, char *filename, int verbose) { + dsmObjName *objname; + char *p; + + objname = (dsmObjName*)malloc(sizeof(dsmObjName)); + + if (objname==NULL) { + perror("Arg, out of memory?"); + exit(255); + } + + memset(objname,0x00,sizeof(dsmObjName)); + + if (verbose) + fprintf(stderr,"dsmNameToObjname: FS: %s Filename: %s\n",fsname,filename); + + /* fs == "/filesystem", hl == "/directory/path", ll == "/filename" */ + strcpy(objname->fs,fsname); + + p = strrchr(filename, '/'); + + if (p) { + *p = '\0'; + + if (*filename && *filename != '/') + strcpy(objname->hl, "/"); + + strcpy(objname->hl,filename); + sprintf(objname->ll,"/%s",p+1); + + } else { + if (*filename && *filename != '/') + strcpy(objname->ll, "/"); + + strcat(objname->ll,filename); + } + + objname->objType = DSM_OBJ_FILE; + + return *objname; +} + +char *dsmObjnameToStr(dsmObjName objName) { + char *s; + + s = malloc(sizeof(dsmObjName)); + + if (s==NULL) { + perror("Arg, out of memory?"); + exit(255); + } + + memset(s,0x00,sizeof(s)); + + sprintf(s,"%s%s%s",objName.fs,objName.hl,objName.ll); + + return s; +} + +double dsmSizeToNum(dsStruct64_t dsStruct64) { + unsigned long long filesize=0; + + filesize = 0x00; + + filesize = dsStruct64.hi; + filesize <<= 32; + filesize |= dsStruct64.lo; + + // Return number in MB + return (float)filesize/1024/1024; +} diff --git a/lib/dsmsendrecv.c b/lib/dsmsendrecv.c new file mode 100644 index 0000000..9cdcbd4 --- /dev/null +++ b/lib/dsmsendrecv.c @@ -0,0 +1,445 @@ +/* + * 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 +#include +#include +#include +#include + +#include "dsmrc.h" +#include "dsmapitd.h" +#include "dsmapifp.h" + +#include "../tsmpipe.h" + +extern dsBool_t compressEnabled; + +extern void tsm_printerr(dsUint32_t dsmHandle, dsInt16_t rc, char *str); +extern char *dsmObjnameToStr(dsmObjName objName); +extern double dsmSizeToNum(dsStruct64_t dsStruct64); +extern dsmObjName dsmNameToObjname(char *fsname, char *filename, int verbose); +extern dsInt16_t tsm_queryfile(dsUint32_t dsmHandle, dsmObjName *objName, char *description, dsmSendType sendtype, char verbose, tsm_query_callback usercb, void * userdata, char *pitdate, int querytype); + +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,"tsmpipe: 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 */ +int tsm_sendfile(dsUint32_t dsmHandle, char *fsname, char *filename, off_t length, char *description, dsmSendType sendtype, char 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); + } + + // 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,verbose); + + 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(mcBindKey.backup_cg_exists) { + cgdest = mcBindKey.backup_copy_dest; + } + + 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); + } + + memset(&dataBlk,0x00,sizeof(DataBlk)); + dataBlk.stVersion = DataBlkVersion; + + while(1) { + nbytes = rw_full(STDIN_FILENO,buffer,BUFLEN); + + if (nbytes < 0) { + perror("tsmpipe: read"); + return 0; + } else if (nbytes == 0) { + break; + } + + 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_senfile: 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"); + } + } + + return 1; +} + +/* Get data from TSM for restore */ +int tsm_restorefile(dsUint32_t dsmHandle, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose, char *pitdate) { + dsInt16_t rc=0; + struct matchone_cb_data cbdata; + dsmObjName objName; + dsmGetList getList; + dsmGetType getType; + DataBlk dataBlk; + + objName = dsmNameToObjname(fsname,filename,verbose); + + if (verbose) + fprintf(stderr,"tsm_restorefile: Starting to receive %s via stdin\n",dsmObjnameToStr(objName)); + + memset(&cbdata,0x00,sizeof(cbdata)); + cbdata.numfound = 0; + + // Retrieve a list based on the PITDATE or if no PITDATE, the last ACTIVE + rc = tsm_queryfile(dsmHandle,&objName,description,sendtype,verbose,tsm_matchone_cb,&cbdata,pitdate,pitdate ? DSM_ANY_MATCH : DSM_ACTIVE); + + 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; + + if (sendtype == stArchiveMountWait || sendtype == stArchive) { + getType = gtArchive; + } else { + getType = gtBackup; + } + + rc = dsmBeginGetData(dsmHandle,bTrue,getType,&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, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose) { + dsInt16_t rc=0; + dsUint16_t reason=0; + dsmDelInfo *dInfoP; + dsmDelType dType; + struct matchone_cb_data cbdata; + delArch daInfo; + delBack dbInfo; + dsmObjName objName; + + objName = dsmNameToObjname(fsname,filename,verbose); + + if (verbose) + fprintf(stderr,"tsm_deletefile: Deleting file %s\n",dsmObjnameToStr(objName)); + + cbdata.numfound = 0; + + rc = tsm_queryfile(dsmHandle,&objName,description,sendtype,verbose,tsm_matchone_cb,&cbdata,NULL,DSM_ACTIVE); + 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 (sendtype == stArchiveMountWait || sendtype == stArchive) { + dType = dtArchive; + + daInfo.stVersion = delArchVersion; + daInfo.objId = cbdata.objId; + + dInfoP = (dsmDelInfo *) &daInfo; + } else { + dType = dtBackup; + + dbInfo.stVersion = delBackVersion; + dbInfo.objNameP = &objName; + dbInfo.copyGroup = cbdata.copyGroup; + + dInfoP = (dsmDelInfo *) &dbInfo; + } + + 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; +} diff --git a/lib/dsmsession.c b/lib/dsmsession.c new file mode 100644 index 0000000..4f8327d --- /dev/null +++ b/lib/dsmsession.c @@ -0,0 +1,369 @@ +/* + * This function will set up a session to the TSM server and return the + * session handler + */ + +#include +#include +#include + +#include "dsmrc.h" +#include "dsmapitd.h" +#include "dsmapifp.h" + +#include "../tsmpipe.h" + +dsBool_t compressEnabled=bFalse; // Is compression enabled + +extern char *dsmDateToStr(dsmDate date); +extern dsmDate dsmStrToDate(char *s,int verbose); +extern char *dsmObjnameToStr(dsmObjName objName); + +/* Print out TSM Error Code */ +void tsm_printerr(dsUint32_t dsmHandle, dsInt16_t rc, char *str) { + char rcStr[DSM_MAX_RC_MSG_LENGTH]; + + if (rc == DSM_RC_WILL_ABORT) { + dsUint16_t reason; + + rc = dsmEndTxn(dsmHandle, DSM_VOTE_COMMIT, &reason); + + if (rc == DSM_RC_CHECK_REASON_CODE) + rc = reason; + } + + dsmRCMsg(dsmHandle,rc,rcStr); + + fprintf(stderr, "tsmpipe: %s\n (rc=%s)\n",str,rcStr); +} + +/* Check the TSM API Version */ +int tsm_checkapi(void) { + dsmApiVersionEx apiLibVer; + dsUint32_t apiVersion; + dsUint32_t applVersion = (10000 * DSM_API_VERSION) + (1000 * DSM_API_RELEASE) + (100 * DSM_API_LEVEL) + DSM_API_SUBLEVEL; + + memset(&apiLibVer,0x00,sizeof(dsmApiVersionEx)); + apiLibVer.stVersion = apiVersionExVer; + dsmQueryApiVersionEx(&apiLibVer); + + apiVersion = (10000 * apiLibVer.version) + (1000 * apiLibVer.release) + (100 * apiLibVer.level) + apiLibVer.subLevel; + + if (apiVersion < applVersion) { + printf("The Tivoli Storage Manager API library Version (%d.%d.%d.%d) is at a lower version than the application version (%d.%d.%d.%d)\n", + apiLibVer.version, + apiLibVer.release, + apiLibVer.level, + apiLibVer.subLevel, + DSM_API_VERSION, + DSM_API_RELEASE, + DSM_API_LEVEL, + DSM_API_SUBLEVEL); + + printf("Please upgrade the API accordingly.\n"); + + return 0; + } + + return 1; +} + +/* Initialise a session to the TSM server */ +dsUint32_t tsm_initsess(char *options) { + dsInt16_t rc=0; + dsUint32_t dsmHandle=0; + dsmApiVersionEx applApi; + dsmInitExIn_t initIn; + dsmInitExOut_t initOut; + optStruct dsmOpt; + ApiSessInfo dsmSessInfo; + + if (! tsm_checkapi()) { + exit(2); + } + + memset(&applApi,0x00,sizeof(dsmApiVersionEx)); + applApi.stVersion = apiVersionExVer; + applApi.version = DSM_API_VERSION; + applApi.release = DSM_API_RELEASE; + applApi.level = DSM_API_LEVEL; + applApi.subLevel = DSM_API_SUBLEVEL; + + memset(&initIn,0x00,sizeof(dsmInitExIn_t)); + initIn.stVersion = dsmInitExInVersion; + initIn.apiVersionExP = &applApi; + initIn.clientNodeNameP = NULL; + initIn.clientOwnerNameP = NULL; + initIn.clientPasswordP = NULL; + initIn.applicationTypeP = NULL; + initIn.configfile = NULL; + initIn.options = options; + initIn.userNameP = NULL; + initIn.userPasswordP = NULL; + //initIn.dirDelimiter = dirDelimiter; + //initIn.useUnicode = useUnicode; + //initIn.bEncryptKeyEnabled = encrypt; + //initIn.encryptionPasswordP = encryptKey; + + memset(&initOut,0x00,sizeof(dsmInitExOut_t)); + initOut.stVersion = dsmInitExOutVersion; + + rc = dsmInitEx(&dsmHandle, &initIn, &initOut); + + /* If the TSM password has expired, change it. */ + if (rc == DSM_RC_REJECT_VERIFIER_EXPIRED) { + rc = dsmChangePW(dsmHandle,NULL,NULL); + + if (rc != DSM_RC_OK) { + tsm_printerr(dsmHandle,rc,"dsmChangePW failed"); + + return 0; + } + + } else if (rc != DSM_RC_OK) { + tsm_printerr(dsmHandle, rc, "dsmInitEx failed"); + dsmTerminate(dsmHandle); + + return 0; + } + + // Make sure if we have compression enabled, that we also have COMPRESSAlways YES + memset(&dsmOpt,0x00,sizeof(dsmOpt)); + rc = dsmQuerySessOptions(dsmHandle, &dsmOpt); + + memset(&dsmSessInfo,0x00,sizeof(ApiSessInfo)); + dsmSessInfo.stVersion = ApiSessInfoVersion; /* Init struct version */ + rc = dsmQuerySessInfo(dsmHandle, &dsmSessInfo); + + rc = 1; + switch (dsmSessInfo.compression) { + case COMPRESS_YES : compressEnabled = bTrue; break; + case COMPRESS_NO : compressEnabled = bFalse; break; + case COMPRESS_CD : compressEnabled = dsmOpt.compression; break; + default : rc=0; + } + + if (!rc || (compressEnabled && ! dsmOpt.compressalways)) { + fprintf(stderr,!rc ? "Error Querying Session Capabilities" : "Error, COMPRESSion is ENABLED, but not COMPRESSAlways Yes\n"); + fprintf(stderr,"\n"); + exit(1); + } + + return dsmHandle; +} + +/* List objects that are in TSM */ +void tsm_sessioninfo(dsUint32_t dsmHandle) { + dsInt16_t rc=0; + optStruct dsmOpt; + ApiSessInfo dsmSessInfo; + char t[50]; + + memset(&dsmOpt,0x00,sizeof(dsmOpt)); + rc = dsmQuerySessOptions(dsmHandle, &dsmOpt); + + if (rc) + printf("dsmQuerySessOptions error on issueing Query Session Options. Rc = %d\n",rc); + else { + printf("dsmQuerySessOptions:\n"); + printf(" DSMI_DIR: %s\n",dsmOpt.dsmiDir); + printf(" DSMI_CONFIG: %s\n",dsmOpt.dsmiConfig); + printf(" SErvername: %s\n",dsmOpt.serverName); + printf(" COMMmethod: %d\n",dsmOpt.commMethod); + printf(" TCPServerAddress: %s\n",dsmOpt.serverAddress); + printf(" NODEName: %s\n",dsmOpt.nodeName); + printf(" COMPRESSIon: %d\n",dsmOpt.compression); + printf(" COMPRESSAlways: %d\n",dsmOpt.compressalways); + printf(" PASSWORDAccess: %d\n",dsmOpt.passwordAccess); + } + + memset(&dsmSessInfo,0x00,sizeof(ApiSessInfo)); + dsmSessInfo.stVersion = ApiSessInfoVersion; /* Init struct version */ + rc = dsmQuerySessInfo(dsmHandle, &dsmSessInfo); + + if (rc) + printf("dsmQuerySessOptions error on issueing Query Session Options. Rc = %d\n",rc); + else { + printf("\n"); + printf("dsmQuerySessInfo:\n"); + printf(" Server Information:\n"); + printf(" Name: %s\n",dsmSessInfo.adsmServerName); + printf(" Host: %s\n",dsmSessInfo.serverHost); + printf(" Port: %u\n",dsmSessInfo.serverPort); + printf(" Date: %s\n",dsmDateToStr(dsmSessInfo.serverDate)); + printf(" Type: %s\n",dsmSessInfo.serverType); + printf(" Version: %i.%i.%i.%i\n", + dsmSessInfo.serverVer, + dsmSessInfo.serverRel, + dsmSessInfo.serverLev, + dsmSessInfo.serverSubLev); + printf(" Archive Retention Protection : %s\n",dsmSessInfo.archiveRetentionProtection ? "YES" : "NO"); + printf("\n"); + printf(" Client Information:\n"); + printf(" Node: %s\n",dsmSessInfo.id); + printf(" Node Type: %s\n",dsmSessInfo.nodeType); + printf(" Filespace delimiter: %c\n",dsmSessInfo.fsdelim); + printf(" HL & LL delimiter: %c\n",dsmSessInfo.hldelim); + + switch (dsmSessInfo.compression) { + case COMPRESS_YES : strcpy(t,"ON"); break; + case COMPRESS_NO : strcpy(t,"OFF"); break; + case COMPRESS_CD : strcpy(t,"CLIENT"); break; + default : strcpy(t,"UNKNOWN"); + } + printf(" Client compression: %s\n",t); + + switch (dsmSessInfo.archDel) { + case ARCHDEL_YES : strcpy(t,"YES"); break; + case ARCHDEL_NO : strcpy(t,"NO"); break; + default : strcpy(t,"UNKNOWN"); + } + printf(" ARCHIVE Delete: %s\n",t); + + switch (dsmSessInfo.backDel) { + case BACKDEL_YES : strcpy(t,"YES"); break; + case ARCHDEL_NO : strcpy(t,"NO"); break; + default : strcpy(t,"UNKNOWN"); + } + printf(" BACKUP delete: %s\n",t); + + printf(" MAX objects per transactions: %u\n", dsmSessInfo.maxObjPerTxn); + printf(" LAN FREE Enabled: %s\n",dsmSessInfo.lanFreeEnabled ? "YES" : "NO"); + printf(" Deduplication: %s\n",dsmSessInfo.dedupType == dedupClientOrServer ? "Client Or Server" : "Server Only"); + printf("\n"); + printf(" General session info:\n"); + printf(" Owner: %s\n",dsmSessInfo.owner); + printf(" API Config file: %s\n",dsmSessInfo.confFile); + printf("\n"); + printf(" Policy Information:\n"); + printf(" Domain name: %s\n",dsmSessInfo.domainName); + printf(" Policyset name: %s\n",dsmSessInfo.policySetName); + printf(" Policy activation date: %s\n",dsmDateToStr(dsmSessInfo.polActDate)); + printf(" Default management class: %s\n",dsmSessInfo.dfltMCName); + printf(" BACKUP retention grace: %u days\n",dsmSessInfo.gpBackRetn); + printf(" ARCHIVE retention grace: %u days\n",dsmSessInfo.gpArchRetn); + } +} + +/* + * Query TSM for a list of objects. + * + * We use a callback to process the list, the callback should return: + * -1 upon error condition, application should exit. + * 0 if tsm_queryfile() should skip processing the remaining matches. + * 1 otherwise. + */ +dsInt16_t tsm_queryfile(dsUint32_t dsmHandle, dsmObjName *objName, char *description, dsmSendType sendtype, char verbose, tsm_query_callback usercb, void * userdata, char *pitdate, int querytype) { + dsInt16_t rc=0; + DataBlk qResp; + dsmQueryType qType; + qryArchiveData qaData; + qryRespArchiveData qaResp; + qryBackupData qbData; + qryRespBackupData qbResp; + dsmQueryBuff *qDataP; + + if (verbose) + fprintf(stderr,"tsm_queryfile: Query filespace %s\n",dsmObjnameToStr(*objName)); + + memset(&qResp,0x00,sizeof(DataBlk)); + qResp.stVersion = DataBlkVersion; + + if (sendtype == stArchiveMountWait || sendtype == stArchive) { + qType = qtArchive; + + memset(&qaData,0x00,sizeof(qryArchiveData)); + qaData.stVersion = qryArchiveDataVersion; + qaData.objName = objName; + qaData.owner = ""; + qaData.insDateLowerBound.year = DATE_MINUS_INFINITE; + qaData.insDateUpperBound.year = DATE_PLUS_INFINITE; + qaData.expDateLowerBound.year = DATE_MINUS_INFINITE; + qaData.expDateUpperBound.year = DATE_PLUS_INFINITE; + qaData.descr = description ? description : "*"; + + qDataP = &qaData; + + qaResp.stVersion = qryRespArchiveDataVersion; + + qResp.bufferPtr = (char *) &qaResp; + qResp.bufferLen = sizeof(qaResp); + + } else { + qType = qtBackup; + + memset(&qbData,0x00,sizeof(qryBackupData)); + qbData.stVersion = qryBackupDataVersion; + qbData.objName = objName; + qbData.owner = ""; + qbData.objState = querytype; + + if (pitdate) { + qbData.pitDate = dsmStrToDate(pitdate,verbose); + } else { + qbData.pitDate.year = DATE_MINUS_INFINITE; + } + + qDataP = &qbData; + + qbResp.stVersion = qryRespBackupDataVersion; + + qResp.bufferPtr = (char *) &qbResp; + qResp.bufferLen = sizeof(qbResp); + } + + rc = dsmBeginQuery(dsmHandle, qType, qDataP); + if (rc != DSM_RC_OK) { + tsm_printerr(dsmHandle,rc,"tsm_queryfile: dsmBeginQuery failed"); + return rc; + } + + /* Loop and apply our callback to the result */ + while ((rc = dsmGetNextQObj(dsmHandle, &qResp)) == DSM_RC_MORE_DATA) { + int cbret; + + if(verbose > 1) { + dsmObjName *rObjName; + + if(qType == qtArchive) { + qryRespArchiveData *qr = (void *) qResp.bufferPtr; + rObjName = &(qr->objName); + + } else if(qType == qtBackup) { + qryRespBackupData *qr = (void *) qResp.bufferPtr; + rObjName = &(qr->objName); + + } else { + fprintf(stderr,"tsm_queryfile: Internal error: Unknown qType %d\n",qType); + + return DSM_RC_UNKNOWN_ERROR; + } + + fprintf(stderr,"tsm_queryfile: Match file %s\n",dsmObjnameToStr(*rObjName)); + } + + if (usercb == NULL) + continue; + + cbret = usercb(qType,&qResp,userdata); + if (cbret < 0) { + return DSM_RC_UNKNOWN_ERROR; + + } else if(cbret == 0) { + break; + } + } + + if (rc != DSM_RC_FINISHED && rc != DSM_RC_MORE_DATA) { + tsm_printerr(dsmHandle, rc, "tsm_queryfile: dsmGetNextObj failed"); + return rc; + } + + rc = dsmEndQuery(dsmHandle); + if (rc != DSM_RC_OK) { + tsm_printerr(dsmHandle,rc,"tsm_queryfile: dsmEndQuery failed"); + return rc; + } + + return DSM_RC_OK; +} diff --git a/tsmpipe.c b/tsmpipe.c index 1f2088f..469327b 100644 --- a/tsmpipe.c +++ b/tsmpipe.c @@ -1,6 +1,4 @@ /* - Copyright (c) 2006,2007 HPC2N, Umeå University, Sweden - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the @@ -17,9 +15,10 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. - Modifications Copyright(c) 2012-2013 by Deon George + Original Idea Copyright (c) 2006,2007 HPC2N, Umeå University, Sweden + Modifications Copyright (c) 2012-2013 by Deon George */ /* Enable Large File Support stuff */ @@ -31,7 +30,6 @@ SOFTWARE. #include #include #include -#include #include #include @@ -39,1177 +37,203 @@ SOFTWARE. #include "dsmapitd.h" #include "dsmapifp.h" -/* - * 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) - -static dsmDate xStringToDate (char *s); - -/* Convert a string number into a number */ -off_t atooff(const char *s) -{ - off_t o; - - if (sizeof(off_t) == 4) - sscanf(s,"%d",(int *) &o); - else if (sizeof(off_t) == 8) - sscanf(s,"%lld",(long long *) &o); - else { - fprintf(stderr, "tsmpipe: atooff: Internal error\n"); - exit(1); - } - - return o; -} - -/* 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, "tsmpipe: rw_full: Unknown FD\n"); - exit(1); - } - - 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); -} - -/* Check the TSM API Version */ -int tsm_checkapi(void) { - dsmApiVersionEx apiLibVer; - dsUint32_t apiVersion; - dsUint32_t applVersion = (10000 * DSM_API_VERSION) + (1000 * DSM_API_RELEASE) + (100 * DSM_API_LEVEL) + DSM_API_SUBLEVEL; - - memset(&apiLibVer, 0, sizeof(apiLibVer)); - apiLibVer.stVersion = apiVersionExVer; - dsmQueryApiVersionEx(&apiLibVer); - - apiVersion = (10000 * apiLibVer.version) + (1000 * apiLibVer.release) + - (100 * apiLibVer.level) + apiLibVer.subLevel; - - if (apiVersion < applVersion) { - printf("The Tivoli Storage Manager API library Version = %d.%d.%d.%d is at a lower version\n", - apiLibVer.version, - apiLibVer.release, - apiLibVer.level, - apiLibVer.subLevel); - printf("than the application version = %d.%d.%d.%d.\n", - DSM_API_VERSION, - DSM_API_RELEASE, - DSM_API_LEVEL, - DSM_API_SUBLEVEL); - printf("Please upgrade the API accordingly.\n"); - - return 0; - } - - return 1; -} - -/* Print out TSM Error Code */ -void tsm_printerr(dsUint32_t sesshandle, dsInt16_t rc, char *str) { - char rcStr[DSM_MAX_RC_MSG_LENGTH]; - - if (rc == DSM_RC_WILL_ABORT) { - dsUint16_t reason; - - rc = dsmEndTxn(sesshandle, DSM_VOTE_COMMIT, &reason); - if (rc == DSM_RC_CHECK_REASON_CODE) - rc = reason; - } - - dsmRCMsg(sesshandle, rc, rcStr); - fprintf(stderr, "tsmpipe: %s\n" - " rc=%s\n", str, rcStr); -} - -/* @TODO: Need to force compressalways if compression is on */ -dsUint32_t tsm_initsess(char *options) { - dsmApiVersionEx applApi; - dsUint32_t sesshandle = 0; - dsmInitExIn_t initIn; - dsmInitExOut_t initOut; - - dsInt16_t rc; - optStruct dsmOpt1; - ApiSessInfo dsmSessInfo; - char t[50]; - - memset(&applApi, 0, sizeof(applApi)); - applApi.version = DSM_API_VERSION; - applApi.release = DSM_API_RELEASE; - applApi.level = DSM_API_LEVEL ; - applApi.subLevel = DSM_API_SUBLEVEL; - - memset(&initIn, 0, sizeof(initIn)); - initIn.stVersion = dsmInitExInVersion; - initIn.apiVersionExP = &applApi; - initIn.clientNodeNameP = NULL; - initIn.clientOwnerNameP = NULL; - initIn.clientPasswordP = NULL; - initIn.applicationTypeP = NULL; - initIn.configfile = NULL; - initIn.options = options; - initIn.userNameP = NULL; - initIn.userPasswordP = NULL; - - memset(&initOut, 0, sizeof(initOut)); - - rc = dsmInitEx(&sesshandle, &initIn, &initOut); - /* If the TSM password has expired, change it. */ - if(rc == DSM_RC_REJECT_VERIFIER_EXPIRED) { - rc = dsmChangePW(sesshandle, NULL, NULL); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmChangePW failed"); - return 0; - } - - } else if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmInitEx failed"); - dsmTerminate(sesshandle); - return 0; - } - - memset(&dsmOpt1, 0, sizeof(dsmOpt1)); - rc = dsmQuerySessOptions(sesshandle, &dsmOpt1); - - if (rc) - printf("dsmQuerySessOptions error on issueing Query Session Options. Rc = %d\n",rc); - else { - printf("++dsmQuerySessOptions:\n"); - printf("DSMI_DIR >%s<\n", dsmOpt1.dsmiDir); - printf("DSMI_CONFIG >%s<\n", dsmOpt1.dsmiConfig); - printf("serverName >%s<\n", dsmOpt1.serverName); - printf("commMethod %d\n", dsmOpt1.commMethod); - printf("serverAddress >%s<\n", dsmOpt1.serverAddress); - printf("nodeName >%s<\n", dsmOpt1.nodeName); - printf("compress %d\n", dsmOpt1.compression); - printf("compressalways %d\n", dsmOpt1.compressalways); - printf("passwordAccess %d\n", dsmOpt1.passwordAccess); - } - - memset(&dsmSessInfo, 0x00, sizeof(ApiSessInfo)); - dsmSessInfo.stVersion = ApiSessInfoVersion; /* Init struct version */ - rc = dsmQuerySessInfo(sesshandle, &dsmSessInfo); - if (rc) - printf("dsmQuerySessOptions error on issueing Query Session Options. Rc = %d\n",rc); - else { - printf("\ndsmQuerySessInfo Values:\n"); - printf(" Server Information:\n"); - printf(" Server name: %s\n",dsmSessInfo.adsmServerName); - - printf(" Server Host: %s\n",dsmSessInfo.serverHost); - printf(" Server port: %u\n",dsmSessInfo.serverPort); - printf(" Server date: %i/%i/%i %i:%i:%i\n", - dsmSessInfo.serverDate.year, - (dsInt16_t)dsmSessInfo.serverDate.month, - (dsInt16_t)dsmSessInfo.serverDate.day, - (dsInt16_t)dsmSessInfo.serverDate.hour, - (dsInt16_t)dsmSessInfo.serverDate.minute, - (dsInt16_t)dsmSessInfo.serverDate.second); - printf(" Server type: %s\n",dsmSessInfo.serverType); - printf(" Server version: %i.%i.%i.%i\n", - dsmSessInfo.serverVer, - dsmSessInfo.serverRel, - dsmSessInfo.serverLev, - dsmSessInfo.serverSubLev); - printf(" Server Archive Retention Protection : %s (%i)\n",dsmSessInfo.archiveRetentionProtection ? "YES" : "NO",dsmSessInfo.archiveRetentionProtection); - printf(" Client Information:\n"); - printf(" Client node type: %s\n",dsmSessInfo.nodeType); - printf(" Client filespace delimiter: %c\n",dsmSessInfo.fsdelim); - printf(" Client hl & ll delimiter: %c\n",dsmSessInfo.hldelim); - - switch (dsmSessInfo.compression) - { - case COMPRESS_YES : - strcpy(t,"ON"); - break; - case COMPRESS_NO : - strcpy(t,"OFF"); - break; - case COMPRESS_CD : - strcpy(t,"Client determined"); - break; - default : - strcpy(t,"Unknown compress state."); - } - printf(" Client compression: %s (%i)\n",t,dsmSessInfo.compression); - - switch (dsmSessInfo.archDel) - { - case ARCHDEL_YES : - strcpy(t,"Client can delete archived objects"); - break; - case ARCHDEL_NO : - strcpy(t,"Client CANNOT delete archived objects"); - break; - default : - strcpy(t,"Unknown archive delete state"); - } - printf(" Client archive delete: %s\n",t); - - switch (dsmSessInfo.backDel) - { - case BACKDEL_YES : - strcpy(t,"Client can delete backup objects"); - break; - case ARCHDEL_NO : - strcpy(t,"Client CANNOT delete backup objects"); - break; - default : - strcpy(t,"Unknown backup delete state"); - } - printf(" Client backup delete: %s\n",t); - printf(" Maximum objects in multiple object transactions: %u\n", dsmSessInfo.maxObjPerTxn); - printf(" Lan free Enabled: %s(%i)\n",dsmSessInfo.lanFreeEnabled ? "YES" : "NO",dsmSessInfo.lanFreeEnabled); - printf(" Deduplication : %s(%i)\n",dsmSessInfo.dedupType == dedupClientOrServer ? "Client Or Server" : "Server Only",dsmSessInfo.dedupType); - printf(" General session info:\n"); - printf(" Node: %s\n",dsmSessInfo.id); - printf(" Owner: %s\n",dsmSessInfo.owner); - printf(" API Config file: %s\n",dsmSessInfo.confFile); - printf(" Policy Information:\n"); - printf(" Domain name: %s\n",dsmSessInfo.domainName); - printf(" Policyset name: %s\n",dsmSessInfo.policySetName); - printf(" Policy activation date: %i/%i/%i %i:%i:%i\n", - dsmSessInfo.polActDate.year, - (dsInt16_t)dsmSessInfo.polActDate.month, - (dsInt16_t)dsmSessInfo.polActDate.day, - (dsInt16_t)dsmSessInfo.polActDate.hour, - (dsInt16_t)dsmSessInfo.polActDate.minute, - (dsInt16_t)dsmSessInfo.polActDate.second); - printf(" Default management class: %s\n",dsmSessInfo.dfltMCName); - printf(" Backup retention grace period: %u days\n", dsmSessInfo.gpBackRetn); - printf(" Archive retention grace period: %u days\n", dsmSessInfo.gpArchRetn); - } - - return sesshandle; -} - -int tsm_regfs(dsUint32_t sesshandle, char *fsname) { - regFSData regFS; - dsInt16_t rc; - - memset(®FS, 0, sizeof(regFS)); - - regFS.fsName = fsname; - regFS.fsType = "TSMPIPE"; - - rc = dsmRegisterFS(sesshandle, ®FS); - if(rc != DSM_RC_OK && rc != DSM_RC_FS_ALREADY_REGED) { - tsm_printerr(sesshandle, rc, "dsmRegisterFS failed"); - return 0; - } - - return 1; -} - - -void tsm_name2obj(char *fsname, char *filename, dsmObjName *objName) { - char *p; - - /* fs == "/filesystem", hl == "/directory/path", ll == "/filename" */ - strcpy(objName->fs, fsname); - *objName->hl = '\0'; - *objName->ll = '\0'; - p = strrchr(filename, '/'); - if(p) { - *p = '\0'; - if(*filename && *filename != '/') { - strcpy(objName->hl, "/"); - } - strcat(objName->hl, filename); - sprintf(objName->ll, "/%s", p+1); - *p = '/'; - } - else { - if(*filename && *filename != '/') { - strcpy(objName->ll, "/"); - } - strcat(objName->ll, filename); - } - objName->objType = DSM_OBJ_FILE; -} - - -int tsm_sendfile(dsUint32_t sesshandle, char *fsname, char *filename, - off_t length, char *description, dsmSendType sendtype, - char verbose) -{ - char *buffer; - dsInt16_t rc; - dsUint16_t reason=0; - dsmObjName objName; - mcBindKey mcBindKey; - sndArchiveData archData, *archDataP=NULL; - ObjAttr objAttr; - DataBlk dataBlk; - ssize_t nbytes; - - dsmEndSendObjExIn_t dsmEndSendObjExIn; - dsmEndSendObjExOut_t dsmEndSendObjExOut; - - memset(&dsmEndSendObjExIn, 0x00, sizeof(dsmEndSendObjExIn_t)); - memset(&dsmEndSendObjExOut,0x00, sizeof(dsmEndSendObjExOut_t)); - - buffer = malloc(BUFLEN); - if(!buffer) { - perror("tsmpipe: malloc"); - return 0; - } - - rc = dsmBeginTxn(sesshandle); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmBeginTxn failed"); - return 0; - } - - tsm_name2obj(fsname, filename, &objName); - - if(verbose > 0) { - fprintf(stderr, "tsmpipe: Starting to send stdin as %s%s%s\n", - objName.fs, objName.hl, objName.ll); - } - - mcBindKey.stVersion = mcBindKeyVersion; - rc = dsmBindMC(sesshandle, &objName, sendtype, &mcBindKey); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmBindMC failed"); - return 0; - } - - if(verbose > 1) { - char *cgdest=NULL; - - fprintf(stderr, "tsmpipe: Bound to Management Class: %s\n", mcBindKey.mcName); - if((sendtype == stArchiveMountWait || sendtype == stArchive) && - mcBindKey.archive_cg_exists) - { - cgdest = mcBindKey.archive_copy_dest; - } - else if(mcBindKey.backup_cg_exists) { - cgdest = mcBindKey.backup_copy_dest; - } - if(cgdest) { - fprintf(stderr, "tsmpipe: Destination Copy Group: %s\n", cgdest); - } - } - - memset(&objAttr, 0, sizeof(objAttr)); - objAttr.stVersion = ObjAttrVersion; - *objAttr.owner = '\0'; - objAttr.sizeEstimate.hi = length >> 32; - objAttr.sizeEstimate.lo = length & ~0U; - objAttr.objCompressed = bFalse; - - if(sendtype == stArchiveMountWait || sendtype == stArchive) { - archData.stVersion = sndArchiveDataVersion; - archData.descr = description; - archDataP = &archData; - } - - rc = dsmSendObj(sesshandle, sendtype, archDataP, &objName, &objAttr, NULL); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmSendObj failed"); - return(0); - } - - dataBlk.stVersion = DataBlkVersion; - - while(1) { - nbytes = rw_full(STDIN_FILENO, buffer, BUFLEN); - - if(nbytes < 0) { - perror("tsmpipe: read"); - return 0; - } - else if(nbytes == 0) { - break; - } - - dataBlk.bufferLen = nbytes; - dataBlk.numBytes = 0; - dataBlk.bufferPtr = buffer; - - rc = dsmSendData(sesshandle, &dataBlk); - if(rc != DSM_RC_OK && rc != DSM_RC_COMPRESS_GREW) { - tsm_printerr(sesshandle, rc, "dsmSendData failed"); - return 0; - } - } - - /* - rc = dsmEndSendObj(sesshandle); - if(rc != DSM_RC_OK && rc != DSM_RC_COMPRESS_GREW) { - tsm_printerr(sesshandle, rc, "dsmEndSendObj failed"); - return(0); - } - */ - dsmEndSendObjExIn.stVersion = dsmEndSendObjExInVersion; - dsmEndSendObjExIn.dsmHandle = sesshandle; - dsmEndSendObjExOut.stVersion = dsmEndSendObjExOutVersion; - - if ((rc = dsmEndSendObjEx(&dsmEndSendObjExIn, &dsmEndSendObjExOut)) != DSM_RC_OK) - { - tsm_printerr(sesshandle, rc, "dsmEndSendObj failed"); - return(0); - } - - rc = dsmEndTxn(sesshandle, DSM_VOTE_COMMIT, &reason); - if(rc == DSM_RC_CHECK_REASON_CODE || - (rc == DSM_RC_OK && reason != DSM_RC_OK)) - { - tsm_printerr(sesshandle, reason, "dsmEndTxn failed, reason"); - return(0); - } - else if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmEndTxn failed"); - return(0); - } - - /* - dI64toCh(&endSendObjExOut.totalBytesSent,t,10); - format_number(t,t2); - printf("Total bytes sent: %s\n", t2); - printf("Compression: %s\n", endSendObjExOut.objCompressed == bTrue ? "YES" : "NO"); - - dI64toCh(&endSendObjExOut.totalCompressSize,t,10); - format_number(t,t2); - printf("Compressed size: %s\n", t2); - - dI64toCh(&endSendObjExOut.totalLFBytesSent,t,10); - format_number(t,t2); - printf("LAN-free bytes sent: %s\n", t2); - - printf("Encryption: %s\n", endSendObjExOut.encryptionType & DSM_ENCRYPT_CLIENTENCRKEY ? "CLIENTENCRKEY" : endSendObjExOut.encryptionType & DSM_ENCRYPT_USER ? "USER" : "NO"); - printf("Encryption Strength: %s\n", endSendObjExOut.encryptionType & DSM_ENCRYPT_AES_128BIT ? "AES_128BIT" : endSendObjExOut.encryptionType & DSM_ENCRYPT_DES_56BIT ? "DES_56BIT" : "NONE"); - printf("Object Deduplicated: %s\n", endSendObjExOut.objDeduplicated ? "YES" : "NO"); - dI64toCh(&endSendObjExOut.totalDedupSize,t,10); - format_number(t,t2); - printf("Deduplicated size: %s\n\n", t2); - */ - - return 1; -} - -/* Typedef for the callback used in tsm_queryfile() */ -/* Returns: -1 upon error condition, application should exit. - * 0 if tsm_queryfile() should skip processing the remaining - * matches. - * 1 otherwise. - */ -typedef int (*tsm_query_callback)(dsmQueryType, DataBlk *, void *); - - -dsInt16_t tsm_queryfile(dsUint32_t sesshandle, dsmObjName *objName, - char *description, dsmSendType sendtype, char verbose, - tsm_query_callback usercb, void * userdata, char *pitdate, int querytype) -{ - dsmQueryType qType; - qryArchiveData qaData; - qryRespArchiveData qaResp; - qryBackupData qbData; - qryRespBackupData qbResp; - dsmQueryBuff *qDataP; - DataBlk qResp; - dsInt16_t rc; - - qResp.stVersion = DataBlkVersion; - - if(verbose > 1) { - fprintf(stderr, "tsmpipe: Query file %s%s%s\n", - objName->fs, objName->hl, objName->ll); - } - - if(sendtype == stArchiveMountWait || sendtype == stArchive) { - qType = qtArchive; - - qaData.stVersion = qryArchiveDataVersion; - qaData.objName = objName; - qaData.owner = ""; - qaData.insDateLowerBound.year = DATE_MINUS_INFINITE; - qaData.insDateUpperBound.year = DATE_PLUS_INFINITE; - qaData.expDateLowerBound.year = DATE_MINUS_INFINITE; - qaData.expDateUpperBound.year = DATE_PLUS_INFINITE; - qaData.descr = description?description:"*"; - - qDataP = &qaData; - - qaResp.stVersion = qryRespArchiveDataVersion; - - qResp.bufferPtr = (char *) &qaResp; - qResp.bufferLen = sizeof(qaResp); - } - else { - qType = qtBackup; - - qbData.stVersion = qryBackupDataVersion; - qbData.objName = objName; - qbData.owner = ""; - qbData.objState = querytype; - - if (pitdate) { - qbData.pitDate = xStringToDate(pitdate); - } else { - qbData.pitDate.year = DATE_MINUS_INFINITE; - } - - qDataP = &qbData; - - qbResp.stVersion = qryRespBackupDataVersion; - - qResp.bufferPtr = (char *) &qbResp; - qResp.bufferLen = sizeof(qbResp); - } - - rc = dsmBeginQuery(sesshandle, qType, qDataP); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmBeginQuery failed"); - return rc; - } - - /* Loop and apply our callback to the result */ - while((rc = dsmGetNextQObj(sesshandle, &qResp)) == DSM_RC_MORE_DATA) { - int cbret; - - if(verbose > 1) { - dsmObjName *rObjName; - - if(qType == qtArchive) { - qryRespArchiveData *qr = (void *) qResp.bufferPtr; - rObjName = &(qr->objName); - } - else if(qType == qtBackup) { - qryRespBackupData *qr = (void *) qResp.bufferPtr; - rObjName = &(qr->objName); - } - else { - fprintf(stderr, - "tsm_queryfile: Internal error: Unknown qType %d\n", - qType); - return DSM_RC_UNKNOWN_ERROR; - } - fprintf(stderr, "tsmpipe: Matched file %s%s%s\n", - rObjName->fs, rObjName->hl, rObjName->ll); - } - if(usercb == NULL) { - continue; - } - cbret = usercb(qType, &qResp, userdata); - if (cbret < 0) { - return DSM_RC_UNKNOWN_ERROR; - } - else if(cbret == 0) { - break; - } - } - - if(rc != DSM_RC_FINISHED && rc != DSM_RC_MORE_DATA) { - tsm_printerr(sesshandle, rc, "dsmGetNextObj failed"); - return rc; - } - - rc = dsmEndQuery(sesshandle); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmEndQuery failed"); - return rc; - } - - return DSM_RC_OK; -} - -struct matchone_cb_data { - int numfound; - dsStruct64_t objId; - dsUint32_t copyGroup; -}; - -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, "tsmpipe: FAILED: The file specification matched multiple files.\n"); - return -1; - } - - return 1; -} - - -int tsm_deletefile(dsUint32_t sesshandle, char *fsname, char *filename, - char *description, dsmSendType sendtype, char verbose) -{ - dsInt16_t rc; - dsUint16_t reason=0; - dsmDelInfo *dInfoP; - dsmDelType dType; - struct matchone_cb_data cbdata; - delArch daInfo; - delBack dbInfo; - dsmObjName objName; - - tsm_name2obj(fsname, filename, &objName); - - if(verbose > 0) { - fprintf(stderr, "tsmpipe: Deleting file %s%s%s\n", - objName.fs, objName.hl, objName.ll); - } - - cbdata.numfound = 0; - rc = tsm_queryfile(sesshandle, &objName, description, sendtype, - verbose, tsm_matchone_cb, &cbdata, NULL, DSM_ACTIVE); - if(rc != DSM_RC_OK) { - return 0; - } - - if(cbdata.numfound == 0) { - fprintf(stderr, "tsmpipe: FAILED: The file specification did not match any file.\n"); - return(0); - } - - if(sendtype == stArchiveMountWait || sendtype == stArchive) { - dType = dtArchive; - - daInfo.stVersion = delArchVersion; - daInfo.objId = cbdata.objId; - - dInfoP = (dsmDelInfo *) &daInfo; - } - else { - dType = dtBackup; - - dbInfo.stVersion = delBackVersion; - dbInfo.objNameP = &objName; - dbInfo.copyGroup = cbdata.copyGroup; - - dInfoP = (dsmDelInfo *) &dbInfo; - } - - rc = dsmBeginTxn(sesshandle); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmBeginTxn failed"); - return 0; - } - - rc = dsmDeleteObj(sesshandle, dType, *dInfoP); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmDeleteObj failed"); - return 0; - } - - rc = dsmEndTxn(sesshandle, DSM_VOTE_COMMIT, &reason); - if(rc == DSM_RC_CHECK_REASON_CODE || - (rc == DSM_RC_OK && reason != DSM_RC_OK)) - { - tsm_printerr(sesshandle, reason, "dsmEndTxn failed, reason"); - return(0); - } - else if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmEndTxn failed"); - return(0); - } - - return(1); -} - - -/* @TODO Need to assume latest active if PIT not specified */ -int tsm_restorefile(dsUint32_t sesshandle, char *fsname, char *filename, - char *description, dsmSendType sendtype, char verbose, char *pitdate) -{ - dsInt16_t rc; - struct matchone_cb_data cbdata; - dsmGetList getList; - dsmGetType getType; - DataBlk dataBlk; - dsmObjName objName; - - tsm_name2obj(fsname, filename, &objName); - - if(verbose > 0) { - fprintf(stderr, "tsmpipe: Restoring file %s%s%s\n", - objName.fs, objName.hl, objName.ll); - } - - cbdata.numfound = 0; - - rc = tsm_queryfile(sesshandle, &objName, description, sendtype, - verbose, tsm_matchone_cb, &cbdata, pitdate, DSM_ANY_MATCH); - if(rc != DSM_RC_OK) { - return 0; - } - - if(cbdata.numfound == 0) { - fprintf(stderr, "tsmpipe: FAILED: The file specification did not match any file.\n"); - return(0); - } - - getList.stVersion = dsmGetListVersion; - getList.numObjId = 1; - getList.objId = &cbdata.objId; - getList.partialObjData = NULL; - - if(sendtype == stArchiveMountWait || sendtype == stArchive) { - getType = gtArchive; - } - else { - getType = gtBackup; - } - - rc = dsmBeginGetData(sesshandle, bTrue, getType, &getList); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmBeginGetData failed"); - return 0; - } - - dataBlk.stVersion = DataBlkVersion; - dataBlk.bufferPtr = malloc(BUFLEN); - if(!dataBlk.bufferPtr) { - perror("tsmpipe: malloc"); - return 0; - } - dataBlk.bufferLen = BUFLEN; - dataBlk.numBytes = 0; - rc = dsmGetObj(sesshandle, &cbdata.objId, &dataBlk); - while(rc == DSM_RC_MORE_DATA) { - if(rw_full(STDOUT_FILENO, dataBlk.bufferPtr, dataBlk.numBytes) < 0) { - perror("tsmpipe: write"); - return 0; - } - dataBlk.numBytes = 0; - rc = dsmGetData(sesshandle, &dataBlk); - } - if(rc != DSM_RC_FINISHED) { - tsm_printerr(sesshandle, rc, "dsmGetObj/dsmGetData failed"); - return 0; - } - if(rw_full(STDOUT_FILENO, dataBlk.bufferPtr, dataBlk.numBytes) < 0) { - perror("tsmpipe: write"); - return 0; - } - - rc = dsmEndGetObj(sesshandle); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmEndGetObj failed"); - return 0; - } - - rc = dsmEndGetData(sesshandle); - if(rc != DSM_RC_OK) { - tsm_printerr(sesshandle, rc, "dsmEndGetData failed"); - return 0; - } - - return 1; -} - -// Display the dsmDate value as a string -void QryDateToStr(char *s,dsmDate date) -{ - sprintf(s,"%02i/%02i/%02i %02i:%02i:%02i", - (dsInt16_t)date.month, - (dsInt16_t)date.day, - date.year, - (dsInt16_t)date.hour, - (dsInt16_t)date.minute, - (dsInt16_t)date.second); -} - -dsmDate xStringToDate(char *s) -{ - dsUint32_t temp; - dsUint32_t temp1; - dsmDate *date; - - date = (dsmDate*)malloc(sizeof(dsmDate)); - /* printf("\n Date String: %s", s); */ - /* if user key in some inputs */ - if (s[0] != '\0') - { - temp1 = atol(s); - date->month = temp1 / 1000000; - temp = temp1 % 1000000; - date->day = temp / 10000; - date->year = temp % 10000; - } - /* if user just hit enter key */ - /* everythin else except year is initialized. */ - /* we don't know it's hi or lo year. */ - else - { - date->month = 12; - date->day = 31; - } - /* printf("\ndate = %d, month = %d, year = %d", date->day, date->month, date->year);*/ - - return *date; -} /* static void xStringToDate(char *s, dsmDate *date) */ - -int tsm_listfile_cb(dsmQueryType qType, DataBlk *qResp, void * userdata) -{ - unsigned long long filesize; - dsStruct64_t *rSizeEst; - dsmObjName *rObjName; - dsmDate *insDate; - char *s; - char *state="?"; - dsUint8_t *objstate=0; - - - s = (char*)malloc(sizeof(dsmObjName)); - insDate = (dsmDate*)malloc(sizeof(dsmDate)); - if(userdata != NULL ) { - fprintf(stderr, "tsm_listfile_cb: Internal error: userdate != NULL"); - return -1; - } - - if(qType == qtArchive) { - qryRespArchiveData *qr = (void *) qResp->bufferPtr; - - rSizeEst = &qr->sizeEstimate; - rObjName = &qr->objName; - } - else if(qType == qtBackup) { - qryRespBackupData *qr = (void *) qResp->bufferPtr; - - rSizeEst = &qr->sizeEstimate; - rObjName = &qr->objName; - insDate = &qr->insDate; - objstate = &qr->objState; - if (*objstate==DSM_INACTIVE) - state="I"; - if (*objstate==DSM_ACTIVE) - state="A"; - - } - else { - fprintf(stderr, - "tsm_listfile_cb: Internal error: Unknown qType %d\n", qType); - return -1; - } - - filesize = rSizeEst->hi; - filesize <<= 32; - filesize |= rSizeEst->lo; - QryDateToStr(s, *insDate); - printf("%s %s %10lld %s %s%s\n", s, state, filesize, rObjName->fs, rObjName->hl, rObjName->ll); - - return 1; -} - - -int tsm_listfile(dsUint32_t sesshandle, char *fsname, char *filename, - char *description, dsmSendType sendtype, char verbose, char *pitdate) -{ - dsInt16_t rc; - dsmObjName objName; - - tsm_name2obj(fsname, filename, &objName); - - if(verbose > 0) { - fprintf(stderr, "tsmpipe: Listing file(s) %s%s%s\n", - objName.fs, objName.hl, objName.ll); - } - - rc = tsm_queryfile(sesshandle, &objName, description, sendtype, - verbose, tsm_listfile_cb, NULL, pitdate, DSM_ANY_MATCH); - if(rc != DSM_RC_OK && rc != DSM_RC_ABORT_NO_MATCH) { - return 0; - } - - return 1; -} +extern dsUint32_t tsm_initsess(char *options); +extern void tsm_sessioninfo(dsUint32_t dsmHandle); +extern int tsm_listfile(dsUint32_t dsmHandle, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose, char *pitdate); +extern int tsm_sendfile(dsUint32_t dsmHandle, char *fsname, char *filename, off_t length, char *description, dsmSendType sendtype, char verbose); +extern int tsm_restorefile(dsUint32_t dsmHandle, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose, char *pitdate); +extern int tsm_deletefile(dsUint32_t dsmHandle, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose); int copy_env(const char *from, const char *to) { - char *e; - char n[PATH_MAX+1]; + char *e; + char n[PATH_MAX+1]; - e = getenv(from); - if(!e) { - fprintf(stderr, "tsmpipe: Environment variable %s not set\n", from); - return(0); - } - n[PATH_MAX] = '\0'; - snprintf(n, PATH_MAX, "%s=%s", to, e); - if(putenv(strdup(n))) { - perror("tsmpipe: Setting up environment"); - return(0); - } + e = getenv(from); + if (!e) { + fprintf(stderr,"tsmpipe: Environment variable %s not set\n",from); + return 0; + } - return(1); + n[PATH_MAX] = '\0'; + snprintf(n, PATH_MAX, "%s=%s", to, e); + + if (putenv(strdup(n))) { + perror("tsmpipe: Setting up environment"); + return 0; + } + + return 1; } - void usage(void) { - fprintf(stderr, - "tsmpipe $Revision: 1.5-dg $, usage:\n" - "tsmpipe [-A|-B] [-c|-x|-d|-t] -s fsname -f filepath [-l len]\n" - " -A and -B are mutually exclusive:\n" - " -A Use Archive objects\n" - " -B Use Backup objects\n" - " -c, -x, -d and -t are mutually exclusive:\n" - " -c Create: Read from stdin and store in TSM\n" - " -x eXtract: Recall from TSM and write to stdout\n" - " -d Delete: Delete object from TSM\n" - " -t lisT: Print filelist to stdout\n" - " -s and -f are required arguments:\n" - " -s fsname Name of filesystem in TSM\n" - " -f filepath Path to file within filesystem in TSM\n" - " -l length Length of object to store. If guesstimating too large\n" - " is better than too small\n" - " -D desc Description of archive object\n" - " -P pitdate PITDate (mmddYYYY)\n" - " -O options Extra options to pass to dsmInitEx\n" - " -v Verbose. More -v's gives more verbosity\n" - ); -} + fprintf(stderr, + "tsmpipe $Revision: 1.5-dg $, usage:\n" + "\n" + "tsmpipe [-i] [-A|-B] [-c|-x|-d|-t] -s fsname -f filepath [-l len]\n" + " -i Show session information:\n" + " -A and -B are mutually exclusive:\n" + " -A Use Archive objects\n" + " -B Use Backup objects\n" + " -c, -x, -d and -t are mutually exclusive:\n" + " -c Create: Read from stdin and store in TSM\n" + " -x eXtract: Recall from TSM and write to stdout\n" + " -d Delete: Delete object from TSM\n" + " -t lisT: Print filelist to stdout\n" + " -s and -f are required arguments for (-A/ -B operations):\n" + " -s fsname Name of filesystem in TSM\n" + " -f filepath Path to file within filesystem in TSM\n" + " -l length Length of object to store. If guesstimating too large\n" + " is better than too small\n" + " -D desc Description of archive object\n" + " -P pitdate PITDate (mmddYYYY)\n" + " -O options Extra options to pass to dsmInitEx\n" + " -v Verbose. More -v's gives more verbosity\n" + ); + exit(1); +} int main(int argc, char *argv[]) { - int c; - extern int optind, optopt; - extern char *optarg; - char archmode=0, backmode=0, create=0, xtract=0, delete=0, verbose=0, info=0; - char list=0; - char *space=NULL, *filename=NULL, *lenstr=NULL, *desc=NULL, *pitdate=NULL; - char *options=NULL; - off_t length; - dsUint32_t sesshandle; - dsmSendType sendtype; + int c; + extern int optopt; + extern char *optarg; + char archive=0, backup=0, create=0, xtract=0, delete=0, verbose=0, info=0, list=0; + char *space=NULL, *filename=NULL, *lenstr=NULL, *desc=NULL, *pitdate=NULL, *options=NULL; + off_t length; + dsUint32_t dsmHandle; + dsmSendType sendtype; - while ((c = getopt(argc, argv, "hiABcxdtvs:f:l:D:O:P:")) != -1) { - switch(c) { - case 'h': - usage(); - exit(1); - case 'i': - info = 1; - break; - case 'A': - archmode = 1; - break; - case 'B': - backmode = 1; - break; - case 'c': - create = 1; - break; - case 'x': - xtract = 1; - break; - case 'd': - delete = 1; - break; - case 't': - list = 1; - break; - case 'v': - verbose++; - break; - case 's': - space = optarg; - break; - case 'f': - filename = optarg; - break; - case 'l': - lenstr = optarg; - break; - case 'D': - desc = optarg; - break; - case 'O': - options = optarg; - break; - case 'P': - pitdate = optarg; - break; - case ':': - fprintf(stderr, "tsmpipe: Option -%c requires an operand\n", optopt); - exit(1); - case '?': - fprintf(stderr, "tsmpipe: Unrecognized option: -%c\n", optopt); - exit(1); - } - } + while ((c = getopt(argc, argv, "hiABcxdtvs:f:l:D:O:P:")) != -1) { + switch(c) { + case 'h': usage(); break; + case 'i': info = 1; break; + case 'A': archive = 1; break; + case 'B': backup = 1; break; + case 'c': create = 1; break; + case 'x': xtract = 1; break; + case 'd': delete = 1; break; + case 't': list = 1; break; + case 'v': verbose++; break; + case 's': space = optarg; break; + case 'f': filename = optarg; break; + case 'l': lenstr = optarg; break; + case 'D': desc = optarg; break; + case 'O': options = optarg; break; + case 'P': pitdate = optarg; break; - if(archmode+backmode+info != 1) { - fprintf(stderr, "tsmpipe: ERROR: Must give one of -i, -A or -B\n"); - exit(1); - } - if(create+xtract+delete+list+info != 1) { - fprintf(stderr, "tsmpipe: ERROR: Must give one of -c, -x, -d or -t\n"); - exit(1); - } - if(!info && !space) { - fprintf(stderr, "tsmpipe: ERROR: Must give -s filespacename\n"); - exit(1); - } - if(!info && !filename) { - fprintf(stderr, "tsmpipe: ERROR: Must give -f filename\n"); - exit(1); - } - if(!info && create && !lenstr) { - fprintf(stderr, "tsmpipe: ERROR: Must give -l length with -c\n"); - exit(1); - } - if(!info && !create && lenstr) { - fprintf(stderr, "tsmpipe: ERROR: -l length useless without -c\n"); - exit(1); - } - if(!info && !archmode && desc) { - fprintf(stderr, "tsmpipe: ERROR: -D desc useless without -A\n"); - exit(1); - } + case ':': + fprintf(stderr, "tsmpipe: Option -%c requires an operand\n", optopt); + exit(1); + case '?': + fprintf(stderr, "tsmpipe: Unrecognized option: -%c\n", optopt); + exit(1); + } + } - if(archmode) { - sendtype = stArchiveMountWait; - } - else { - sendtype = stBackupMountWait; - } + if (archive+backup+info != 1) { + fprintf(stderr, "tsmpipe: ERROR: Must give one of -i, -A or -B\n"); + exit(1); + } - /* Let the TSM api get the signals */ - signal(SIGPIPE, SIG_IGN); - signal(SIGINT, SIG_IGN); - signal(SIGUSR1, SIG_IGN); + if (! info) { + if (create+xtract+delete+list != 1) { + fprintf(stderr, "tsmpipe: ERROR: Must give one of -c, -x, -d or -t\n"); + exit(1); + } - if(getenv("DSM_DIR") && (!copy_env("DSM_DIR", "DSMI_DIR"))) { - exit(2); - } + if (! space) { + fprintf(stderr, "tsmpipe: ERROR: Must give -s filespacename\n"); + exit(1); + } - if(getenv("DSM_DIR") && (!copy_env("DSM_CONFIG", "DSMI_CONFIG"))) { - exit(2); - } + if (! filename) { + fprintf(stderr, "tsmpipe: ERROR: Must give -f filename\n"); + exit(1); + } - if(!tsm_checkapi()) { - exit(2); - } + if(create && ! lenstr) { + fprintf(stderr, "tsmpipe: ERROR: Must give -l length with -c\n"); + exit(1); + } - sesshandle = tsm_initsess(options); - if(!sesshandle) { - exit(3); - } + if(! create && lenstr) { + fprintf(stderr, "tsmpipe: ERROR: -l length useless without -c\n"); + exit(1); + } - if(verbose > 1) { - fprintf(stderr, "tsmpipe: Session initiated\n"); - } + if(! archive && desc) { + fprintf(stderr, "tsmpipe: ERROR: -D desc useless without -A\n"); + exit(1); + } + } - if(info) { - fprintf(stdout,"info"); - exit(0); - } + sendtype = archive ? stArchiveMountWait : stBackupMountWait; - if(create) { - if(!tsm_regfs(sesshandle, space)) { - exit(4); - } - length = atooff(lenstr); - if(length <= 0) { - fprintf(stderr, "tsmpipe: ERROR: Provide positive length, overestimate if guessing"); - exit(5); - } - if(!tsm_sendfile(sesshandle, space, filename, length, desc, sendtype, verbose)){ - dsmTerminate(sesshandle); - exit(6); - } - } + /* Let the TSM api get the signals */ + signal(SIGPIPE, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGUSR1, SIG_IGN); - if(delete) { - if(!tsm_deletefile(sesshandle, space, filename, desc, sendtype, verbose)) { - dsmTerminate(sesshandle); - exit(7); - } - } + if (getenv("DSM_DIR") && ((! copy_env("DSM_DIR", "DSMI_DIR")) || (! copy_env("DSM_CONFIG", "DSMI_CONFIG")))) { + exit(1); + } - if(xtract) { - if(!tsm_restorefile(sesshandle, space, filename, desc, sendtype, verbose, pitdate)) - { - dsmTerminate(sesshandle); - exit(8); - } - } + // OK, we are ready to talk to TSM + dsmHandle = tsm_initsess(options); + if (! dsmHandle) { + exit(2); + } - if(list) { - if(!tsm_listfile(sesshandle, space, filename, desc, sendtype, verbose, pitdate)) - { - dsmTerminate(sesshandle); - exit(9); - } - } + if (verbose > 1) + fprintf(stderr, "tsmpipe: Session initiated\n"); - if(verbose > 0) { - fprintf(stderr, "tsmpipe: Success!\n"); - } + // Show our session information + if (info) { + tsm_sessioninfo(dsmHandle); + } - dsmTerminate(sesshandle); + // If we are backing up + if (create) { + length = atof(lenstr); + if (length <= 0) { + fprintf(stderr,"tsmpipe: ERROR: Provide positive length, overestimate if guessing"); + exit(1); + } - return(0); + if (! tsm_sendfile(dsmHandle,space,filename,length,desc,sendtype,verbose)){ + dsmTerminate(dsmHandle); + exit(3); + } + } + + // Delete an object from TSM + if (delete) { + if (! tsm_deletefile(dsmHandle,space,filename,desc,sendtype,verbose)) { + dsmTerminate(dsmHandle); + exit(3); + } + } + + // Restore from TSM + if(xtract) { + if (! tsm_restorefile(dsmHandle,space,filename,desc,sendtype,verbose,pitdate)) { + dsmTerminate(dsmHandle); + exit(3); + } + } + + // List objects in TSM + if (list) { + if (! tsm_listfile(dsmHandle,space,filename,desc,sendtype,verbose,pitdate)) { + dsmTerminate(dsmHandle); + exit(3); + } + } + + dsmTerminate(dsmHandle); + + if (verbose > 0) + fprintf(stderr, "tsmpipe: Success\n"); + + return 0; } - -/* -vim:ts=4:sw=4:et:cindent -*/ diff --git a/tsmpipe.h b/tsmpipe.h new file mode 100644 index 0000000..37828f8 --- /dev/null +++ b/tsmpipe.h @@ -0,0 +1,3 @@ +typedef int (*tsm_query_callback)(dsmQueryType, DataBlk *, void *); + +struct matchone_cb_data { int numfound; dsStruct64_t objId; dsUint32_t copyGroup; };