/*- *********************************************************************** * * $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); }