/* 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 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 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. */ static const char rcsid[] = /*Add RCS version string to binary */ "$Id: tsmpipe.c,v 1.5-dg 2010/02/15 07:41:26 nikke Exp $"; /* Enable Large File Support stuff */ #define _FILE_OFFSET_BITS 64 #define _LARGEFILE_SOURCE 1 #define _LARGE_FILES 1 #include #include #include #include #include #include #include #include "dsmrc.h" #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 32*1024*2-4. */ /* We (HPC2N) have 512kB tcpbuff */ #define BUFLEN (64*1024-4) static dsmDate xStringToDate (char *s); 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; } ssize_t read_full(int fd, void *buf, size_t count) { ssize_t done=0; while(count) { ssize_t len; len = read(fd, buf+done, count); 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); } ssize_t write_full(int fd, const void *buf, size_t count) { ssize_t done=0; while(count) { ssize_t len; len = write(fd, buf+done, count); if(len < 0) { if(errno == EINTR) { continue; } else { done = -1; break; } } count -= len; done += len; } return(done); } 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; } 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); } dsUint32_t tsm_initsess(char *options) { dsmApiVersionEx applApi; dsUint32_t sesshandle = 0; dsmInitExIn_t initIn; dsmInitExOut_t initOut; dsInt16_t rc; 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(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; } 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; 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 = read_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); } 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; } /* 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) { 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 = DSM_ANY_MATCH; 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, char *pitdate) { 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, pitdate); 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); } 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); 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(write_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(write_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 static void QryDateToStr(char *s,dsmDate date) { sprintf(s,"%i/%02i/%02i %02i:%02i:%02i", date.year, (dsInt16_t)date.month, (dsInt16_t)date.day, (dsInt16_t)date.hour, (dsInt16_t)date.minute, (dsInt16_t)date.second); } static 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 %lld %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); if(rc != DSM_RC_OK && rc != DSM_RC_ABORT_NO_MATCH) { return 0; } return 1; } int copy_env(const char *from, const char *to) { 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); } 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" ); } 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; 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; while ((c = getopt(argc, argv, "hABcxdtvs:f:l:D:O:P:")) != -1) { switch(c) { case 'h': usage(); exit(1); 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); } } if(archmode+backmode != 1) { fprintf(stderr, "tsmpipe: ERROR: Must give one of -A or -B\n"); exit(1); } if(create+xtract+delete+list != 1) { fprintf(stderr, "tsmpipe: ERROR: Must give one of -c, -x, -d or -t\n"); exit(1); } if(!space) { fprintf(stderr, "tsmpipe: ERROR: Must give -s filespacename\n"); exit(1); } if(!filename) { fprintf(stderr, "tsmpipe: ERROR: Must give -f filename\n"); exit(1); } if(create && !lenstr) { fprintf(stderr, "tsmpipe: ERROR: Must give -l length with -c\n"); exit(1); } if(!create && lenstr) { fprintf(stderr, "tsmpipe: ERROR: -l length useless without -c\n"); exit(1); } if(!archmode && desc) { fprintf(stderr, "tsmpipe: ERROR: -D desc useless without -A\n"); exit(1); } if(archmode) { sendtype = stArchiveMountWait; } else { sendtype = stBackupMountWait; } /* Let the TSM api get the signals */ signal(SIGPIPE, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGUSR1, SIG_IGN); if(getenv("DSM_DIR") && (!copy_env("DSM_DIR", "DSMI_DIR"))) { exit(2); } if(getenv("DSM_DIR") && (!copy_env("DSM_CONFIG", "DSMI_CONFIG"))) { exit(2); } if(!tsm_checkapi()) { exit(2); } sesshandle = tsm_initsess(options); if(!sesshandle) { exit(3); } if(verbose > 1) { fprintf(stderr, "tsmpipe: Session initiated\n"); } 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); } } if(delete) { if(!tsm_deletefile(sesshandle, space, filename, desc, sendtype, verbose, pitdate)) { dsmTerminate(sesshandle); exit(7); } } if(xtract) { if(!tsm_restorefile(sesshandle, space, filename, desc, sendtype, verbose, pitdate)) { dsmTerminate(sesshandle); exit(8); } } if(list) { if(!tsm_listfile(sesshandle, space, filename, desc, sendtype, verbose, pitdate)) { dsmTerminate(sesshandle); exit(9); } } if(verbose > 0) { fprintf(stderr, "tsmpipe: Success!\n"); } dsmTerminate(sesshandle); return(0); } /* vim:ts=4:sw=4:et:cindent */