/*-
***********************************************************************
*
* $Id: pad-binary-guts.c,v 1.10 2006/05/25 22:17:28 mavrik Exp $
*
***********************************************************************
*
* Copyright 2002-2006 The WebJob Project, All Rights Reserved.
*
***********************************************************************
*/
#include "pad-common.h"
#include "pad-binary-guts.h"
/*-
***********************************************************************
*
* Global Variables.
*
***********************************************************************
*/
void *gpvProperties;
PAD_CALL_TABLE gsCallTable[] =
{
{ PAD_VOID_CALL main, "PaDMain()" },
{ PAD_VOID_CALL PaDBootStrap, "PaDBootStrap()" },
{ PAD_VOID_CALL PaDBuildCmdLine, "PaDBuildCmdLine()" },
{ PAD_VOID_CALL PaDCalculateCmdLineLength, "PaDCalculateCmdLineLength()" },
{ PAD_VOID_CALL PaDCheckBasename, "PaDCheckBasename()" },
{ PAD_VOID_CALL PaDCheckSuffix, "PaDCheckSuffix()" },
{ PAD_VOID_CALL PaDDeliverPayload, "PaDDeliverPayload()" },
{ PAD_VOID_CALL PaDExtractPayload, "PaDExtractPayload()" },
{ PAD_VOID_CALL PaDGetBasename, "PaDGetBasename()" },
{ PAD_VOID_CALL PaDGetCallname, "PaDGetCallname()" },
{ PAD_VOID_CALL PaDGetEnvValue, "PaDGetEnvValue()" },
{ PAD_VOID_CALL PaDGetMyHandle, "PaDGetMyHandle()" },
{ PAD_VOID_CALL PaDGetPropertiesReference, "PaDGetPropertiesReference()" },
{ PAD_VOID_CALL PaDLocateDelimiter, "PaDLocateDelimiter()" },
{ PAD_VOID_CALL PaDNewDelimiter, "PaDNewDelimiter()" },
{ PAD_VOID_CALL PaDNewProperties, "PaDNewProperties()" },
{ PAD_VOID_CALL PaDProcessArguments, "PaDProcessArguments()" },
{ PAD_VOID_CALL PaDReadWrite, "PaDReadWrite()" },
{ PAD_VOID_CALL PaDSetPropertiesReference, "PaDSetPropertiesReference()" },
{ PAD_VOID_CALL PaDShutdown, "PaDShutdown()" }
};
int giNCalls = (sizeof(gsCallTable) / sizeof(gsCallTable[0]));
/*-
***********************************************************************
*
* PaDMain
*
***********************************************************************
*/
int
main(int iArgumentCount, char *ppcArgumentVector[])
{
void (*pvCall)() = PAD_VOID_CALL main;
char acLocalError[MESSAGE_SIZE];
int iError;
int iIndex;
int iNeedXBit;
PAD_GUTS_PROPERTIES *psProperties;
/*-
*********************************************************************
*
* Punch in and go to work.
*
*********************************************************************
*/
iError = PaDBootStrap(acLocalError);
if (iError != ER_OK)
{
fprintf(stderr, "%s: %s\n", PaDGetCallname(pvCall), acLocalError);
PaDShutdown(XER_BootStrap);
}
psProperties = (PAD_GUTS_PROPERTIES *) PaDGetPropertiesReference();
/*-
*********************************************************************
*
* Process command line arguments.
*
*********************************************************************
*/
iError = PaDProcessArguments(iArgumentCount, ppcArgumentVector, psProperties, acLocalError);
if (iError != ER_OK)
{
fprintf(stderr, "%s: %s\n", PaDGetCallname(pvCall), acLocalError);
PaDShutdown(XER_ProcessArguments);
}
/*-
*********************************************************************
*
* Check suffix.
*
*********************************************************************
*/
iIndex = PaDCheckSuffix(ppcArgumentVector[0], PAD_SUFFIX, acLocalError);
if (iIndex == ER)
{
fprintf(stderr, "%s: %s\n", PaDGetCallname(pvCall), acLocalError);
PaDShutdown(XER_Suffix);
}
psProperties->pcPayload[iIndex] = 0; /* Chop off suffix. */
/*-
*********************************************************************
*
* Check basename.
*
*********************************************************************
*/
iError = PaDCheckBasename(psProperties->pcPayload, acLocalError);
if (iError != ER_OK)
{
fprintf(stderr, "%s: %s\n", PaDGetCallname(pvCall), acLocalError);
PaDShutdown(XER_Basename);
}
/*-
*********************************************************************
*
* Locate delimiter, and seek past it.
*
*********************************************************************
*/
iError = PaDLocateDelimiter(psProperties->pFilePaD, psProperties->pcDelimiter, acLocalError);
if (iError != ER_OK)
{
fprintf(stderr, "%s: %s\n", PaDGetCallname(pvCall), acLocalError);
PaDShutdown(XER_Delimiter);
}
/*-
*********************************************************************
*
* Extract payload.
*
*********************************************************************
*/
if (psProperties->iMute == PAD_MUTE_OFF)
{
fprintf(stderr, "Extracting payload...\n");
}
iError = PaDExtractPayload(psProperties, acLocalError);
if (iError != ER_OK)
{
fprintf(stderr, "%s: %s\n", PaDGetCallname(pvCall), acLocalError);
PaDShutdown(XER_Extract);
}
/*-
*********************************************************************
*
* Conditionally, deliver payload.
*
*********************************************************************
*/
if (iArgumentCount > 1)
{
psProperties->iUnlinkPayload = 1;
iNeedXBit = PaDBuildCmdLine(iArgumentCount, ppcArgumentVector, psProperties->pcPayload, psProperties->pcCmdLine);
if (psProperties->iMute == PAD_MUTE_OFF)
{
fprintf(stderr, "Delivering payload... %s\n", psProperties->pcCmdLine);
}
iError = PaDDeliverPayload(psProperties->pcPayload, iNeedXBit, psProperties->pcCmdLine, acLocalError);
if (iError == ER)
{
fprintf(stderr, "%s: %s\n", PaDGetCallname(pvCall), acLocalError);
PaDShutdown(XER_Deliver);
}
if (psProperties->iMute == PAD_MUTE_OFF)
{
fprintf(stderr, "DeliveryStatus='%d'\n", iError);
}
}
/*-
*********************************************************************
*
* Shutdown and go home.
*
*********************************************************************
*/
PaDShutdown(XER_OK);
return XER_OK;
}
/*-
***********************************************************************
*
* PaDBootStrap
*
***********************************************************************
*/
int
PaDBootStrap(char *pcError)
{
void (*pvCall)() = PAD_VOID_CALL PaDBootStrap;
char acLocalError[MESSAGE_SIZE];
char *pcValue = NULL;
PAD_GUTS_PROPERTIES *psProperties;
#ifdef UNIX
int i = 0;
int iLength = 0;
#endif
#ifdef WIN32
/*-
*********************************************************************
*
* Suppress critical-error-handler message boxes.
*
*********************************************************************
*/
SetErrorMode(SEM_FAILCRITICALERRORS);
#endif
/*-
*********************************************************************
*
* Allocate and initialize the properties structure.
*
*********************************************************************
*/
psProperties = (PAD_GUTS_PROPERTIES *) PaDNewProperties(sizeof(PAD_GUTS_PROPERTIES), acLocalError);
if (psProperties == NULL)
{
snprintf(pcError, MESSAGE_SIZE, "%s: %s", PaDGetCallname(pvCall), acLocalError);
return ER;
}
PaDSetPropertiesReference((void *) psProperties);
/*-
*********************************************************************
*
* Allocate and initialize the delimiter.
*
*********************************************************************
*/
psProperties->pcDelimiter = PaDNewDelimiter(PAD_GUTS_TEMPLATE, 1, acLocalError);
if (psProperties->pcDelimiter == NULL)
{
snprintf(pcError, MESSAGE_SIZE, "%s: %s", PaDGetCallname(pvCall), acLocalError);
return ER;
}
/*-
*********************************************************************
*
* Pull in envrionment variables.
*
*********************************************************************
*/
pcValue = PaDGetEnvValue("PAD_MUTE");
psProperties->iMute = (pcValue == NULL) ? PAD_MUTE_OFF : (strcmp(pcValue, "0") == 0) ? PAD_MUTE_OFF : PAD_MUTE_ON;
pcValue = PaDGetEnvValue("PAD_OVERWRITE");
psProperties->iOverwritePayload = (pcValue == NULL) ? PAD_OVERWRITE_ON : (strcmp(pcValue, "0") == 0) ? PAD_OVERWRITE_OFF : PAD_OVERWRITE_ON;
#ifdef UNIX
pcValue = PaDGetEnvValue("PAD_UMASK");
if (pcValue != NULL && (iLength = strlen(pcValue)) <= 4)
{
for (i = 0; i < iLength; i++)
{
if (!isdigit((int)pcValue[i]) || pcValue[i] > '7') /* Accept only octal digits. */
{
break;
}
}
if (i == iLength) /* We have 1-4 octal digits, so strtoul() should succeed. */
{
psProperties->ulUmask = strtoul(pcValue, NULL, 8);
}
}
else
{
psProperties->ulUmask = PAD_UMASK;
}
umask((mode_t)psProperties->ulUmask);
#endif
return ER_OK;
}
/*-
***********************************************************************
*
* PaDBuildCmdLine
*
***********************************************************************
*/
int
PaDBuildCmdLine(int iArgumentCount, char *ppcArgumentVector[], char *pcPayload, char *pcCmdLine)
{
char *pc;
int i;
int j;
int iNeedXBit;
int iIndex1;
int iIndex2;
int iLength;
pcCmdLine[0] = iNeedXBit = 0;
/*-
*********************************************************************
*
* Build a command line if there's enough arguments.
*
*********************************************************************
*/
if (iArgumentCount > 1)
{
if (strncmp(ppcArgumentVector[1], PAD_PAYLOAD_TOKEN, strlen(PAD_PAYLOAD_TOKEN)) == 0)
{
iNeedXBit = 1;
}
for (i = iIndex1 = iIndex2 = 0; i < iArgumentCount - 1; i++, iIndex1 = 0)
{
if (i > 0)
{
pcCmdLine[iIndex2++] = ' ';
}
while ((pc = strstr(&ppcArgumentVector[i + 1][iIndex1], PAD_PAYLOAD_TOKEN)) != NULL)
{
while (iIndex1 < (int)(pc - &ppcArgumentVector[i + 1][0]))
{
pcCmdLine[iIndex2++] = ppcArgumentVector[i + 1][iIndex1++];
}
iIndex2 += sprintf(&pcCmdLine[iIndex2], "%s", pcPayload);
iIndex1 += strlen(PAD_PAYLOAD_TOKEN);
}
iLength = strlen(&ppcArgumentVector[i + 1][iIndex1]);
for (j = 0; j < iLength; j++)
{
pcCmdLine[iIndex2++] = ppcArgumentVector[i + 1][iIndex1++];
}
pcCmdLine[iIndex2] = 0;
}
}
return iNeedXBit;
}
/*-
***********************************************************************
*
* PaDCalculateCmdLineLength
*
***********************************************************************
*/
int
PaDCalculateCmdLineLength(int iArgumentCount, char *ppcArgumentVector[])
{
char *pc;
int i;
int iDelta;
int iIndex;
int iLength;
int iMatches;
iDelta = strlen(ppcArgumentVector[0]) - strlen(PAD_PAYLOAD_TOKEN); /* This can be negative. */
for (i = iIndex = iLength = iMatches = 0; i < iArgumentCount - 1; i++, iIndex = iMatches = 0)
{
while ((pc = strstr(&ppcArgumentVector[i + 1][iIndex], PAD_PAYLOAD_TOKEN)) != NULL)
{
iMatches++;
iIndex = (pc - &ppcArgumentVector[i + 1][0]) + strlen(PAD_PAYLOAD_TOKEN);
}
iLength += ((i > 0) ? 1 : 0) + strlen(ppcArgumentVector[i + 1]) + (iDelta * iMatches);
}
return iLength;
}
/*-
***********************************************************************
*
* PaDCheckBasename
*
***********************************************************************
*/
int
PaDCheckBasename(char *pcPath, char *pcError)
{
void (*pvCall)() = PAD_VOID_CALL PaDCheckBasename;
char *pcBasename;
/*-
*********************************************************************
*
* Get basename, and make sure it's not NULL, DOT, or DOTDOT.
*
*********************************************************************
*/
pcBasename = PaDGetBasename(pcPath);
if (pcBasename[0] == 0 || strcmp(pcBasename, DOT) == 0 || strcmp(pcBasename, DOTDOT) == 0)
{
snprintf(pcError, MESSAGE_SIZE, "%s: Error='Invalid or missing basename.'", PaDGetCallname(pvCall));
return ER;
}
return ER_OK;
}
/*-
***********************************************************************
*
* PaDCheckSuffix
*
***********************************************************************
*/
int
PaDCheckSuffix(char *pcName, char *pcSuffix, char *pcError)
{
void (*pvCall)() = PAD_VOID_CALL PaDCheckSuffix;
int iIndex;
/*-
*********************************************************************
*
* Name must be at least as long as and equal to the suffix.
*
*********************************************************************
*/
iIndex = strlen(pcName) - strlen(pcSuffix);
if (iIndex < 0 || strcmp(&pcName[iIndex], pcSuffix) != 0)
{
snprintf(pcError, MESSAGE_SIZE, "%s: Error='Invalid or missing suffix.'", PaDGetCallname(pvCall));
return ER;
}
return iIndex;
}
/*-
***********************************************************************
*
* PaDDeliverPayload
*
***********************************************************************
*/
int
PaDDeliverPayload(char *pcPayload, int iNeedXBit, char *pcCmdLine, char *pcError)
{
void (*pvCall)() = PAD_VOID_CALL PaDDeliverPayload;
int iError;
#ifdef UNIX
struct stat statEntry;
if (iNeedXBit)
{
if (stat(pcPayload, &statEntry) == -1)
{
snprintf(pcError, MESSAGE_SIZE, "%s: stat(): File='%s' Error='%s'", PaDGetCallname(pvCall), pcPayload, strerror(errno));
return ER;
}
if ((statEntry.st_mode & S_IXUSR) != S_IXUSR)
{
statEntry.st_mode |= S_IXUSR;
if (chmod(pcPayload, statEntry.st_mode) == -1)
{
snprintf(pcError, MESSAGE_SIZE, "%s: chmod(): File='%s' Error='%s'", PaDGetCallname(pvCall), pcPayload, strerror(errno));
return ER;
}
}
}
#endif
iError = system(pcCmdLine);
if (iError == -1)
{
snprintf(pcError, MESSAGE_SIZE, "%s: system(): Command='%s' Error='%s'", PaDGetCallname(pvCall), pcCmdLine, strerror(errno));
return ER;
}
return iError;
}
/*-
***********************************************************************
*
* PaDExtractPayload
*
***********************************************************************
*/
int
PaDExtractPayload(PAD_GUTS_PROPERTIES *psProperties, char *pcError)
{
void (*pvCall)() = PAD_VOID_CALL PaDExtractPayload;
char acLocalError[MESSAGE_SIZE];
FILE *pFileFrom;
FILE *pFileTo;
int iError;
struct stat statEntry;
if (stat(psProperties->pcPayload, &statEntry) == 0 && psProperties->iOverwritePayload == 0)
{
snprintf(pcError, MESSAGE_SIZE, "%s: stat(): File='%s' Error='File exists and PAD_OVERWRITE is disabled. Extraction aborted.'", PaDGetCallname(pvCall), psProperties->pcPayload);
return ER;
}
pFileFrom = psProperties->pFilePaD;
pFileTo = fopen(psProperties->pcPayload, "wb");
if (pFileTo == NULL)
{
psProperties->iUnlinkPayload = 1;
snprintf(pcError, MESSAGE_SIZE, "%s: fopen(): File='%s' Error='%s'", PaDGetCallname(pvCall), psProperties->pcPayload, strerror(errno));
return ER;
}
iError = PaDReadWrite(pFileFrom, pFileTo, acLocalError);
if (iError != ER_OK)
{
psProperties->iUnlinkPayload = 1;
snprintf(pcError, MESSAGE_SIZE, "%s: %s:", PaDGetCallname(pvCall), acLocalError);
fclose(pFileTo);
return ER;
}
fclose(pFileTo);
return ER_OK;
}
/*-
***********************************************************************
*
* PaDProcessArguments
*
***********************************************************************
*/
int
PaDProcessArguments(int iArgumentCount, char *ppcArgumentVector[], PAD_GUTS_PROPERTIES *psProperties, char *pcError)
{
void (*pvCall)() = PAD_VOID_CALL PaDProcessArguments;
char acLocalError[MESSAGE_SIZE];
int iLength;
/*-
*********************************************************************
*
* Open a read handle for this program.
*
*********************************************************************
*/
psProperties->pFilePaD = PaDGetMyHandle(ppcArgumentVector[0], acLocalError);
if (psProperties->pFilePaD == NULL)
{
snprintf(pcError, MESSAGE_SIZE, "%s: %s", PaDGetCallname(pvCall), acLocalError);
return ER;
}
/*-
*********************************************************************
*
* Allocate and initialize the payload filename.
*
*********************************************************************
*/
iLength = strlen(ppcArgumentVector[0]) + 1;
psProperties->pcPayload = calloc(iLength, 1);
if (psProperties->pcPayload == NULL)
{
snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): Error='%s'", PaDGetCallname(pvCall), strerror(errno));
return ER;
}
strcpy(psProperties->pcPayload, ppcArgumentVector[0]);
/*-
*********************************************************************
*
* Allocate and initialize the delivery command.
*
*********************************************************************
*/
if (iArgumentCount > 1)
{
iLength = PaDCalculateCmdLineLength(iArgumentCount, ppcArgumentVector) + 1;
}
else
{
iLength = 1;
}
psProperties->pcCmdLine = calloc(iLength, 1);
if (psProperties->pcCmdLine == NULL)
{
snprintf(pcError, MESSAGE_SIZE, "%s: calloc(): Error='%s'", PaDGetCallname(pvCall), strerror(errno));
return ER;
}
return ER_OK;
}
/*-
***********************************************************************
*
* PaDShutdown
*
***********************************************************************
*/
void
PaDShutdown(int iError)
{
PAD_GUTS_PROPERTIES *psProperties;
psProperties = (PAD_GUTS_PROPERTIES *) PaDGetPropertiesReference();
if (psProperties != NULL)
{
if (psProperties->pFilePaD != NULL)
{
fclose(psProperties->pFilePaD);
}
if (psProperties->pcDelimiter != NULL)
{
free(psProperties->pcDelimiter);
}
if (psProperties->pcPayload != NULL)
{
if (psProperties->iUnlinkPayload)
{
unlink(psProperties->pcPayload);
}
free(psProperties->pcPayload);
}
if (psProperties->pcCmdLine != NULL)
{
free(psProperties->pcCmdLine);
}
free(psProperties);
}
exit(iError);
}
syntax highlighted by Code2HTML, v. 0.9.1