Files
libraries/SDD/sdd_scmd.c
Philip Smart af833c09ee Initial upload
2019-11-18 00:29:48 +00:00

1283 lines
44 KiB
C
Executable File

/******************************************************************************
* Product: ##### ###### ###### # ### ######
* # # # # # # # # # #
* # # # # # # # # #
* ##### # # # # # # ######
* # # # # # # # # #
* # # # # # # # # # #
* ##### ###### ###### ####### ####### ### ######
*
* File: sdd_scmd.c
* Description: Server Data-source Driver library driver to handle system
* command execution on the local host.
*
* Version: %I%
* Dated: %D%
* Copyright: P.D. Smart, 1996-2019.
*
* History: 1.0 - Initial Release.
*
******************************************************************************
* This source file is free software: you can redistribute it and#or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This source file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
/* Bring in system header files.
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
#include <sys/wait.h>
#include <unistd.h>
#endif
/* Indicate that we are a C module for any header specifics.
*/
#define SDD_SCMD_C
/* Bring in local specific header files.
*/
#include "sdd.h"
#include "sdd_scmd.h"
/******************************************************************************
* Function: _SCMD_GetStrArg
* Description: Function to scan an input buffer and extract a string based
* argument.
*
* Returns: SDD_FAIL- Couldnt obtain argument.
* SDD_OK - Argument obtained.
******************************************************************************/
int _SCMD_GetStrArg( UCHAR *snzDataBuf, /* I: Input buffer */
int nDataLen, /* I: Len of data */
UCHAR *szArg, /* I: Arg to look for */
UCHAR **pszPath ) /* O: Pointer to argument */
{
/* Local variables.
*/
int nCmpLen;
int nPos;
int nReturn = SDD_FAIL;
UCHAR *szFunc = "_SCMD_GetStrArg";
/* Go through the input buffer looking for 'szArg' within the
* input buffer. If it exists, then note the position just after it
* as this contains the string argument.
*/
for(nPos=0, nCmpLen=strlen(szArg); nPos < nDataLen; nPos++)
{
/* If a match occurs, then setup the pointer to correct location.
*/
if(strncmp(&snzDataBuf[nPos], szArg, nCmpLen) == 0)
{
/* Make sure that the match is not a sub-match as some of the
* variables we are scanning for are similar.
*/
if( (nPos == 0) ||
(nPos > 0 && snzDataBuf[nPos-1] == '\0') ||
(nPos > 0 && isspace(snzDataBuf[nPos-1])) )
{
nPos += nCmpLen;
break;
}
}
}
/* If the pointer did not reach the end of the buffer then we have
* located a valid name.
*/
if(nPos < nDataLen)
{
/* Setup the callers pointer to point to the correct location
* in the buffer.
*/
*pszPath = &snzDataBuf[nPos];
nReturn=SDD_OK;
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _SCMD_ValidatePath
* Description: Function to validate the existence of a path.
*
* Returns: SDD_FAIL- Couldnt validate PATH.
* SDD_OK - PATH validated.
******************************************************************************/
int _SCMD_ValidatePath( UCHAR *pszPath ) /* I: Path to validate */
{
/* Local variables.
*/
int nReturn = SDD_FAIL;
UCHAR *szFunc = "_SCMD_ValidatePath";
struct stat sStat;
/* Test the path to ensure its valid.
*/
if( (stat(pszPath, &sStat) == -1) ||
((sStat.st_mode & S_IFDIR) == 0) )
{
nReturn=SDD_FAIL;
} else
{
nReturn=SDD_OK;
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _SCMD_ValidateFile
* Description: Function to validate the existence of a file or to validate
* that a file can be created.
*
* Returns: SDD_FAIL- Couldnt obtain Filename or validate it.
* SDD_OK - Filename obtained and validated.
******************************************************************************/
int _SCMD_ValidateFile( UCHAR *pszPath, /* I: Path to file */
UCHAR *pszFile, /* I: File to validate */
UINT nWriteFlag ) /* I: Read = 0, Write = 1 */
{
/* Local variables.
*/
int nReturn = SDD_FAIL;
UCHAR szTmpBuf[MAX_TMPBUFLEN];
UCHAR *szFunc = "_SCMD_ValidateFile";
struct stat sStat;
FILE *fpTest;
/* Concatenate the file and path together, ready to perform a test.
*/
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
sprintf(szTmpBuf, "%s//%s", pszPath, pszFile);
#endif
#if defined(_WIN32)
sprintf(szTmpBuf, "%s%c%s", pszPath, 0x5c, pszFile);
#endif
/* Is the file to be created?
*/
if(nWriteFlag == TRUE)
{
/* Test the file by trying to create it, see if the underlying OS
* can perform this operation.
*/
if((fpTest=fopen(szTmpBuf, "w")) != NULL)
{
/* Close and remove the file we created, not needed yet.
*/
fclose(fpTest);
unlink(szTmpBuf);
nReturn = SDD_OK;
} else
{
nReturn = SDD_FAIL;
}
} else
{
/* Test the file to ensure that it exists and is readable.
*/
if( (stat(szTmpBuf, &sStat) == -1) ||
((sStat.st_mode & S_IFREG) == 0) )
{
nReturn=SDD_FAIL;
} else
{
nReturn=SDD_OK;
}
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _SCMD_ValidateTime
* Description: Function to validate a time value given as an ascii string.
*
* Returns: SDD_FAIL- Couldnt obtain a TIME or validate it.
* SDD_OK - TIME obtained and validated.
******************************************************************************/
int _SCMD_ValidateTime( UCHAR *pszTime, /* I: Time to verify */
ULNG *lTime ) /* O: Time in seconds */
{
/* Local variables.
*/
int nReturn = SDD_FAIL;
UCHAR *szFunc = "_SCMD_ValidateTime";
/* Convert the time value into a long value which represents the
* number of seconds since the beginning of the machine date start
* point (ie. 0:00 Jan 1970 for PCDOS).
*/
nReturn=SDD_OK;
/* Return result code to caller.
*/
return(SDD_OK);
}
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
/******************************************************************************
* Function: _SCMD_Exec
* Description: Function to execute a given command via a fork and exec,
* attaching the parent to the childs I/O so that any data
* output by the child can be captured by the parent and fed
* back to the caller.
*
* Returns: SDD_FAIL- Command failed during execution.
* SDD_OK - Command executed successfully.
******************************************************************************/
int _SCMD_Exec( int nTimedExec, /* I: Is this a timed exec (T/F)? */
UCHAR *pszPath, /* I: Path to command */
UCHAR *pszCmd, /* I: Command name */
UCHAR *pszArgs, /* I: Arguments to command */
ULNG lTimeToExec, /* I: Time to execution */
int (*fSendDataCB)(UCHAR *, UINT),
/* I: Func for returning data */
UCHAR *szErrMsg ) /* O: Error message generated */
{
/* Local variables.
*/
int nChar;
int nEnd = FALSE;
int nNdx;
int nResult;
int nRetBufSize;
int nReturn = SDD_OK;
UCHAR *pszTmpBuf;
UCHAR *pszRetBuf;
UCHAR *szFunc = "_SCMD_Exec";
FILE *fpStdIn;
/* Work out return buffer memory based on mode and return buffer size.
*/
if(SCMD.nRetMode == SCMD_BINMODE)
{
nRetBufSize = SCMD.nRetBufSize+1;
} else
{
nRetBufSize = MAX_RETURN_BUF_SIZE+1;
}
/* Allocate memory for return buffer.
*/
if((pszRetBuf=(UCHAR *)malloc(nRetBufSize)) == NULL)
{
return(SDD_FAIL);
}
/* Is this a timed execution?
*/
if(nTimedExec == TRUE)
{
sleep(1);
}
/* Concatenate the file, command and arguments to build up a string
* for the system command to use.
*/
nNdx=strlen(pszPath)+strlen(pszCmd)+strlen(pszArgs)+10;
if((pszTmpBuf=(UCHAR *)malloc(nNdx)) == NULL)
{
return(SDD_FAIL);
}
sprintf(pszTmpBuf, "%s//%s %s", pszPath, pszCmd, pszArgs);
/* Execute the program as a child with its stdout connected to a read
* stream such that we can capture its output.
*/
if((fpStdIn=popen(pszTmpBuf, "r")) != NULL)
{
while(nEnd == FALSE)
{
/* Initialise loop variables.
*/
nNdx=1;
/* Loop until our return buffer becomes full or we run out of data
* to read.
*/
while(nNdx < nRetBufSize && (nChar=fgetc(fpStdIn)) != EOF)
{
pszRetBuf[nNdx] = (UCHAR)nChar;
nNdx++;
/* If we are in ascii mode and we detect an end of line then
* exit from the loop.
*/
if(SCMD.nRetMode == SCMD_ASCIIMODE && pszRetBuf[nNdx-1] == '\n')
break;
}
/* Has the child completed, i.e. no more data?
*/
if(nChar == EOF)
{
/* Set flag to indicate that we have reached end of input.
*/
nEnd = TRUE;
}
/* If data exists in the buffer for xmit, then transmit it.
*/
if(nNdx > 1)
{
/* Set the first location in the return buffer to indicate
* that this is just one of many data blocks in consecutive
* order.
*/
pszRetBuf[0] = SDD_DATABLOCK;
/* Call function to transmit row to original caller.
*/
if(fSendDataCB(pszRetBuf, nNdx) == SDD_FAIL)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg,
"%s: Failed to send row back to client",
SDD_EMSG_SENDROW);
nReturn = SDD_FAIL;
nEnd = TRUE;
}
}
}
/* Close the process and get its exit code.
*/
nResult=pclose(fpStdIn);
/* If we completed without error, then build a final packet
* to indicate the exit code of the process.
*/
if(nEnd == TRUE && nReturn != SDD_FAIL)
{
/* Create the packet for transmit based on the end of data
* indicator and an ascii representation of the exit code.
*/
pszRetBuf[0] = SDD_ENDBLOCK;
sprintf(&pszRetBuf[1], "%d", nResult);
/* Send the packet and see what happens.
*/
if(fSendDataCB(pszRetBuf, (strlen(&pszRetBuf[1])+1)) == SDD_FAIL)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg,
"%s: Failed to send row back to client",
SDD_EMSG_SENDROW);
nReturn = SDD_FAIL;
}
}
} else
{
/* Build up an error message to indicate that the command was
* invalid.
*/
sprintf(szErrMsg, "%s: Command execution failed", SDD_EMSG_BADCMD);
/* Set exit code to indicate failure.
*/
nReturn = SDD_FAIL;
}
/* Free up allocated memory block.
*/
free(pszTmpBuf);
/* Return result code to caller.
*/
return(nReturn);
}
#endif
/******************************************************************************
* Function: _SCMD_GetWriteData
* Description: Function to scan an input buffer, verify that it has data in it,
* extract the data and store in the opened file stream and
* set the start flag if the block is the final block.
*
* Returns: SDD_FAIL- Bad block of data or error writing to file.
* SDD_OK - Block obtained and stored.
******************************************************************************/
int _SCMD_GetWriteData( UCHAR *snzDataBuf, /* I: Input buffer */
int nDataLen, /* I: Len of data */
FILE *fpFile, /* IO: Opened file stream */
int *nLast, /* O: Last block flag */
UCHAR *szErrMsg ) /* O: Any resultant error msg */
{
/* Local variables.
*/
int nBlockSize;
int nCmpDataLen;
int nCmpEndLen;
int nPos;
int nReturn = SDD_FAIL;
UCHAR *szFunc = "_SCMD_GetWriteData";
/* Initialise any required variables.
*/
*nLast = FALSE;
nCmpDataLen=strlen(SCMD_DATA);
nCmpEndLen=strlen(SCMD_END);
/* Go through the input buffer looking for SCMD_DATA or SCMD_END within the
* input buffer. If either exist then note position just after it
* as this contains the size of the data block as an ascii number. If
* SCMD_END is detected then set the nLast flag to indicate last block.
*/
for(nPos=0; nPos < nDataLen; nPos++)
{
/* If a match occurs, then setup the pointer to correct location.
*/
if(strncmp(&snzDataBuf[nPos], SCMD_DATA, nCmpDataLen) == 0 ||
strncmp(&snzDataBuf[nPos], SCMD_END, nCmpEndLen) == 0)
{
/* Make sure that the match is not a sub-match as some of the
* variables we are scanning for are similar.
*/
if( (nPos == 0) ||
(nPos > 0 && snzDataBuf[nPos-1] == '\0') ||
(nPos > 0 && isspace(snzDataBuf[nPos-1])) )
{
if(strncmp(&snzDataBuf[nPos], SCMD_DATA, nCmpDataLen) == 0)
{
nPos += nCmpDataLen;
} else
{
/* Setup the nLast flag as this is the last data block.
*/
*nLast = TRUE;
nPos += nCmpEndLen;
}
break;
}
}
}
/* If the pointer did not reach the end of the buffer then we have
* located a valid data block.
*/
if(nPos < nDataLen)
{
/* The following location upto a NULL byte should contain the
* size of the data block in ASCII representation so use scanf
* to extract the data accordingly.
*/
if(sscanf(&snzDataBuf[nPos], "%d", &nBlockSize) != 1)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg, "%s: Invalid Block Size provided",
SDD_EMSG_BADBLOCKSZ);
nReturn = SDD_FAIL;
goto _SCMD_GetWriteData_EXIT;
}
/* Update our index variable.
*/
nPos += (strlen(&snzDataBuf[nPos]) + 1);
/* Quick test before we go any further, ensure that the data
* provided is sufficient.
*/
if((nPos+nBlockSize) != nDataLen)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg,
"%s: Data block size does not match data provided",
SDD_EMSG_BADBLOCKSZ);
nReturn = SDD_FAIL;
goto _SCMD_GetWriteData_EXIT;
}
/* Read data byte at a time and write to the opened file stream.
*/
while(nPos < nDataLen)
{
if(fputc(snzDataBuf[nPos], fpFile) == EOF)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg,
"%s: Couldnt write to temporary file to store data",
SDD_EMSG_FILEERROR);
nReturn = SDD_FAIL;
break;
}
/* Time for pointer update... Could write the same data forever
* I suppose....
*/
nPos += 1;
}
}
/* I suppose we are successful.... this time!
*/
nReturn=SDD_OK;
_SCMD_GetWriteData_EXIT:
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _SCMD_PutReadData
* Description: Function to read an open stream and transmit the data
* contents to the caller via the callback mechanism.
*
* Returns: SDD_FAIL- Couldnt obtain PATH.
* SDD_OK - PATH obtained.
******************************************************************************/
int _SCMD_PutReadData( FILE *fpFile, /* I: Stream to read from */
int (*fSendDataCB)(UCHAR *, UINT),
/* I: CB to send data to */
UCHAR *szErrMsg ) /* O: Error text */
{
/* Local variables.
*/
int nChar;
int nEnd = FALSE;
int nNdx;
int nReturn;
UCHAR szRetBuf[SCMD.nRetBufSize+1];
UCHAR *szFunc = "_SCMD_PutReadData";
/* Loop, extracting data from the input stream and sending it to the
* users callback in packets of size indicated by SCMD.nRetBufSize.
*/
while(nEnd == FALSE)
{
/* Initialise any loop variables.
*/
nNdx=1;
/* Loop until the return buffer becomes full or we run out of data.
*/
while(nNdx < SCMD.nRetBufSize && (nChar=fgetc(fpFile)) != EOF)
{
szRetBuf[nNdx] = (UCHAR)nChar;
nNdx++;
}
/* Is this the end of the input stream?
*/
if(nChar == EOF)
{
/* Set flag as we've got to end of the file, time to get out.
*/
nEnd = TRUE;
/* Set the first location in the input buffer to indicate last
* block.
*/
szRetBuf[0] = SDD_ENDBLOCK;
} else
{
/* Set the first location in the input buffer to indicate that
* this is one of many data blocks.
*/
szRetBuf[0] = SDD_DATABLOCK;
}
/* Call function to transmit row to original caller.
*/
if(fSendDataCB(szRetBuf, nNdx) == SDD_FAIL)
{
/* Create an error message to indicate the problem.
*/
sprintf(szErrMsg,
"%s: Failed to send row back to client", SDD_EMSG_SENDROW);
nReturn = SDD_FAIL;
nEnd = TRUE;
}
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _SCMD_MoveFile
* Description: Function to move a file from one location/name to another.
* This is performed as a copy and unlink operation because the
* underlying may not support moves across file systems.
*
* Returns: SDD_FAIL- An error whilst moving file, see szErrMsg.
* SDD_OK - File moved successfully.
******************************************************************************/
int _SCMD_MoveFile( UCHAR *pszSrcPath, /* I: Path to source file */
UCHAR *pszSrcFile, /* I: Source File */
UCHAR *pszDstPath, /* I: Path to dest file */
UCHAR *pszDstFile, /* I: Dest File */
UCHAR *szErrMsg ) /* O: Error message */
{
/* Local variables.
*/
int nChar;
int nReturn = SDD_OK;
UCHAR szSourceFile[MAX_FILENAME_LEN+1];
UCHAR szDestFile[MAX_FILENAME_LEN+1];
UCHAR *szFunc = "_SCMD_MoveFile";
FILE *fpDestFile;
FILE *fpSourceFile;
/* Combine path and filename to create an absolute source filename.
*/
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
sprintf(szSourceFile, "%s//%s", pszSrcPath, pszSrcFile);
#endif
#if defined(_WIN32)
sprintf(szSourceFile, "%s%c%s", pszSrcPath, 0x5c, pszSrcFile);
#endif
/* Combine path and filename to create an absolute destination filename.
*/
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
sprintf(szDestFile, "%s//%s", pszDstPath, pszDstFile);
#endif
#if defined(_WIN32)
sprintf(szDestFile, "%s%c%s", pszDstPath, 0x5c, pszDstFile);
#endif
/* Open source file ready for copy operation.
*/
if((fpSourceFile=fopen(szSourceFile, "r")) == NULL)
{
sprintf(szErrMsg, "%s: Couldnt open source file (%s)", szSourceFile);
return(SDD_FAIL);
}
/* Open destination file ready to accept copied data.
*/
if((fpDestFile=fopen(szDestFile, "w")) == NULL)
{
fclose(fpSourceFile);
sprintf(szErrMsg, "%s: Couldnt create destination file (%s)",
szDestFile);
return(SDD_FAIL);
}
/* Copy data byte by byte, checking for accuracy.
*/
while((nChar=fgetc(fpSourceFile)) != EOF)
{
/* Put the newly read byte into the destination file and check return
* status. If the put fails, exit with error.
*/
if(fputc((UCHAR)nChar, fpDestFile) == EOF)
{
/* Close files, and delete destination.
*/
fclose(fpSourceFile);
fclose(fpDestFile);
unlink(szDestFile);
/* Build up error message and exit.
*/
sprintf(szErrMsg, "%s: Error writing to destination file (%s)",
szDestFile);
return(SDD_FAIL);
}
}
/* All done, first close and confirm destination file, then close and
* delete source file.
*/
fclose(fpSourceFile);
if(fclose(fpDestFile) == EOF)
{
sprintf(szErrMsg, "%s: Error writing to destination file (%s)",
szDestFile);
return(SDD_FAIL);
}
unlink(szSourceFile);
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: _SCMD_DeleteFile
* Description: Function to delete a file from the given path.
*
* Returns: SDD_FAIL- An error whilst moving file, see szErrMsg.
* SDD_OK - File moved successfully.
******************************************************************************/
int _SCMD_DeleteFile( UCHAR *pszDelPath, /* I: Path to file */
UCHAR *pszDelFile, /* I: File to delete */
UCHAR *szErrMsg ) /* O: Error message */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UCHAR szDeleteFile[MAX_FILENAME_LEN+1];
UCHAR *szFunc = "_SCMD_DeleteFile";
/* Combine path and filename to create an absolute filename for deletion.
*/
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
sprintf(szDeleteFile, "%s//%s", pszDelPath, pszDelFile);
#endif
#if defined(_WIN32)
sprintf(szDeleteFile, "%s%c%s", pszDelPath, 0x5c, pszDelFile);
#endif
/* Call the operating system to perform the actual operation.
*/
unlink(szDeleteFile);
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: scmd_InitService
* Description: Entry point which initialises the driver into a defined state.
* It is mandatory that this function is called before any other
* in order for the driver to function correctly. The caller
* provides it with two types of data, 1) A structure containing
* data for it to use in initialising itself, 2) a pointer to a
* buffer which the driver uses to place an error message should
* it not be able to complete initialisation.
*
* Returns: SDD_FAIL- An error occurred in initialising the driver and an
* error message is stored in szErrStr.
* SDD_OK - Driver initialised successfully.
******************************************************************************/
int scmd_InitService( SERVICEDETAILS *sServiceDet, /* I: Init data */
UCHAR *szErrStr ) /* O: Error message */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UCHAR *szFunc = "scmd_InitService";
/* Log if debugging switched on.
*/
Lgr(LOG_MESSAGE, szFunc, "SCMD Driver: Initialised:");
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: scmd_CloseService
* Description: Entry point which performs a drive closedown. The closedown
* procedure ensure that the driver returns to a virgin state
* (ie.like at power up) so that InitService can be called again.
*
* Returns: SDD_FAIL- An error occurred in closing the driver and an
* error message is stored in szErrStr.
* SDD_OK - Driver successfully closed.
******************************************************************************/
int scmd_CloseService( UCHAR *szErrMsg ) /* O: Error message if failed */
{
/* Local variables.
*/
int nReturn = SDD_OK;
UCHAR *szFunc = "scmd_CloseService";
/* Log if debugging switched on.
*/
Lgr(LOG_MESSAGE, szFunc, "SCMD Driver: Closed.");
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: scmd_ProcessRequest
* Description: Entry point into driver to initiate the driver into
* processing a request. A data block is passed as a parameter
* to the driver which represents a request with relevant
* parameters. The data within the structure is only relevant
* to the original client and this driver code.
*
* Returns: SDD_FAIL- An error occurred within the driver whilst trying to
* process the request, see error text.
* SDD_OK - Request processed successfully.
******************************************************************************/
int scmd_ProcessRequest( UCHAR *snzDataBuf, /* I: Input data */
int nDataLen, /* I: Len of data */
int (*fSendDataCB)(UCHAR *, UINT),
/* I: CB to send reply*/
UCHAR *szErrMsg ) /* O: Error text */
{
/* Static variables.
*/
static UCHAR szWriteFile[MAX_FILENAME_LEN+1];
static FILE *fpWriteFile = NULL;
/* Local variables.
*/
int nLastBlock;
int nReturn = SDD_OK;
ULNG lTime = 0;
UCHAR *pszDstFile;
UCHAR *pszSrcFile;
UCHAR *pszDstPath;
UCHAR *pszSrcPath;
UCHAR *pszArgs;
UCHAR *pszBufSize;
UCHAR *pszCmd;
UCHAR *pszMode;
UCHAR *pszTime;
UCHAR szReadFile[MAX_FILENAME_LEN+1];
UCHAR *szFunc = "scmd_ProcessRequest";
FILE *fpReadFile;
/* If the request block doesnt contain any data, something went wrong
* somewhere?
*/
if(nDataLen <= 1)
{
sprintf(szErrMsg,
"%s: Illegal request, has size of %dBytes",
SDD_EMSG_BADREQ, nDataLen);
return(SDD_FAIL);
}
/* If we have an EXECUTE command, then extract relevant information from
* buffer.
*/
if(snzDataBuf[0] == SDD_CMD_EXEC || snzDataBuf[0] == SDD_CMD_EXEC_TIMED)
{
/* Locate the path argument and validate it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_SRCPATH,
&pszSrcPath) == SDD_FAIL||
_SCMD_ValidatePath(pszSrcPath) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid PATH to command provided",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
/* Locate the command argument and validate it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_CMD, &pszCmd)
== SDD_FAIL ||
_SCMD_ValidateFile(pszSrcPath, pszCmd, FALSE) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid COMMAND provided",
SDD_EMSG_BADCMD);
return(SDD_FAIL);
}
/* Locate the mode flag (ASCII or BINARY) and if present ensure
* it is valid.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_MODE, &pszMode)
== SDD_OK)
{
/* Is the parameter valid?
*/
if( strcmp(pszMode, SCMD_BINARY) != 0 &&
strcmp(pszMode, SCMD_ASCII) !=0 )
{
sprintf(szErrMsg, "%s: Invalid MODE provided", SDD_EMSG_BADCMD);
return(SDD_FAIL);
}
/* Setup parameter accordingly.
*/
if( strcmp(pszMode, SCMD_BINARY) == 0 )
{
SCMD.nRetMode = SCMD_BINMODE;
} else
SCMD.nRetMode = SCMD_ASCIIMODE;
} else
{
/* Setup the default return buffer mode.
*/
SCMD.nRetMode = DEF_RETURN_MODE;
}
/* Locate the buffer size flag and if present, ensure its within range.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1,SCMD_BUFSIZE,&pszBufSize)
== SDD_OK )
{
/* Get the value passed to verify and store.
*/
sscanf(pszBufSize, "%d", &SCMD.nRetBufSize);
if( SCMD.nRetBufSize < MIN_RETURN_BUF_SIZE ||
SCMD.nRetBufSize > MAX_RETURN_BUF_SIZE )
{
sprintf(szErrMsg, "%s: Invalid MODE provided", SDD_EMSG_BADCMD);
return(SDD_FAIL);
}
} else
{
/* Setup the default return buffer size.
*/
SCMD.nRetBufSize = DEF_RETURN_BUF_SIZE;
}
/* Locate the Args argument.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_ARGS, &pszArgs)
== SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid command ARGS provided",
SDD_EMSG_BADARGS);
return(SDD_FAIL);
}
/* For timed EXECUTION commands, get the time value.
*/
if(snzDataBuf[0] == SDD_CMD_EXEC_TIMED)
{
/* Locate the Time argument in the input buffer, validate that it
* is for a time in the future and setup our pointer into it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_TIME, &pszTime)
== SDD_FAIL ||
_SCMD_ValidateTime(pszTime, &lTime) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid TIME value provided",
SDD_EMSG_BADARGS);
return(SDD_FAIL);
}
}
}
/* If we have a READ/MOVE command, then extract relevant information from
* buffer.
*/
if(snzDataBuf[0] == SDD_CMD_READ || snzDataBuf[0] == SDD_CMD_MOVE)
{
/* Locate the path argument and validate it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_SRCPATH,
&pszSrcPath) == SDD_FAIL ||
_SCMD_ValidatePath(pszSrcPath) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid Source PATH provided",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
/* Locate the file argument and validate it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_SRCFILE,
&pszSrcFile) == SDD_FAIL ||
_SCMD_ValidateFile(pszSrcPath, pszSrcFile, FALSE) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid Source FILE provided",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
}
/* If we have a DELETE/MOVE command, then extract relevant information
* from buffer.
*/
if(snzDataBuf[0] == SDD_CMD_DEL || snzDataBuf[0] == SDD_CMD_MOVE)
{
/* Locate the path argument and validate it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_DSTPATH,
&pszDstPath) == SDD_FAIL ||
_SCMD_ValidatePath(pszDstPath) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid Destination PATH provided",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
/* Locate the file argument and validate it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_DSTFILE,
&pszDstFile) == SDD_FAIL ||
_SCMD_ValidateFile(pszDstPath, pszDstFile,
(snzDataBuf[0] == SDD_CMD_DEL ? FALSE : TRUE))
== SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid Destination FILE provided",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
}
/* First byte of the request data block indicates actions required, so
* decipher it.
*/
switch(snzDataBuf[0])
{
case SDD_CMD_EXEC:
/* Log if debugging switched on.
*/
Lgr(LOG_DEBUG, szFunc,
"SCMD Driver: Req to execute COMMAND");
Lgr(LOG_DEBUG, szFunc,
"Command: Path=%s, Cmd=%s, Args=%s",
pszSrcPath, pszCmd, pszArgs);
/* Execute the required command. Any output generated by the
* command is fed back to the caller row-at-a-time. The final
* exit status dictates wether the command was a success or
* failure.
*/
if(_SCMD_Exec(FALSE,pszSrcPath,pszCmd,pszArgs,0,fSendDataCB,
szErrMsg) == SDD_FAIL)
{
return(SDD_FAIL);
}
break;
case SDD_CMD_EXEC_TIMED:
/* Log if debugging switched on.
*/
Lgr(LOG_DEBUG, szFunc,
"SCMD Driver: Req to execute timed COMMAND");
Lgr(LOG_DEBUG, szFunc,
"Command: Path=%s, Cmd=%s, Args=%s, Time=%ld",
pszSrcPath, pszCmd, pszArgs, lTime);
/* Execute the required command at the given time, and upon
* command completion return the status to the caller via a return
* code and text message.
*/
if(_SCMD_Exec(TRUE,pszSrcPath,pszCmd,pszArgs,lTime,fSendDataCB,
szErrMsg) == SDD_FAIL)
{
return(SDD_FAIL);
}
break;
case SDD_CMD_READ:
/* Log if debugging switched on.
*/
Lgr(LOG_DEBUG, szFunc,
"SCMD Driver: Requested to perform a READ operation");
/* Open the file as indicated by the command parameters.
*/
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
sprintf(szReadFile, "%s//%s", pszSrcPath, pszSrcFile);
#endif
#if defined(_WIN32)
sprintf(szReadFile, "%s%c%s", pszSrcPath, 0x5c, pszSrcFile);
#endif
if((fpReadFile=fopen(szReadFile, "r")) == NULL)
{
/* Create a message to indicate failure.
*/
sprintf(szErrMsg,
"%s: Illegal Filename given in command",
SDD_EMSG_BADFILE);
/* Exit directly as we have nothing open to tidy up.
*/
return(SDD_FAIL);
}
/* Copy the requested file from opened file stream to the remote
* via a return byte stream.
*/
nReturn=_SCMD_PutReadData(fpReadFile, fSendDataCB, szErrMsg);
/* Close the file as were all done, then exit.
*/
fclose(fpReadFile);
break;
case SDD_CMD_WRITE:
/* If this is the first time we've been called then process
* options and open the indicated file for writing.
*/
if(fpWriteFile == NULL)
{
/* Log if debugging switched on.
*/
Lgr(LOG_DEBUG, szFunc,
"SCMD Driver: Requested to perform a WRITE operation");
/* Locate the path argument and validate it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_DSTPATH,
&pszDstPath) == SDD_FAIL ||
_SCMD_ValidatePath(pszDstPath) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid Destination PATH provided",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
/* Locate the file argument and validate it.
*/
if(_SCMD_GetStrArg(&snzDataBuf[1], nDataLen-1, SCMD_DSTFILE,
&pszDstFile) == SDD_FAIL ||
_SCMD_ValidateFile(pszDstPath, pszDstFile, TRUE) == SDD_FAIL)
{
sprintf(szErrMsg, "%s: Invalid Destination FILE provided",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
/* Create new file for writing.
*/
#if defined(SOLARIS) || defined(SUNOS) || defined(LINUX)
sprintf(szWriteFile, "%s//%s", pszDstPath, pszDstFile);
#endif
#if defined(_WIN32)
sprintf(szWriteFile, "%s%c%s", pszDstPath, 0x5c, pszDstFile);
#endif
if((fpWriteFile=fopen(szWriteFile, "w")) == NULL)
{
/* Create message to indicate failure.
*/
sprintf(szErrMsg, "%s: Couldnt create file",
SDD_EMSG_BADPATH);
return(SDD_FAIL);
}
} else
{
/* Extract the data from the passed buffer and store in the
* opened file. Make a note as to wether this is the last
* block or not.
*/
if(_SCMD_GetWriteData(&snzDataBuf[1], (nDataLen-1), fpWriteFile,
&nLastBlock, szErrMsg) == SDD_FAIL)
{
/* Tidy up as we are not coming back!!!!
*/
fclose(fpWriteFile);
fpWriteFile = NULL;
/* Delete the file as theres no point in keeping half a
* file.
*/
unlink(szWriteFile);
/* Exit with the bad tidings in szErrMsg.
*/
return(SDD_FAIL);
}
/* If we wrote the last block successfully then alles klare,
* wunderbar!.
*/
if(nLastBlock == TRUE)
{
/* Firstly, close the opened file and reset the pointer for
* next time.
*/
fclose(fpWriteFile);
fpWriteFile = NULL;
}
}
break;
case SDD_CMD_MOVE:
/* Log if debugging switched on.
*/
Lgr(LOG_DEBUG, szFunc,
"SCMD Driver: Requested to perform a MOVE operation");
/* Call function to perform the move and use its return code
* as our return code.
*/
nReturn=_SCMD_MoveFile(pszSrcPath, pszSrcFile, pszDstPath,
pszDstFile, szErrMsg);
break;
case SDD_CMD_DEL:
/* Log if debugging switched on.
*/
Lgr(LOG_DEBUG, szFunc,
"SCMD Driver: Requested to perform a DELETE operation");
/* Call function to perform the move and use its return code
* as our return code.
*/
nReturn=_SCMD_DeleteFile(pszDstPath, pszDstFile, szErrMsg);
break;
default:
sprintf(szErrMsg,
"%s: Illegal command in request buffer (%x)",
SDD_EMSG_BADREQ, snzDataBuf[0]);
return(SDD_FAIL);
}
/* Return result code to caller.
*/
return(nReturn);
}
/******************************************************************************
* Function: scmd_ProcessOOB
* Description: Entry point into driver to process an out of band command
* that may or may not be relevant to current state of
* operation. The task of this function is to decipher the
* command and act on it immediately, ie. a cancel command
* would abort any ProcessRequest that is in process and
* clean up.
*
* Returns: No returns.
******************************************************************************/
void scmd_ProcessOOB( UCHAR nCommand ) /* I: OOB Command */
{
/* Local variables.
*/
/* Decipher command and perform actions accordingly.
*/
switch(nCommand)
{
/* Request to abort current ProcessRequest command and return daemon
* to a waiting-for-request state.
*/
case SDD_ABORT:
break;
/* Request to close down and exit.
*/
case SDD_EXIT:
break;
default:
break;
}
/* Return to caller.
*/
return;
}