void plainconf::loadDirectory(const char *pPath, const char *pPattern) { DIR *pDir = opendir(pPath); if (!pDir) { logToMem(LOG_LEVEL_ERR, "Failed to open directory [%s].", pPath); return ; } struct dirent *dir_ent; char str[4096] = {0}; strcpy(str, pPath); strcatchr(str, '/', 4096); int offset = strlen(str); StringList AllEntries; while ((dir_ent = readdir(pDir))) { const char *pName = dir_ent->d_name; if ((strcmp(pName, ".") == 0) || (strcmp(pName, "..") == 0) || (*(pName + strlen(pName) - 1) == '~')) continue; if (pPattern) { //Beside the unmatch, also must exclude *,v which was created by rcs if(fnmatch(pPattern, pName, FNM_PATHNAME) != 0 || fnmatch("*,v", pName, FNM_PATHNAME) == 0) continue; } strcpy(str + offset, pName); struct stat st; if (stat(str, &st) == 0) { if (S_ISDIR(st.st_mode) || pPattern || fnmatch("*.conf", pName, FNM_PATHNAME) == 0) AllEntries.add(str); } } closedir(pDir); AllEntries.sort(); StringList::iterator iter; for (iter = AllEntries.begin(); iter != AllEntries.end(); ++iter) { const char *pName = (*iter)->c_str(); logToMem(LOG_LEVEL_INFO, "Processing config file: %s", pName); loadConfFile(pName); } }
void plainconf::loadDirectory(const char *pPath, const char *pPattern) { DIR *pDir = opendir(pPath); if (!pDir) { logToMem(LOG_LEVEL_ERR, "Failed to open directory [%s].", pPath); return ; } struct dirent *dir_ent; StringList AllEntries; while ((dir_ent = readdir(pDir))) { const char *pName = dir_ent->d_name; if ((strcmp(pName, ".") == 0) || (strcmp(pName, "..") == 0) || (*(pName + strlen(pName) - 1) == '~')) continue; if (pPattern) { if (fnmatch(pPattern, pName, FNM_PATHNAME)) continue; } char str[4096] = {0}; strcpy(str, pPath); strcatchr(str, '/', 4096); strcat(str, pName); AllEntries.add(str); } closedir(pDir); //Sort the filename order AllEntries.sort(); StringList::iterator iter; for (iter = AllEntries.begin(); iter != AllEntries.end(); ++iter) { const char *p = (*iter)->c_str(); logToMem(LOG_LEVEL_INFO, "Processing config file: %s", p); loadConfFile(p); } }
void plainconf::addModuleWithParam(XmlNode *pCurNode, const char *moduleName, const char *param) { XmlNode *pModuleNode = NULL; XmlNodeList::const_iterator iter; const XmlNodeList *pModuleList = pCurNode->getChildren("module"); if (pModuleList) { for (iter = pModuleList->begin(); iter != pModuleList->end(); ++iter) { if (strcasecmp((*iter)->getChildValue("name", 1), moduleName) == 0) { pModuleNode = (*iter); break; } } } if (!pModuleNode) { pModuleNode = new XmlNode; //XmlNode *pParamNode = new XmlNode; const char *attr = NULL; pModuleNode->init("module", &attr); pModuleNode->setValue(moduleName, strlen(moduleName)); pCurNode->addChild(pModuleNode->getName(), pModuleNode); logToMem(LOG_LEVEL_INFO, "[%s:%s]addModuleWithParam ADD module %s", pCurNode->getName(), pCurNode->getValue(), moduleName); } appendModuleParam(pModuleNode, param); }
void plainconf::appendModuleParam(XmlNode *pModuleNode, const char *param) { XmlNode *pParamNode = pModuleNode->getChild("param"); if (pParamNode == NULL) { pParamNode = new XmlNode; const char *attr = NULL; pParamNode->init("param", &attr); pParamNode->setValue(param, strlen(param)); pModuleNode->addChild(pParamNode->getName(), pParamNode); } else { AutoStr2 totalValue = pParamNode->getValue(); totalValue.append("\n", 1); totalValue.append(param, strlen(param)); pParamNode->setValue(totalValue.c_str(), totalValue.len()); } logToMem(LOG_LEVEL_INFO, "[%s:%s] module [%s] add param [%s]", pModuleNode->getParent()->getName(), ((pModuleNode->getParent()->getValue()) ? pModuleNode->getParent()->getValue() : ""), pModuleNode->getValue(), param); }
//return the root node of the tree XmlNode *plainconf::parseFile(const char *configFilePath, const char *rootTag) { #ifdef TEST_OUTPUT_PLAIN_CONF char *tmp = (char *)new char[5 * 1024 * 1024]; if (tmp) delete []tmp; #endif XmlNode *rootNode = new XmlNode; const char *attr = NULL; rootNode->init(rootTag, &attr); gModuleList.push_back(rootNode); loadConfFile(configFilePath); if (gModuleList.size() != 1) logToMem(LOG_LEVEL_ERR, "parseFile find '{' and '}' do not match in the end of file %s, rootTag %s.", configFilePath, rootTag); gModuleList.clear(); handleSpecialCaseLoop(rootNode); #ifdef TEST_OUTPUT_PLAIN_CONF char sPlainFile[512] = {0}; strcpy(sPlainFile, configFilePath); strcat(sPlainFile, ".txt"); plainconf::testOutputConfigFile(rootNode, sPlainFile); #endif return rootNode; }
void plainconf::getIncludeFile(const char *orgFile, char *targetFile) { int len = strlen(orgFile); if (len == 0) return; //Absolute path if (orgFile[0] == '/') strcpy(targetFile, orgFile); else if (orgFile[0] == '$') { if (strncasecmp(orgFile, "$server_root/", 13) == 0) { strcpy(targetFile, rootPath.c_str()); strcat(targetFile, orgFile + 13); } else { logToMem(LOG_LEVEL_ERR, "Can't resolve include file %s", orgFile); return ; } } else { strcpy(targetFile, rootPath.c_str()); strcat(targetFile, orgFile); } }
//When checking we use lock for may need to update the conf file later //If user RCS checkout a revision, a unlock should be used for next time checkin. //Example: co -u1.1 httpd_config.conf void plainconf::checkInFile(const char *path) { if (access(path, 0) == -1) return ; //Backup file abd checkin and out char new_path[4096]; strcpy(new_path, path); strcat(new_path, "0"); AutoStr2 buf; buf.setStr("cp \""); buf.append(path, strlen(path)); buf.append("\" \"", 3); buf.append(new_path, strlen(new_path)); buf.append("\"", 1); int ret = system(buf.c_str()); if (ret != 0) { logToMem(LOG_LEVEL_INFO, "Failed to backup the conf file %s, ret %d.", path, ret); return ; } buf.setStr("ci -l -q -t-\""); buf.append(new_path, strlen(new_path)); buf.append("\" -mUpdate \"", 12); buf.append(new_path, strlen(new_path)); buf.append("\" >/dev/null 2>&1", 17); ret = system(buf.c_str()); if (ret == 0) logToMem(LOG_LEVEL_INFO, "RCS checkin config file %s OK.", new_path); else logToMem(LOG_LEVEL_INFO, "Failed to RCS checkin conf file %s, ret %d, error(%s). " "Org command is %s.", new_path, ret, strerror(errno), buf.c_str()); unlink(new_path); }
void plainconf::saveUnknownItems(const char *fileName, int lineNumber, XmlNode *pCurNode, const char *name, const char *value) { //if not inside a "module" and without a "::", treated as error if (strcasecmp(pCurNode->getName(), "module") != 0 && strstr(name, "::") == NULL) { logToMem(LOG_LEVEL_ERR, "Not support [%s %s] in file %s:%d", name, value, fileName, lineNumber); return ; } char newvalue[4096] = {0}; XmlNode *pParamNode = new XmlNode; const char *attr = NULL; pParamNode->init(UNKNOWN_KEYWORDS, &attr); strcpy(newvalue, name); strcat(newvalue, " "); strcat(newvalue, value); pParamNode->setValue(newvalue, strlen(newvalue)); pCurNode->addChild(pParamNode->getName(), pParamNode); }
void plainconf::parseLine(const char *fileName, int lineNumber, const char *sLine) { const int MAX_NAME_LENGTH = 4096; char name[MAX_NAME_LENGTH] = {0}; char value[MAX_NAME_LENGTH] = {0}; const char *attr = NULL; XmlNode *pNode = NULL; XmlNode *pCurNode = (XmlNode *)gModuleList.back(); const char *p = sLine; const char *pEnd = sLine + strlen(sLine); bool bNameSet = false; for (; p < pEnd; ++p) { //"{" is a beginning of a block only if it is the last char of a line if (*p == '{' && pEnd - p == 1) { if (strlen(name) > 0) { const char *pRealname = getRealName(name); if (pRealname) { pNode = new XmlNode; pNode->init(pRealname, &attr); //Remove space in the end of the value such as "module cache {", value will be "cache" removeSpace(value, 1); if (strlen(value) > 0) pNode->setValue(value, strlen(value)); pCurNode->addChild(pNode->getName(), pNode); gModuleList.push_back(pNode); pCurNode = pNode; clearNameAndValue(name, value); break; } else { logToMem(LOG_LEVEL_ERR, "parseline find block name [%s] is NOT keyword in %s:%d", name, fileName, lineNumber); break; } } else { logToMem(LOG_LEVEL_ERR, "parseline found '{' without a block name in %s:%d", fileName, lineNumber); break; } } else if (*p == '}' && p == sLine) { if (gModuleList.size() > 1) { gModuleList.pop_back(); clearNameAndValue(name, value); if (*(p + 1)) { ++p; trimWhiteSpace(&p); parseLine(fileName, lineNumber, p); break; } } else { logToMem(LOG_LEVEL_ERR, "parseline found more '}' in %s:%d", fileName, lineNumber); clearNameAndValue(name, value); break; } } else if ((*p == ' ' || *p == '\t') && value[0] == 0) { bNameSet = true; continue; } else { if (!bNameSet) strcatchr(name, *p, MAX_NAME_LENGTH); else strcatchr(value, *p, MAX_NAME_LENGTH); } } if (name[0] != 0) { const char *pRealname = getRealName(name); if (pRealname) { assert(pNode == NULL); pNode = new XmlNode; pNode->init(pRealname, &attr); if (strlen(value) > 0) pNode->setValue(value, strlen(value)); pCurNode->addChild(pNode->getName(), pNode); } else { //There is no special case in server level //if (memcmp(pCurNode->getName(), SERVER_ROOT_XML_NAME, sizeof(SERVER_ROOT_XML_NAME) - 1) != 0) saveUnknownItems(fileName, lineNumber, pCurNode, name, value); //else // logToMem(LOG_LEVEL_ERR, "%s Server level find unknown keyword [%s], ignored.", SERVER_ROOT_XML_NAME, name ); } } }
void plainconf::handleSpecialCase(XmlNode *pNode) { const XmlNodeList *pUnknownList = pNode->getChildren(UNKNOWN_KEYWORDS); if (!pUnknownList) return ; int bModuleNode = (strcasecmp(pNode->getName(), "module") == 0); XmlNodeList::const_iterator iter; for (iter = pUnknownList->begin(); iter != pUnknownList->end(); ++iter) { const char *value = (*iter)->getValue(); if (bModuleNode) appendModuleParam(pNode, value); else { const char *p = strstr(value, "::"); //Only hanlde has :: case if (p) { /** * CASE such as cache::enablecache 1, will be treated as * module chace { * param enablecache 1 * } */ char newname[1024] = {0}; char newvalue[4096] = {0}; strncpy(newname, value, p - value); strcpy(newvalue, p + 2); XmlNode *pRootNode = pNode; while (pRootNode->getParent()) pRootNode = pRootNode->getParent(); const XmlNodeList *pModuleList = pRootNode->getChildren("module"); if (pModuleList) { XmlNodeList::const_iterator iter2; for (iter2 = pModuleList->begin(); iter2 != pModuleList->end(); ++iter2) { if (strcasecmp((*iter2)->getValue(), newname) == 0) { addModuleWithParam(pNode, newname, newvalue); break; } } if (iter2 == pModuleList->end()) logToMem(LOG_LEVEL_ERR, "Module[%s] not defined in server leve while checking [%s].", newname, value); } else logToMem(LOG_LEVEL_ERR, "No module defined in server leve while checking [%s].", value); } } } }
//This function may be recruse called void plainconf::loadConfFile(const char *path) { logToMem(LOG_LEVEL_INFO, "start parsing file %s", path); int type = checkFiletype(path); if (type == 0) return; else if (type == 2) loadDirectory(path, NULL); else if (type == 3) { AutoStr2 prefixPath = path; const char *p = strrchr(path, '/'); if (p) prefixPath.setStr(path, p - path); struct stat sb; //removed the wildchar filename, should be a directory if exist if (stat(prefixPath.c_str(), &sb) == -1) { logToMem(LOG_LEVEL_ERR, "LoadConfFile error 1, path:%s directory:%s", path, prefixPath.c_str()); return ; } if ((sb.st_mode & S_IFMT) != S_IFDIR) { logToMem(LOG_LEVEL_ERR, "LoadConfFile error 2, path:%s directory:%s", path, prefixPath.c_str()); return ; } loadDirectory(prefixPath.c_str(), p + 1); } else //existed file { //gModuleList.push_back(); //XmlNode *xmlNode = new XmlNode; FILE *fp = fopen(path, "r"); if (fp == NULL) { logToMem(LOG_LEVEL_ERR, "Cannot open configuration file: %s", path); return; } const int MAX_LINE_LENGTH = 8192; char sLine[MAX_LINE_LENGTH]; char *p; char sLines[MAX_LINE_LENGTH] = {0}; int lineNumber = 0; const int MAX_MULLINE_SIGN_LENGTH = 128; char sMultiLineModeSign[MAX_MULLINE_SIGN_LENGTH] = {0}; size_t nMultiLineModeSignLen = 0; //>0 is mulline mode while (fgets(sLine, MAX_LINE_LENGTH, fp), !feof(fp)) { ++lineNumber; p = sLine; if (nMultiLineModeSignLen) { //Check if reach the END of the milline mode size_t len = 0; const char *pLineStart = getStrNoSpace(p, len); if (len == nMultiLineModeSignLen && strncasecmp(pLineStart, sMultiLineModeSign, nMultiLineModeSignLen) == 0) { nMultiLineModeSignLen = 0; removeSpace(sLines, 1); //Remove the last \r\n so that if it is one line, it will still be one line parseLine(path, lineNumber, sLines); sLines[0] = 0x00; } else strcat(sLines, p); continue; } removeSpace(p, 0); removeSpace(p, 1); if (!isValidline(p)) continue; AutoStr2 pathInclude; if (isInclude(p, pathInclude)) { char achBuf[512] = {0}; getIncludeFile(pathInclude.c_str(), achBuf); loadConfFile(achBuf); } else { nMultiLineModeSignLen = checkMultiLineMode(p, sMultiLineModeSign, MAX_MULLINE_SIGN_LENGTH); if (nMultiLineModeSignLen > 0) strncat(sLines, p, strlen(p) - (3 + nMultiLineModeSignLen)); //need to continue else if (isChunkedLine(p)) { strncat(sLines, p, strlen(p) - 1); //strcatchr(sLines, ' ', MAX_LINE_LENGTH); //add a space at the end of the line which has a '\\' } else { strcat(sLines, p); parseLine(path, lineNumber, sLines); sLines[0] = 0x00; } } } fclose(fp); //Parsed, check in it checkInFile(path); } }