ossp-pkg/rc/rc_proc.c
1.30
/* OSSP rc - Run-command processor
** Copyright (c) 2002 Ralf S. Engelschall
** Copyright (c) 2002 Cable & Wireless Deutschland GmbH
** Copyright (c) 2002 The OSSP Project <http://www.ossp.org/>
**
** 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_proc.c: Run-command processor ISO C source file
*/
#include <stdlib.h> /* Standard system headers */
#include <fcntl.h> /* For reading rc files */
#include <unistd.h> /* For reading rc files */
#include <string.h> /* For string manipulation */
/* FIXME: Remove */
#include <sys/stat.h>
#include "rc.h" /* Public interfaces */
#include "rc_const.h" /* String and value const */
#include "rc_config.h" /* Option definitions */
/************************************************
* procNew(void) *
* Construct a processor *
************************************************/
rc_proc_t *procNew(void)
{
rc_proc_t *pNewrc = NULL;
pNewrc = malloc(sizeof(rc_proc_t));
pNewrc->m_pAnal = analNew(); /* Construct a configuration analyser */
analParse(pNewrc->m_pAnal); /* Preprocess the anal configuration */
pNewrc->m_pScriptcom = scriptNew(); /* Construct a run-command script */
pNewrc->m_ppLabvec = calloc(pNewrc->m_pAnal->m_nRcs, sizeof(rc_label_t *));
return(pNewrc);
}
/************************************************
* procReadtmp(rc_proc_t *, const char *) *
* Open and store a temp file *
************************************************/
rc_return_t procReadtmp(rc_proc_t *pRc, const char *szTmpname)
{
fprintf(stderr, "%s!!!\n", szTmpname);
return(RC_THROW(RC_OK));
}
/************************************************
* procPopulate(rc_proc_t *) *
* Populate the processor with run commands *
************************************************/
rc_return_t procPopulate(rc_proc_t *pRc)
{
int nSect = 0;
int nFdrc = 0;
int nFdfunc = 0;
int nRet = 0;
int nRc = 0;
ex_t Except;
char *sBuf = NULL;
rc_section_t *pSec = NULL;
char *szLocex = NULL;
rc_script_t *pTempscript = NULL;
assert(*pRc->m_pAnal->m_szRcs);
sBuf = (char *)calloc(1, RC_READ_BUFSIZE);
/* Open the func file if it exists in the configuration */
if (pRc->m_pAnal->m_szFuncs) {
if ((nFdfunc = open(pRc->m_pAnal->m_szFuncs, O_RDONLY)) < 0) {
RC_THROW(RC_ERR_FNC);
}
}
/* Stick on the starting shell id line */
scriptAppend(pRc->m_pScriptcom, "#! /bin/sh\n", strlen("#! /bin/sh\n"));
/* Read data from the func file */
while ((nRet = read(nFdfunc, sBuf, RC_READ_BUFSIZE)) > 0) {
scriptAppend(pRc->m_pScriptcom, sBuf, nRet);
}
scriptAppend(pRc->m_pScriptcom, "\n", sizeof(char));
if (nRet == -1) /* Handle read errors */
RC_THROW(RC_ERR_IO);
/* Iteratively read possibly globbed rc files */
for (nRc = 0; nRc < pRc->m_pAnal->m_nRcs; nRc++)
{
assert(*pRc->m_pAnal->m_szRcs); /* If one of these assertions fail, */
assert(pRc->m_pAnal->m_szLocs); /* you've probably seen the ex_ bug */
/* Construct a new label */
pRc->m_ppLabvec[nRc] = labelNew(pRc->m_pAnal->m_szRcs[nRc]);
/* Build the path name */
szLocex = (char *)malloc(strlen(pRc->m_pAnal->m_szLocs) + strlen(pRc->m_pAnal->m_szRcs[nRc]) + 2);
strcpy(szLocex, pRc->m_pAnal->m_szLocs);
strcat(szLocex, "rc."); /* FIXME: Make the prefix configurable */
strcat(szLocex, pRc->m_pAnal->m_szRcs[nRc]);
/* Open the rc file unconditionally */
if ((nFdrc = open(szLocex, O_RDONLY)) == -1)
RC_THROW(RC_ERR_RCF);
/* Read data from the rc file into a temporary script */
pTempscript = scriptNew();
while ((nRet = read(nFdrc, sBuf, RC_READ_BUFSIZE)) > 0)
scriptAppend(pTempscript, sBuf, nRet);
if (nRet == -1) /* Handle read errors */
RC_THROW(RC_ERR_IO);
try {
/* Append config section if it exists */
pSec = scriptSection(pTempscript, configGetval(RC_NCF_VAL));
if (pSec) { /* Only operate if the section lookup succeeds */
scriptAppend(pRc->m_pScriptcom, sectionGetdata(pSec), strlen(sectionGetdata(pSec)));
scriptAppend(pRc->m_pScriptcom, "\n", sizeof(char));
sectionDelete(pSec); /* Cleanup */
pSec = NULL; /* Cleanup */
}
for (nSect = 0; nSect < pRc->m_pAnal->m_nSecs; nSect++) { /* Iterate over */
/* Extract a section from the temp script, and append it */
pSec = scriptSection(pTempscript, pRc->m_pAnal->m_pszSecs[nSect]);
if (pSec) { /* Only copy if the section lookup succeeds */
labelAppendsec(pRc->m_ppLabvec[nRc], pSec);
}
else if (configGetval(RC_DBG_VAL)) /* Only show if debug set */
fprintf(stderr, "#Warning: Missing section '%s' in %s!\n",\
pRc->m_pAnal->m_pszSecs[nSect],\
pRc->m_pAnal->m_szRcs[nRc]);
if (pSec) { /* Cleanup iterative section string */
sectionDelete(pSec);
pSec = NULL;
}
}
}
catch(Except)
rethrow;
/* Clean up our crap */
scriptDelete(pTempscript); /* Temp script */
pTempscript = NULL;
free(szLocex); /* Temp Location + Rcfile */
szLocex = NULL;
close(nFdrc); /* Close Rc file handle */
}
close(nFdfunc); /* Close Func file handle */
/* Memory cleanups */
if (sBuf) {
free(sBuf);
sBuf = NULL;
}
return(RC_THROW(RC_OK));
}
/************************************************
* procRun(rc_proc_t *) *
* Run the processed run-command script *
************************************************/
rc_return_t procRun(rc_proc_t *pRc)
{
int nTmp = 0; /* Generic index */
int nTmpname = 0; /* Temp file name size */
int nRcs = 0; /* Rc index */
int nSecs = 0; /* Section index */
char *szTmpfile = NULL; /* Path of temporary file */
char *szTmp = NULL; /* Generic temporary string */
char *szExec = NULL; /* Used only during exec mode */
char *pszVec[RC_EXEC_MAXARGS]; /* For passing in to execv(3) */
rc_script_t *pFatscript = NULL; /* To build a comprehensive script */
rc_section_t **ppSectmp = NULL; /* Used with priority scheduling */
/****************************************************/
/* This will execute, evaluate, or print the script */
/* Exec - Fork and execute each command */
/* Eval - Print machine evaluatable format */
/* Print - Print human readable format */
/****************************************************/
if (configGetval(RC_EVL_VAL)) { /* Evaluate */
/* Allocate a block of section pointers to use temporarily */
ppSectmp = calloc(pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *));
/* Allocate the command chain string to execute with execv(3) */
pFatscript = scriptCopy(pRc->m_pScriptcom);
for (nSecs = 0; nSecs < pRc->m_pAnal->m_nSecs; nSecs++) {
for (nRcs = 0; nRcs < pRc->m_pAnal->m_nRcs; nRcs++) {
nTmp = 0;
while (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs && \
strcmp(pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp]->m_szName, \
pRc->m_pAnal->m_pszSecs[nSecs]))
nTmp++;
if (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs)
ppSectmp[nRcs] = pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp];
else
ppSectmp[nRcs] = NULL;
}
qsort((void *)ppSectmp, (size_t)pRc->m_pAnal->m_nRcs, \
sizeof(rc_section_t *), priCompare);
nTmp = 0;
while (nTmp < pRc->m_pAnal->m_nRcs && ppSectmp[nTmp]) {
if ((szTmp = (char *)sectionGetlogin(ppSectmp[nTmp])) != NULL) {
scriptAppend(pFatscript, "#su ", strlen("#su "));
scriptAppend(pFatscript, szTmp, strlen(szTmp));
scriptAppend(pFatscript, "\n", strlen("\n") + 1);
}
szTmp = (char *)sectionGetdata(ppSectmp[nTmp]);
scriptAppend(pFatscript, szTmp, strlen(szTmp) + 1);
nTmp++;
}
}
free(ppSectmp);
ppSectmp = NULL;
szTmpfile = (char *)configGetval(RC_TMP_VAL);
nTmpname = (strlen(szTmpfile) + strlen(RC_EVL_TMP) + \
strlen(RC_EVL_SUF) + 1) * sizeof(char);
if (*(szTmpfile + (strlen(szTmpfile) - 1) * sizeof(char)) != '/')
nTmpname += sizeof(char);
szTmpfile = malloc(nTmpname);
strcpy(szTmpfile, configGetval(RC_TMP_VAL));
if (*(szTmpfile + (strlen(szTmpfile) - 1) * sizeof(char)) != '/')
*(szTmpfile + (strlen(szTmpfile)) * sizeof(char)) = '/';
strcat(szTmpfile, RC_EVL_TMP);
mktemp(szTmpfile);
strcat(szTmpfile, RC_EVL_SUF);
scriptWrite(pFatscript, szTmpfile); /* Write the whole script out */
fprintf(stdout, RC_EVL_OUT, szTmpfile, szTmpfile);
free(szTmpfile);
szTmpfile = NULL;
scriptDelete(pFatscript);
pFatscript = NULL;
}
else if (configGetval(RC_EXC_VAL)) { /* Execute */
/* Allocate a block of section pointers to use temporarily */
ppSectmp = calloc(pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *));
/* Allocate the command chain string to execute with execv(3) */
szTmp = (char *)scriptTostring(pRc->m_pScriptcom);
szExec = malloc((strlen(szTmp) + 1) * sizeof(char));
strcpy(szExec, szTmp);
for (nSecs = 0; nSecs < pRc->m_pAnal->m_nSecs; nSecs++) {
for (nRcs = 0; nRcs < pRc->m_pAnal->m_nRcs; nRcs++) {
nTmp = 0;
while (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs && \
strcmp(pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp]->m_szName, \
pRc->m_pAnal->m_pszSecs[nSecs]))
nTmp++;
if (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs)
ppSectmp[nRcs] = pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp];
else
ppSectmp[nRcs] = NULL;
}
qsort((void *)ppSectmp, (size_t)pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *), priCompare);
nTmp = 0;
while (nTmp < pRc->m_pAnal->m_nRcs && ppSectmp[nTmp]) {
szTmp = (char *)sectionGetdata(ppSectmp[nTmp]);
szExec = realloc(szExec, (strlen(szExec) + 1) * sizeof(char) + \
(strlen(szTmp) + 1) * sizeof(char));
strcat(szExec, szTmp); /* Build onto the command chain */
nTmp++;
}
}
free(ppSectmp);
ppSectmp = NULL;
/* Actually launch the new process image now */
pszVec[0] = "/bin/sh";
pszVec[1] = "-c";
pszVec[2] = szExec;
pszVec[3] = NULL; /* Add a NULL to mark the end of the chain */
if (execvp(*pszVec, pszVec) == -1) { /* launch */
TRACE("Bad, execvp for common script in child returned -1");
return(RC_THROW(RC_ERR_INT));
}
}
else if (configGetval(RC_PRN_VAL)) { /* Print */
/* Allocate a block of section pointers to use as a temporary */
ppSectmp = calloc(pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *));
scriptDump(pRc->m_pScriptcom); /* Dump the common script */
for (nSecs = 0; nSecs < pRc->m_pAnal->m_nSecs; nSecs++) {
for (nRcs = 0; nRcs < pRc->m_pAnal->m_nRcs; nRcs++) {
nTmp = 0;
while (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs && \
strcmp(pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp]->m_szName, \
pRc->m_pAnal->m_pszSecs[nSecs]))
nTmp++;
if (nTmp < pRc->m_ppLabvec[nRcs]->m_nSecs)
ppSectmp[nRcs] = pRc->m_ppLabvec[nRcs]->m_ppSecvec[nTmp];
else
ppSectmp[nRcs] = NULL;
}
qsort((void *)ppSectmp, (size_t)pRc->m_pAnal->m_nRcs, sizeof(rc_section_t *), priCompare);
nTmp = 0;
while (nTmp < pRc->m_pAnal->m_nRcs && ppSectmp[nTmp]) {
sectionDump(ppSectmp[nTmp]);
nTmp++;
}
}
free(ppSectmp);
ppSectmp = NULL;
}
else /* Something is wrong here */
return(RC_THROW(RC_ERR_INT));
return(RC_THROW(RC_OK));
}
/************************************************
* procDelete(rc_proc_t *) *
* Destruct a processor *
************************************************/
rc_return_t procDelete(rc_proc_t *pRc)
{
int nRcs = pRc->m_pAnal->m_nRcs;
/* Destroy the label vector */
while (nRcs-- > 0) {
if (pRc->m_ppLabvec[nRcs]) {
labelDelete(pRc->m_ppLabvec[nRcs]);
pRc->m_ppLabvec[nRcs] = NULL;
}
}
free(pRc->m_ppLabvec);
pRc->m_ppLabvec = NULL;
scriptDelete(pRc->m_pScriptcom); /* Destroy the script */
analDelete(pRc->m_pAnal); /* Destroy the analyser */
free(pRc); /* Free the processor itself */
return(RC_THROW(RC_OK));
}