/* OSSP rc - Run-command processor ** Copyright (c) 2002 Ralf S. Engelschall ** Copyright (c) 2002 Cable & Wireless Deutschland GmbH ** Copyright (c) 2002 The OSSP Project ** ** This file is part of OSSP rc, a portable Run-command processor ** which can be found at http://www.ossp.org/pkg/lib/rc/ ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** rc_script.c: Run-command processor ISO C source file */ #include #include #include "rc.h" /* Public Rc interface */ #include "rc_pcre.h" /* For section parsing */ #include "rc_config.h" /* For configuration access */ #include "rc_const.h" /* For configuration defaults */ /************************************************ * scriptNew(void) * * Construct a script * ************************************************/ rc_script_t *scriptNew(void) { rc_script_t *pScript = NULL; pScript = (rc_script_t *)malloc(sizeof(rc_script_t)); *pScript = NULL; return(pScript); } /**************************************************** * scriptAppend(rc_script_t *, const char *, size_t) * * Append text to a script * ****************************************************/ rc_return_t scriptAppend(rc_script_t *pScript, const char *szInbuf, size_t Size) { int nResize = 0; void *pvRealloc = NULL; assert(pScript); /* Script parameter must be valid */ if (!szInbuf) { TRACE("Problem with appendScript"); /* return(RC_THROW(RC_ERR_USE));*/ } /* Short circuit in case of dumb noop call */ if (Size == 0) { return(RC_THROW(RC_OK)); } /* Add 2 to end of nResize to ensure that a \0 precedes any strings */ nResize = (*pScript != NULL ? strlen(*pScript) : 0) + Size + 2; /* Don't trust realloc(3) in this case */ if ((pvRealloc = calloc(1, (size_t)nResize)) == NULL) { TRACE("Problem with appendScript"); /* return(RC_THROW(RC_ERR_MEM));*/ } /* Coerce strings into one Script again */ if (*pScript) { strcpy(pvRealloc, *pScript); strncat(pvRealloc, szInbuf, Size); } else strncpy(pvRealloc, szInbuf, Size); /* Cleanup and deallocate memory */ if (*pScript) { free(*pScript); *pScript = NULL; } *pScript = pvRealloc; return(RC_THROW(RC_OK)); } /************************************************ * scriptSection(rc_script_t *, const char *) * * Parse a script for a given section * ************************************************/ rc_section_t *scriptSection(rc_script_t *pScript, const char *kszSecname) { rc_section_t *pSec = NULL; char *piLabstart = NULL; int nLabsize = NULL; char *piSubtemp = NULL; /* To find priority and userid in substrings */ char *piBlocend = NULL; /* Misnomer used to control section looping */ char *piStart = NULL; char *piEnd = NULL; int nOffset = 0; int nFound = 0; int nVecsize = 0; int nSubstrings = 0; int *pnVec = NULL; const char *kszErr = NULL; const int kiRegopt = PCRE_DOTALL | PCRE_MULTILINE; /* const int kiRegopt = PCRE_DOTALL | PCRE_MULTILINE | PCRE_UNGREEDY;*/ pcre *pRegex = NULL; /* Perl Compatible Regular Expression */ pcre_extra *pExtra = NULL; /* Used for studying an expression */ assert(pScript); /* Check for a valid incoming script */ assert(configGetval(RC_DEF_VAL)); if (!kszSecname) /* If we get a NULL section label, then throw up */ RC_THROW(RC_ERR_USE); if ((pRegex = pcre_compile(configGetval(RC_DEF_VAL), kiRegopt, &kszErr, &nOffset, NULL)) == NULL) { RC_THROW(RC_ERR_SYS); } pExtra = pcre_study(pRegex, 0, &kszErr); /* Study the FSM */ if (kszErr) { /* Variable contains a string reference in case of errors */ free(pRegex); RC_THROW(RC_ERR_SYS); } if (pcre_fullinfo(pRegex, pExtra, PCRE_INFO_CAPTURECOUNT, &nSubstrings)) RC_THROW(RC_ERR_SYS); /* Use multiples of six, because PCRE needs 2x multiples of three */ nVecsize = 6 * (nSubstrings > 0 ? nSubstrings : 1); nVecsize *= RC_GOOD_MEASURE; /* Add redundancy factor for error margin */ /* pAwesome += RC_GOOD_VIBRATIONS;*/ /* Add good vibes for super action */ /***********************************************************************/ /* Reminder: PCRE writes vectors to help identify substrings. */ /* That means that in the following code we can */ /* execute a compiled PCRE regex (ab)(\s)(.*)$ */ /* */ /* piBlocend + pnVec[0] = 'start of whole matched string' */ /* piBlocend + pnVec[1] = 'end of whole matched string' */ /* piBlocend + pnVec[2] = 'start of first substring (ab)' */ /* piBlocend + pnVec[3] = 'end of first substring (ab)' */ /* piBlocend + pnVec[4] = 'start of second substring (\s)' */ /* piBlocend + pnVec[5] = 'end of second substring (\s)' */ /* piBlocend + pnVec[6] = 'start of third substring (.*)' */ /* piBlocend + pnVec[7] = 'end of third substring (.*)' */ /***********************************************************************/ /* Filter the rc file for the section label, do it here the first time */ pnVec = calloc(nVecsize, sizeof(int)); /* 2/3 vec 1/3 scrapinfo */ nFound = pcre_exec(pRegex, pExtra, *pScript,\ strlen(*pScript), 0, 0, pnVec, nVecsize); piBlocend = *pScript; /* Start piBlocend pointing to the script object */ while (nFound > 1) { /* Loop as long as we have more sections */ piLabstart = piBlocend + *(pnVec + 2); nLabsize = *(pnVec + 3) - *(pnVec + 2); /*fprintf(stderr, "Substring we want ist %s!\n", kszSecname); fprintf(stderr, "Compared with ist %s!\n", piLabstart);*/ /* Test the substring. If it matches our label, make a new section */ if (!strncmp(piLabstart, kszSecname, nLabsize)) { /* Handle the section body */ piStart = piBlocend + *(pnVec + 6); piEnd = piBlocend + *(pnVec + 7); pSec = sectionNew(); pSec->szData = malloc(piEnd - piStart + sizeof(char)); strncpy(pSec->szData, piStart, piEnd - piStart); *(pSec->szData + (piEnd - piStart)) = NULL; /* Terminate outgoing */ /* Handle the section priority */ piStart = piBlocend + *(pnVec + 4); piEnd = piBlocend + *(pnVec + 5); /* FIXME: Implement --ParseSectionParam for extra gravy */ piSubtemp = strnstr(piStart, RC_DEF_PRG, piEnd - piStart); if (piSubtemp) { /* Priority pattern found */ /* FIXME: Remove the 1 in the following line! */ pSec->nPri = strtol(piSubtemp + strlen(RC_DEF_PRG) + 1, (char **)NULL, 10); } else /* Fallback to default value */ pSec->nPri = RC_DEF_PRI; /*fprintf(stderr, "nPri ist %d!\n", pSec->nPri);*/ /* Handle the section userid */ return(pSec); /* Section found, so return the text */ } /* Looks like we didn't find the section yet, so keep trying */ piBlocend += *(pnVec + 1); /* Find end of section block */ nFound = pcre_exec(pRegex, pExtra, piBlocend,\ strlen(piBlocend), 0, 0, pnVec, nVecsize); } /* Under correct conditions, the section subscript was returned in loop */ if (nFound == 1) /* User gave no klammern */ RC_THROW(RC_ERR_USE); /* so complain about it */ else if (nFound < PCRE_ERROR_NOMATCH) /* Generic problem so */ RC_THROW(RC_ERR_SYS); /* return an error */ return(NULL); /* Probably not found */ } /************************************************ * scriptTostring(rc_script_t *) * * Return the private script data as a string * ************************************************/ const char *scriptTostring(rc_script_t *pScript) { /* Don't remove this! It encapsulates the script object, */ /* which might not be a simple string */ if (pScript) return(*pScript); else return(NULL); } /************************************************ * scriptDump(rc_script_t *) * * Print a script to standard out * ************************************************/ rc_return_t scriptDump(rc_script_t *pScript) { /* Don't remove this! It encapsulates the script object, */ /* which might not be a simple string */ fprintf(stdout, "%s", *pScript); return(RC_THROW(RC_OK)); } /************************************************ * scriptDelete(rc_script_t *) * * Destruct a script * ************************************************/ rc_return_t scriptDelete(rc_script_t *pScript) { if (*pScript) free(*pScript); else { TRACE("Empty script created, unused, then destroyed"); /* RC_THROW(RC_WRN_NUL);*/ } free(pScript); return(RC_THROW(RC_OK)); }