/* OSSP rc - Run-command processor ** Copyright (c) 2002-2003 Ralf S. Engelschall ** Copyright (c) 2002-2003 Cable & Wireless Deutschland GmbH ** Copyright (c) 2002-2003 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_proc.c: Run-command processor ISO C source file */ #include /* Standard system headers */ #include /* For reading rc files */ #include /* For reading rc files */ #include /* For string manipulation */ #include /* For signal(3) */ #include /* For waitpid(2) and fork(2) */ #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) { ex_t Except; rc_proc_t *pNewrc = NULL; ex_try { pNewrc = malloc(sizeof(rc_proc_t)); pNewrc->m_pList = listNew(); /* Construct a rcfile list */ listPopulate(pNewrc->m_pList, configGetrcfile()); /* Prepopulate list */ pNewrc->m_pScriptfunc = scriptNew(); /* Construct a functions script */ pNewrc->m_pScriptcnf = scriptNew(); /* Construct a config script */ } ex_catch(Except) rethrow; return(pNewrc); } /************************************************ * procPopulate(rc_proc_t *) * * Populate the processor with run commands * ************************************************/ rc_return_t procPopulate(rc_proc_t *pRc) { int nSect = 0; int nFdfunc = -1; int nRet = 0; int nRcs = 0; ex_t Except; char *sBuf = NULL; rc_file_t *pRcfile = NULL; rc_section_t *pSec = NULL; rc_section_t *pCom = NULL; short nTotalsecs = vectorCount(configGetsecs()); assert(pRc->m_pList->m_ppFilevec); sBuf = (char *)calloc(1, RC_READ_BUFSIZE); /* Open the func file if it exists in the configuration */ if (configGetval(RC_FNC_VAL)) { /* FIXME: Funcfile data does not belong in config section data! */ if ((nFdfunc = open(configGetval(RC_FNC_VAL), O_RDONLY)) >= 0) { /* Read data from the func file */ while ((nRet = read(nFdfunc, sBuf, RC_READ_BUFSIZE)) > 0) scriptnAppend(pRc->m_pScriptfunc, sBuf, nRet); if (nRet == -1) /* Handle read errors */ RC_THROW(RC_ERR_IO); scriptnAppend(pRc->m_pScriptfunc, "\n", sizeof("\n")); close(nFdfunc); /* Close Func file handle */ } else RC_THROW(RC_ERR_FNC); } /* Iteratively read possibly globbed rc files */ for (nRcs = 0; nRcs < pRc->m_pList->m_nFiles; nRcs++) { if (!pRc->m_pList->m_ppFilevec[nRcs]) RC_THROW(RC_ERR_INT); /* Rcfile vector is missing its tail */ pRcfile = rcfileNew(pRc->m_pList->m_ppFilevec[nRcs]->m_szName); rcfileParse(pRcfile); try { /* If it exists, append config section unconditionally */ pSec = rcfileGetsec(pRcfile, configGetval(RC_NCF_VAL)); if (pSec) { /* Only operate if the section lookup succeeds */ scriptAdd(pRc->m_pScriptcnf, sectionGetscript(pSec)); scriptnAppend(pRc->m_pScriptcnf, "\n", strlen ("\n")); } for (nSect = 0; nSect < nTotalsecs; nSect++) { /* Iterate over */ /* Extract a section from the temp script, and append it */ pSec = rcfileGetsec(pRcfile, configGetsecs()[nSect]); if (pSec) { /* Append common section only if the target section matches */ pCom = rcfileGetsec(pRcfile, configGetval(RC_CMN_VAL)); if (pCom) /* Only append if the common lookup succeeds */ rcfileAppendsec(pRc->m_pList->m_ppFilevec[nRcs], pCom); /* Only copy if the section lookup succeeds */ rcfileAppendsec(pRc->m_pList->m_ppFilevec[nRcs], pSec); } else if (configGetval(RC_DBG_VAL)) /* Only show if debug set */ fprintf(stderr, "#Warning: Missing section '%s' in %s!\n",\ configGetsecs()[nSect], pRc->m_pList->m_ppFilevec[nRcs]->m_szName); } } catch(Except) rethrow; /* Attach our rcfile in the list */ pRc->m_pList->m_ppFilevec[nRcs] = pRcfile; pRcfile = NULL; } /* Memory cleanups */ if (sBuf) { free(sBuf); sBuf = NULL; } return(RC_THROW(RC_OK)); } /******************************************* * procRun(rc_proc_t *) * * Run the processed run-command script * * Exec - Fork and execute each command * * Eval - Print machine evaluatable format * * Print - Print human readable format * *******************************************/ rc_return_t procRun(rc_proc_t *pRc) { if (configGetval(RC_EVL_VAL)) /* Evaluate */ return(procEval(pRc)); else if (configGetval(RC_EXC_VAL)) /* Execute */ return(procExec(pRc)); else if (configGetval(RC_PRN_VAL)) /* Print */ return(procPrint(pRc)); else if (configGetval(RC_PAR_VAL)) /* Parse */ return(procParse(pRc)); else return(RC_ERR_INT); /* Run mode was not correctly set */ } /************************************************ * procEval(rc_proc_t *) * * Evaluate the run-command script * ************************************************/ rc_return_t procEval(rc_proc_t *pRc) { short nSecs = 0; /* Section index */ short nTotalsecs = vectorCount(configGetsecs()); /* Sections */ short nRcs = 0; /* Rc index */ int nTmp = 0; /* Generic index */ size_t nTmpname = 0; /* Temp name size */ size_t nBytes = 0; /* Size in bytes */ char *szTmp = NULL; /* Generic temporary string */ char *szTmpfile = NULL; /* Path of temporary file */ char *szVerbose = NULL; /* Used when handling verbose mode */ rc_section_t **ppSectmp = NULL; /* Used with priority scheduling */ rc_script_t *pFatscript = NULL; /* To build a comprehensive script */ /* Allocate a block of section pointers to use temporarily */ ppSectmp = calloc(pRc->m_pList->m_nFiles, sizeof(rc_section_t *)); pFatscript = scriptNew(); scriptnAppend(pFatscript, RC_BANG_STR, strlen(RC_BANG_STR)); /* Shebang */ /* Conditionally output initial notice in verbal mode */ if (configGetval(RC_VRB_VAL)) { szVerbose = malloc((strlen(RC_VST_TEXT) + 2) * sizeof (char)); sprintf(szVerbose, "%s", RC_VST_TEXT); strcat(szVerbose, "\n"); scriptnAppend(pFatscript, szVerbose, strlen(szVerbose)); free(szVerbose); szVerbose = NULL; } /* Conditionally print funcs section notice in verbal mode */ if (configGetval(RC_VRB_VAL)) { szVerbose = malloc((strlen(RC_EVF_TEXT) + 2) * sizeof (char)); sprintf(szVerbose, "%s", RC_EVF_TEXT); strcat(szVerbose, "\n"); scriptnAppend(pFatscript, szVerbose, strlen(szVerbose)); free(szVerbose); szVerbose = NULL; } scriptAdd(pFatscript, pRc->m_pScriptfunc); for (nSecs = 0; nSecs < nTotalsecs; nSecs++) { for (nRcs = 0; nRcs < pRc->m_pList->m_nFiles; nRcs++) { for (nTmp = 0; nTmp < pRc->m_pList->m_ppFilevec[nRcs]->m_nSecs && \ strcmp(pRc->m_pList->m_ppFilevec[nRcs]->m_ppSecvec[nTmp]->m_szName, \ configGetsecs()[nSecs]); nTmp++); if (nTmp < pRc->m_pList->m_ppFilevec[nRcs]->m_nSecs) ppSectmp[nRcs] = pRc->m_pList->m_ppFilevec[nRcs]->m_ppSecvec[nTmp]; else ppSectmp[nRcs] = NULL; } qsort((void *)ppSectmp, (size_t)pRc->m_pList->m_nFiles, \ sizeof(rc_section_t *), priCompare); for (nTmp = 0; nTmp < pRc->m_pList->m_nFiles && ppSectmp[nTmp]; nTmp++) { if (configGetval(RC_VRB_VAL)) { /* Conditionally evaluate config section notice in verbal mode */ nBytes = (strlen(RC_EVN_TEXT) + strlen(RC_DEF_NCF) + \ strlen(sectionGetparent(ppSectmp[nTmp])) + 2) * sizeof (char); szVerbose = malloc(nBytes); sprintf(szVerbose, RC_EVN_TEXT, RC_DEF_NCF, sectionGetparent(ppSectmp[nTmp])); strcat(szVerbose, "\n"); scriptnAppend(pFatscript, szVerbose, strlen(szVerbose)); free(szVerbose); szVerbose = NULL; } scriptAdd(pFatscript, pRc->m_pScriptcnf); /* Examine our list, and try to take the corresponding */ /* common section data from it to add to your script */ { rc_section_t *pComsec = NULL; pComsec = rcfileGetsec(listGetrcfile(pRc->m_pList, \ ppSectmp[nTmp]->m_szParent), configGetval(RC_CMN_VAL)); if (pComsec) { /* Do we have a common section to load? */ if (configGetval(RC_VRB_VAL)) { szTmp = (char *)sectionGetname(pComsec); nBytes = (strlen(RC_EVN_TEXT) + strlen(szTmp) + \ strlen (sectionGetparent(pComsec)) + \ strlen(RC_ECHO_STR) + strlen("\"\"") + 1) * \ sizeof (char); szVerbose = malloc(nBytes); sprintf(szVerbose, RC_EVN_TEXT, szTmp, sectionGetparent(pComsec)); strcat(szVerbose, "\n"); scriptnAppend(pFatscript, szVerbose, strlen(szVerbose)); free(szVerbose); szVerbose = NULL; } scriptAdd(pFatscript, sectionGetscript(pComsec)); } } /* Conditionally print each section notice in verbal mode */ if (configGetval(RC_VRB_VAL)) { szTmp = (char *)sectionGetname(ppSectmp[nTmp]); nBytes = (strlen(RC_EVN_TEXT) + strlen(szTmp) + 2) * sizeof (char); szVerbose = malloc(nBytes); sprintf(szVerbose, RC_EVN_TEXT, szTmp, sectionGetparent(ppSectmp[nTmp])); strcat(szVerbose, "\n"); scriptnAppend(pFatscript, szVerbose, strlen(szVerbose)); free(szVerbose); szVerbose = NULL; } if ((szTmp = (char *)sectionGetlogin(ppSectmp[nTmp])) != NULL) { scriptnAppend(pFatscript, "#su ", strlen("#su ")); scriptnAppend(pFatscript, szTmp, strlen(szTmp)); } else scriptnAppend(pFatscript, "#exit ", strlen("#exit ")); scriptnAppend(pFatscript, "\n", strlen("\n")); scriptAdd(pFatscript, sectionGetscript(ppSectmp[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)) != '/') strcat(szTmpfile, "/"); strcat(szTmpfile, RC_EVL_TMP); mktemp(szTmpfile); strcat(szTmpfile, RC_EVL_SUF); scriptWrite(pFatscript, szTmpfile); /* Write the whole script out */ /* Conditionally don't remove the temp file (see constants) */ if (configGetval(RC_DBG_VAL)) fprintf(stdout, RC_EVL_DBG, szTmpfile); else fprintf(stdout, RC_EVL_OUT, szTmpfile, szTmpfile); /* Cleanup eval processing crap */ free(szTmpfile); szTmpfile = NULL; scriptDelete(pFatscript); pFatscript = NULL; return(RC_THROW(RC_OK)); } /************************************************ * procExec(rc_proc_t *) * * Execute the run-command script * ************************************************/ rc_return_t procExec(rc_proc_t *pRc) { short nRcs = 0; /* Rc index */ short nSecs = 0; /* Section index */ short nTotalsecs = vectorCount(configGetsecs()); /* Sections */ rc_section_t **ppSectmp = NULL; /* Used with priority scheduling */ int nRunuid = -1; /* The current user id */ int nSectuid = -1; /* The section's user id */ int nTmp = 0; /* Generic temporary index */ int nStat = 0; /* Status forked child */ pid_t Pidexec = -1; /* Spawning before execv(3) */ char *pszVec[RC_EXEC_MAXARGS]; /* For passing in to execv(3) */ char *szTmp = NULL; /* Generic temporary string */ char *szFunc = NULL; /* Stores func script text */ char *szCnf = NULL; /* Stores config script text */ char *szExec = NULL; /* Used only during exec mode */ char *szVerbose = NULL; /* Used when handling verbose mode */ /* This block does nothing more than implement the feature, */ /* that allows rc to run unprivileged (as long as no privileged */ /* code is used in the script sections to be executed */ for (nSecs = 0; nSecs < nTotalsecs; nSecs++) { for (nTmp = 0; nTmp < pRc->m_pList->m_nFiles; nTmp++) { if (pRc->m_pList->m_ppFilevec[nTmp]->m_ppSecvec && \ pRc->m_pList->m_ppFilevec[nTmp]->m_ppSecvec[nSecs]) { nRunuid = getuid(); nSectuid = pRc->m_pList->m_ppFilevec[nTmp]->m_ppSecvec[nSecs]->m_nUid; /* See if root user status is needed, and bail out if so */ if (nRunuid != 0 && nSectuid != -1 && nRunuid != nSectuid) { fprintf(stderr, RC_RUT_TEXT); return(RC_THROW(RC_ERR_USE)); } } } } /* Allocate a block of section pointers to use temporarily */ ppSectmp = calloc(pRc->m_pList->m_nFiles, sizeof(rc_section_t *)); szFunc = (char *)scriptGetdata(pRc->m_pScriptfunc); szCnf = (char *)scriptGetdata(pRc->m_pScriptcnf); for (nSecs = 0; nSecs < nTotalsecs; nSecs++) { for (nRcs = 0; nRcs < pRc->m_pList->m_nFiles; nRcs++) { for (nTmp = 0; nTmp < pRc->m_pList->m_ppFilevec[nRcs]->m_nSecs && \ strcmp(pRc->m_pList->m_ppFilevec[nRcs]->m_ppSecvec[nTmp]->m_szName, \ configGetsecs()[nSecs]); nTmp++); if (nTmp < pRc->m_pList->m_ppFilevec[nRcs]->m_nSecs) ppSectmp[nRcs] = pRc->m_pList->m_ppFilevec[nRcs]->m_ppSecvec[nTmp]; else ppSectmp[nRcs] = NULL; } qsort((void *)ppSectmp, (size_t)pRc->m_pList->m_nFiles, sizeof(rc_section_t *), priCompare); pszVec[0] = "/bin/sh"; /* Run the bourne shell over the following */ pszVec[1] = "-c"; /* Append script code of the sections */ pszVec[3] = NULL; /* Add a NULL to mark the end of the chain */ nTmp = 0; /* Count from zero until however many sections we have */ while (nTmp < pRc->m_pList->m_nFiles && ppSectmp[nTmp]) { /* Conditionally print config and other section notices in verbal mode */ if (configGetval(RC_VRB_VAL)) { /* Verbose mode is active */ size_t nSizverb = 0; size_t nPrescr = 0; size_t nSecverb = 0; size_t nSection = 0; /* Allocate space just for string to prepare for verbose */ nSizverb = (strlen(RC_EXN_TEXT) + strlen(RC_DEF_NCF) + \ strlen(sectionGetparent(ppSectmp[nTmp])) + strlen(RC_ECHO_STR) + \ strlen("\"\"") + 1) * sizeof (char); szVerbose = malloc(nSizverb); sprintf(szVerbose, RC_EXN_TEXT, RC_DEF_NCF, sectionGetparent(ppSectmp[nTmp])); /* Allocate space for entire string to execvp(3) */ nPrescr = (strlen(RC_VST_TEXT) + strlen(RC_EXF_TEXT) + \ strlen(szVerbose) + strlen(szFunc) + strlen(szCnf) + \ strlen(RC_BANG_STR) + 1) * sizeof (char); szExec = malloc(nSizverb + nPrescr); strcpy(szExec, RC_BANG_STR); /* Start out with the bang string */ strcat(szExec, RC_ECHO_STR); /* Continue with the echo string */ strcat(szExec, "\""); /* Append a quote next to the echo */ strcat(szExec, RC_VST_TEXT); /* Continue with the start text */ if (strlen(szFunc) > 0) { strcat(szExec, "\n"); /* Stick a newline inbetween */ strcat(szExec, RC_EXF_TEXT); /* Continue with the func text */ } strcat(szExec, "\";"); /* Finalize the verbosity notice */ strcat(szExec, szFunc); /* Continue with the funcs script code */ strcat(szExec, RC_ECHO_STR); /* Continue with the echo string */ strcat(szExec, "\""); /* Append a quote next to the echo */ strcat(szExec, szVerbose); /* Continue with the config text */ strcat(szExec, "\";"); /* Finalize the verbosity notice */ strcat(szExec, szCnf); /* Then with the config script code */ /* Examine our list, and try to take the corresponding */ /* common section data from it to add to your script */ { rc_section_t *pComsec = NULL; pComsec = rcfileGetsec(listGetrcfile(pRc->m_pList, \ ppSectmp[nTmp]->m_szParent), configGetval(RC_CMN_VAL)); if (pComsec) { /* If we have a common section to load, */ szTmp = (char *)sectionGetname(pComsec); nSecverb = (strlen(RC_EXN_TEXT) + strlen(szTmp) + \ strlen (sectionGetparent(pComsec)) + \ strlen(RC_ECHO_STR) + strlen("\"\"") + 1) * \ sizeof (char); realloc(szVerbose, nSecverb); sprintf(szVerbose, RC_EXN_TEXT, szTmp, sectionGetparent(pComsec)); nSection = (strlen(szTmp) + 1) * sizeof (char); realloc(szExec, nSizverb + nPrescr + nSecverb + nSection); strcat(szExec, RC_ECHO_STR); /* Start out with the echo string */ strcat(szExec, "\""); /* Append a quote next to the echo */ strcat(szExec, szVerbose); /* Continue with the common text */ strcat(szExec, "\";"); /* Finalize the verbosity notice */ strcat(szExec, sectionGetdata(pComsec)); /* load it */ } } /* Build last set of verbose data for the actual script */ szTmp = (char *)sectionGetname(ppSectmp[nTmp]); nSecverb = (strlen(RC_EXN_TEXT) + strlen(szTmp) * 2 \ + strlen(RC_ECHO_STR) + strlen("\"\"") + 1) * sizeof (char); realloc(szVerbose, nSecverb); sprintf(szVerbose, RC_EXN_TEXT, szTmp, sectionGetparent(ppSectmp[nTmp])); nSection = (strlen(szTmp) + strlen(sectionGetdata(ppSectmp[nTmp])) + 1) * sizeof (char); realloc(szExec, nSizverb + nPrescr + nSecverb + nSection); szTmp = (char *)sectionGetdata(ppSectmp[nTmp]); strcat(szExec, RC_ECHO_STR); /* Start out with the echo string */ strcat(szExec, "\""); /* Append a quote next to the echo */ strcat(szExec, szVerbose); /* Continue with the verboseity text */ strcat(szExec, "\";"); /* Finalize the verbosity notice */ strcat(szExec, szTmp); /* Then with the new script code */ pszVec[2] = szExec; /* Launch the new process image now */ free(szVerbose); szVerbose = NULL; /* Spawn the section shell code */ switch (Pidexec = fork()) { case -1: /* Broken */ return(RC_THROW(RC_ERR_INT)); break; /* Huh? */ case 0: /* Child, runs script code through bourne shell */ nSectuid = sectionGetuid(ppSectmp[nTmp]); if (nSectuid >= 0 && getuid() != nSectuid) if (setuid(nSectuid) != 0) return(RC_THROW(RC_ERR_ROOT)); if (execvp(*pszVec, pszVec) == -1) return(RC_THROW(RC_ERR_INT)); break; default: /* Parent, blocks until child returns */ waitpid(Pidexec, &nStat, WUNTRACED); if ((nStat = WEXITSTATUS(nStat)) != 0) return(nStat); break; } if (szExec) { free(szExec); /* Cleanup after exec */ szExec = NULL; } } else { /* Verbose mode is off */ szTmp = (char *)sectionGetdata(ppSectmp[nTmp]); szExec = malloc((strlen(szFunc) + strlen(szCnf) + \ strlen(szTmp) + 1) * sizeof(char)); strcpy(szExec, RC_BANG_STR); /* Start out with the shebang string */ strcat(szExec, szFunc); /* Continue with just the funcs script code */ strcat(szExec, szCnf); /* Continue with just the config script code */ /* Examine our list, and try to take the corresponding */ /* common section data from it to add to your script */ { rc_section_t *pComsec = NULL; pComsec = rcfileGetsec(listGetrcfile(pRc->m_pList, \ ppSectmp[nTmp]->m_szParent), configGetval(RC_CMN_VAL)); if (pComsec) /* If we have a common section to load, */ strcat(szExec, sectionGetdata(pComsec)); /* load it */ } strcat(szExec, szTmp); /* And build a section onto the command chain */ pszVec[2] = szExec; /* Actually launch the new process image now */ /* Spawn the section shell code */ switch (Pidexec = fork()){ case -1: /* Broken */ return(RC_THROW(RC_ERR_INT)); break; /* Huh? */ case 0: /* Child, runs script code through bourne shell */ nSectuid = sectionGetuid(ppSectmp[nTmp]); if (nSectuid >= 0 && getuid() != nSectuid) if (setuid(nSectuid) != 0) return(RC_THROW(RC_ERR_ROOT)); if (execvp(*pszVec, pszVec) == -1) return(RC_THROW(RC_ERR_INT)); break; default: /* Parent, blocks until child returns */ waitpid(Pidexec, &nStat, WUNTRACED); if ((nStat = WEXITSTATUS(nStat)) != 0) return(nStat); break; } free(szExec); /* Cleanup after exec */ szExec = NULL; } nTmp++; /* Next rc script */ } } free(ppSectmp); ppSectmp = NULL; return(RC_THROW(RC_OK)); } /************************************************ * procPrint(rc_proc_t *) * * Print the run-command script * ************************************************/ rc_return_t procPrint(rc_proc_t *pRc) { size_t nBytes = 0; /* Size in bytes */ int nTmp = 0; /* Generic index */ short nRcs = 0; /* Rc index */ short nSecs = 0; /* Section index */ short nTotalsecs = vectorCount(configGetsecs()); /* Sections */ rc_section_t **ppSectmp = NULL; /* Used with priority scheduling */ char *szVerbose = NULL; /* Used when handling verbose mode */ char *szTmp = NULL; /* Generic temporary string */ /* Allocate a block of section pointers to use as a temporary */ ppSectmp = calloc(pRc->m_pList->m_nFiles, sizeof(rc_section_t *)); /* Conditionally output initial notice in verbal mode */ if (configGetval(RC_VRB_VAL)) fprintf(stderr, "%s\n", RC_VST_TEXT); /* Conditionally print funcs section notice in verbal mode */ if (configGetval(RC_VRB_VAL)) fprintf(stderr, "%s\n", RC_PNF_TEXT); scriptDump(pRc->m_pScriptfunc); /* Dump the funcs script */ for (nSecs = 0; nSecs < nTotalsecs; nSecs++) { for (nRcs = 0; nRcs < pRc->m_pList->m_nFiles; nRcs++) { for (nTmp = 0; nTmp < pRc->m_pList->m_ppFilevec[nRcs]->m_nSecs && \ strcmp(pRc->m_pList->m_ppFilevec[nRcs]->m_ppSecvec[nTmp]->m_szName, \ configGetsecs()[nSecs]); nTmp++); if (nTmp < pRc->m_pList->m_ppFilevec[nRcs]->m_nSecs) ppSectmp[nRcs] = pRc->m_pList->m_ppFilevec[nRcs]->m_ppSecvec[nTmp]; else ppSectmp[nRcs] = NULL; } qsort((void *)ppSectmp, (size_t)pRc->m_pList->m_nFiles, sizeof(rc_section_t *), priCompare); for (nTmp = 0; nTmp < pRc->m_pList->m_nFiles && ppSectmp[nTmp]; nTmp++) { if (configGetval(RC_VRB_VAL)) { /* Conditionally print config section notice in verbal mode */ nBytes = (strlen(RC_PRN_TEXT) + strlen(RC_DEF_NCF) + \ strlen(sectionGetparent(ppSectmp[nTmp])) + 2) * sizeof (char); szVerbose = malloc(nBytes); sprintf(szVerbose, RC_PRN_TEXT, RC_DEF_NCF, sectionGetparent(ppSectmp[nTmp])); strcat(szVerbose, "\n"); fprintf(stderr, szVerbose); free(szVerbose); szVerbose = NULL; } scriptDump(pRc->m_pScriptcnf); /* Dump the config script */ /* Examine our list, and try to take the corresponding */ /* common section data from it to add to your script */ { rc_section_t *pComsec = NULL; pComsec = rcfileGetsec(listGetrcfile(pRc->m_pList, \ ppSectmp[nTmp]->m_szParent), configGetval(RC_CMN_VAL)); if (pComsec) { /* Do we have a common section to load? */ if (configGetval(RC_VRB_VAL)) { szTmp = (char *)sectionGetname(pComsec); nBytes = (strlen(RC_PRN_TEXT) + strlen(szTmp) + \ strlen (sectionGetparent(pComsec)) + \ strlen(RC_ECHO_STR) + strlen("\"\"") + 1) * \ sizeof (char); szVerbose = malloc(nBytes); sprintf(szVerbose, RC_PRN_TEXT, szTmp, sectionGetparent(pComsec)); strcat(szVerbose, "\n"); fprintf(stderr, "%s", szVerbose); free(szVerbose); szVerbose = NULL; } sectionDump(pComsec); } } if (configGetval(RC_VRB_VAL)) { /* Conditionally print each section notice in verbal mode */ szTmp = (char *)sectionGetname(ppSectmp[nTmp]); nBytes = (strlen(RC_PRN_TEXT) + strlen(szTmp) + 2) * sizeof (char); szVerbose = malloc(nBytes); sprintf(szVerbose, RC_PRN_TEXT, szTmp, sectionGetparent(ppSectmp[nTmp])); strcat(szVerbose, "\n"); fprintf(stderr, "%s", szVerbose); free(szVerbose); szVerbose = NULL; } sectionDump(ppSectmp[nTmp]); } } free(ppSectmp); ppSectmp = NULL; return(RC_THROW(RC_OK)); } /************************************************ * procParse(rc_proc_t *) * * Parse the run-command script * ************************************************/ rc_return_t procParse(rc_proc_t *pRc) { rc_section_t **ppSectmp = NULL; /* Used with priority scheduling */ int nTmp = 0; /* Generic index */ short nRcs = 0; /* Rc index */ short nSecs = 0; /* Section index */ short nTotalsecs = vectorCount(configGetsecs()); /* Sections */ /* Allocate a block of section pointers to use as a temporary */ ppSectmp = calloc(pRc->m_pList->m_nFiles, sizeof(rc_section_t *)); fprintf(stderr, "file %s, section %s\n", pRc->m_pList->m_ppFilevec[nRcs]->m_szName, RC_DEF_NCF); for (nSecs = 0; nSecs < nTotalsecs; nSecs++) { for (nRcs = 0; nRcs < pRc->m_pList->m_nFiles; nRcs++) { for (nTmp = 0; nTmp < pRc->m_pList->m_ppFilevec[nRcs]->m_nSecs && \ strcmp(pRc->m_pList->m_ppFilevec[nRcs]->m_ppSecvec[nTmp]->m_szName, \ configGetsecs()[nSecs]); nTmp++); if (nTmp < pRc->m_pList->m_ppFilevec[nRcs]->m_nSecs) ppSectmp[nRcs] = pRc->m_pList->m_ppFilevec[nRcs]->m_ppSecvec[nTmp]; else ppSectmp[nRcs] = NULL; } qsort((void *)ppSectmp, (size_t)pRc->m_pList->m_nFiles, sizeof(rc_section_t *), priCompare); for (nTmp = 0; nTmp < pRc->m_pList->m_nFiles && ppSectmp[nTmp]; nTmp++) fprintf(stderr, "section %s\n", ppSectmp[nTmp]->m_szName); } free(ppSectmp); ppSectmp = NULL; return(RC_THROW(RC_OK)); } /************************************************ * procDelete(rc_proc_t *) * * Destruct a processor * ************************************************/ rc_return_t procDelete(rc_proc_t *pRc) { int nRcs = pRc->m_pList->m_nFiles; scriptDelete(pRc->m_pScriptcnf); /* Destroy the config script */ pRc->m_pScriptcnf = NULL; scriptDelete(pRc->m_pScriptfunc); /* Destroy the funcs script */ pRc->m_pScriptfunc = NULL; /* Destroy the rcfile objects */ while (nRcs-- > 0) if (rcfileExists(pRc->m_pList->m_ppFilevec[nRcs])) { rcfileDelete(pRc->m_pList->m_ppFilevec[nRcs]); pRc->m_pList->m_ppFilevec[nRcs] = NULL; } free(pRc->m_pList->m_ppFilevec); pRc->m_pList->m_ppFilevec = NULL; listDelete(pRc->m_pList); /* Destroy the rcfile list */ pRc->m_pList = NULL; free(pRc); /* Free the processor itself */ pRc = NULL; return(RC_THROW(RC_OK)); }