/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright Likewise Software 2004-2008
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Copyright Likewise Software 2004-2008
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the license, or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy
* of the GNU Lesser General Public License along with this program. If
* not, see .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
#include "config.h"
#include "ctbase.h"
static
void
CTFreeNVPair(
PNVPAIR pNVPair
)
{
if (pNVPair->pszName)
CTFreeString(pNVPair->pszName);
if (pNVPair->pszValue)
CTFreeString(pNVPair->pszValue);
CTFreeMemory(pNVPair);
}
static
void
CTFreeNVPairList(
PNVPAIR pNVPairList
)
{
PNVPAIR pNVPair = NULL;
while (pNVPairList) {
pNVPair = pNVPairList;
pNVPairList = pNVPairList->pNext;
CTFreeNVPair(pNVPair);
}
}
static
void
CTFreeSection(
PCFGSECTION pSection
)
{
if (pSection->pszName)
CTFreeString(pSection->pszName);
if (pSection->pNVPairList)
CTFreeNVPairList(pSection->pNVPairList);
CTFreeMemory(pSection);
}
static
PNVPAIR
ReverseNVPairList(
PNVPAIR pNVPairList
)
{
PNVPAIR pP = NULL;
PNVPAIR pQ = pNVPairList;
PNVPAIR pR = NULL;
while (pQ) {
pR = pQ->pNext;
pQ->pNext = pP;
pP = pQ;
pQ = pR;
}
return pP;
}
static
PCFGSECTION
ReverseSectionsAndNVPairs(
PCFGSECTION pSectionList
)
{
PCFGSECTION pP = NULL;
PCFGSECTION pQ = pSectionList;
PCFGSECTION pR = NULL;
while (pQ) {
if (pQ->pNVPairList) {
pQ->pNVPairList = ReverseNVPairList(pQ->pNVPairList);
}
pR = pQ->pNext;
pQ->pNext = pP;
pP = pQ;
pQ = pR;
}
return pP;
}
void
CTFreeConfigSectionList(
PCFGSECTION pSectionList
)
{
PCFGSECTION pSection = NULL;
while (pSectionList) {
pSection = pSectionList;
pSectionList = pSectionList->pNext;
CTFreeSection(pSection);
}
}
static
CENTERROR
ParseHeader(
FILE* fp,
PDWORD pdwSignature)
{
CENTERROR ceError = CENTERROR_SUCCESS;
uint16_t wSignature = 0;
if (1 != fread(&wSignature, sizeof(wSignature), 1, fp)) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
*pdwSignature = CONVERT_ENDIAN_WORD(wSignature);
error:
return ceError;
}
static
CENTERROR
ReadNextDoubleByteLine(
FILE* fp,
PSTR pszBuf,
DWORD dwMaxLen,
PBOOLEAN pbEndOfFile
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
DBLBYTE dbBuf;
PSTR pszTmp = pszBuf;
DWORD iBuf = 0;
*pbEndOfFile = 0;
while ((iBuf < dwMaxLen)) {
if (1 != fread(&dbBuf, sizeof(dbBuf), 1, fp)) {
if (feof(fp)) {
*pbEndOfFile = 1;
break;
} else {
ceError = CTMapSystemError(ceError);
BAIL_ON_CENTERIS_ERROR(ceError);
}
}
if ((*pszTmp++ = dbBuf.b1) == '\n')
break;
iBuf++;
}
if (iBuf == dwMaxLen) {
ceError = CENTERROR_CFG_NOT_ENOUGH_BUFFER;
BAIL_ON_CENTERIS_ERROR(ceError);
}
*pszTmp = '\0';
error:
return ceError;
}
CENTERROR
CTParseConfigFile(
PCSTR pszFilePath,
PCFGSECTION* ppCfgSectionList,
BOOLEAN bWindowsDoubleByteFormat
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCFGSECTION pSectionList = NULL;
PCFGSECTION pSection = NULL;
PNVPAIR pNVPair = NULL;
FILE* fp = NULL;
CHAR staticBuffer[1024+1];
PSTR szBuf = NULL;
DWORD dwLen = 0;
PSTR pszTmp = NULL;
PSTR pszName = NULL;
PSTR pszValue = NULL;
DWORD dwSignature = 0;
/*DWORD nRead = 0;*/
BOOLEAN bEOF = FALSE;
if ((fp = fopen(pszFilePath, "r")) == NULL) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (fcntl(fileno(fp), F_SETFD, FD_CLOEXEC) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (bWindowsDoubleByteFormat) {
ceError = ParseHeader(fp, &dwSignature);
BAIL_ON_CENTERIS_ERROR(ceError);
if (dwSignature != 0xFEFF) {
ceError = CENTERROR_CFG_INVALID_SIGNATURE;
BAIL_ON_CENTERIS_ERROR(ceError);
}
}
while (!bEOF) {
CT_SAFE_FREE_STRING(szBuf);
if (bWindowsDoubleByteFormat) {
staticBuffer[0] = '\0';
ceError = ReadNextDoubleByteLine(fp, staticBuffer, 1024, &bEOF);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTStrdup(staticBuffer, &szBuf);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
ceError = CTReadNextLine(fp, &szBuf, &bEOF);
BAIL_ON_CENTERIS_ERROR(ceError);
}
CTStripWhitespace(szBuf);
if (!(dwLen=strlen(szBuf)))
continue;
/* Skip comments for now */
if (szBuf[0] == ';')
continue;
if ((szBuf[0] == '[' &&
szBuf[dwLen-1] == ']') ||
(szBuf[0] == '#' && (!pSection || pSection->pszName[0] == '#'))) {
if (pSection) {
pSection->pNext = pSectionList;
pSectionList = pSection;
pSection = NULL;
}
ceError = CTAllocateMemory(sizeof(CFGSECTION), (PVOID*)&pSection);
BAIL_ON_CENTERIS_ERROR(ceError);
if (szBuf[0] == '#') {
szBuf[dwLen] = '\0';
ceError = CTAllocateString(szBuf, &pSection->pszName);
} else {
szBuf[dwLen-1] = '\0';
ceError = CTAllocateString(szBuf+1, &pSection->pszName);
}
BAIL_ON_CENTERIS_ERROR(ceError);
CTStripWhitespace(pSection->pszName);
} else {
if (szBuf[0] == '#' && pSection) {
szBuf[dwLen] = '\0';
ceError = CTAllocateString(szBuf, &pszName);
BAIL_ON_CENTERIS_ERROR(ceError);
strncpy(pszName, szBuf, strlen(szBuf));
} else {
if (!pSection) {
ceError = CENTERROR_VALUE_NOT_IN_SECTION;
BAIL_ON_CENTERIS_ERROR(ceError);
}
if ((pszTmp = strchr(szBuf, '=')) == NULL) {
ceError = CENTERROR_BAD_TOKEN;
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (pszTmp == szBuf) {
ceError = CENTERROR_BAD_TOKEN;
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTAllocateMemory(pszTmp-szBuf+1, (PVOID*)&pszName);
BAIL_ON_CENTERIS_ERROR(ceError);
strncpy(pszName, szBuf, pszTmp-szBuf);
pszTmp++;
while (*pszTmp != '\0' && isspace((int)*pszTmp))
pszTmp++;
if (*pszTmp != '\0') {
ceError = CTAllocateString(pszTmp, &pszValue);
BAIL_ON_CENTERIS_ERROR(ceError);
}
}
ceError = CTAllocateMemory(sizeof(NVPAIR), (PVOID*)&pNVPair);
BAIL_ON_CENTERIS_ERROR(ceError);
CTStripWhitespace(pszName);
CTStripWhitespace(pszValue);
pNVPair->pszName = pszName; pszName = NULL;
pNVPair->pszValue = pszValue; pszValue = NULL;
pNVPair->pNext = pSection->pNVPairList;
pSection->pNVPairList = pNVPair;
pNVPair = NULL;
}
}
if (pSection) {
pSection->pNext = pSectionList;
pSectionList = pSection;
pSection = NULL;
}
pSectionList = ReverseSectionsAndNVPairs(pSectionList);
*ppCfgSectionList = pSectionList;
pSectionList = NULL;
fclose(fp); fp = NULL;
error:
CT_SAFE_FREE_STRING(szBuf);
if (fp) {
fclose(fp);
}
if (pszName)
CTFreeString(pszName);
if (pszValue)
CTFreeString(pszValue);
if (pNVPair)
CTFreeNVPair(pNVPair);
if (pSection)
CTFreeSection(pSection);
if (pSectionList)
CTFreeConfigSectionList(pSectionList);
return ceError;
}
CENTERROR
CTSaveConfigSectionListToFile(
FILE* fp,
PCFGSECTION pSectionList
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PNVPAIR pNVPair = NULL;
while (pSectionList) {
if (IsNullOrEmptyString(pSectionList->pszName)) {
ceError = CENTERROR_CFG_INVALID_SECTION_NAME;
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (pSectionList->pszName[0] == '#') {
ceError = CTFilePrintf(fp, "%s\n", pSectionList->pszName);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
ceError = CTFilePrintf(fp, "[%s]\n", pSectionList->pszName);
BAIL_ON_CENTERIS_ERROR(ceError);
pNVPair = pSectionList->pNVPairList;
while (pNVPair) {
if (IsNullOrEmptyString(pNVPair->pszName)) {
ceError = CENTERROR_CFG_INVALID_NVPAIR_NAME;
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (pNVPair->pszName[0] == '#') {
CTFilePrintf( fp, " %s\n",
pNVPair->pszName);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
CTFilePrintf( fp, " %s = %s\n",
pNVPair->pszName,
(IsNullOrEmptyString(pNVPair->pszValue) ? "" : pNVPair->pszValue));
BAIL_ON_CENTERIS_ERROR(ceError);
}
pNVPair = pNVPair->pNext;
}
}
pSectionList = pSectionList->pNext;
}
error:
return ceError;
}
CENTERROR
CTSaveConfigSectionList(
PCSTR pszConfigFilePath,
PCFGSECTION pSectionList
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
/*PNVPAIR pNVPair = NULL;*/
FILE* fp = NULL;
PSTR pszTmpPath = NULL;
BOOLEAN bRemoveFile = FALSE;
ceError = CTAllocateMemory(strlen(pszConfigFilePath)+strlen(".gpagent")+1,
(PVOID*)&pszTmpPath);
BAIL_ON_CENTERIS_ERROR(ceError);
sprintf(pszTmpPath, "%s.gpagent", pszConfigFilePath);
if ((fp = fopen(pszTmpPath, "w")) == NULL) {
ceError = CTMapSystemError(ceError);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (fcntl(fileno(fp), F_SETFD, FD_CLOEXEC) < 0) {
ceError = CTMapSystemError(errno);
BAIL_ON_CENTERIS_ERROR(ceError);
}
bRemoveFile = TRUE;
ceError = CTSaveConfigSectionListToFile(fp, pSectionList);
BAIL_ON_CENTERIS_ERROR(ceError);
fclose(fp); fp = NULL;
ceError = CTMoveFile(pszTmpPath, pszConfigFilePath);
BAIL_ON_CENTERIS_ERROR(ceError);
if (pszTmpPath)
CTFreeString(pszTmpPath);
return ceError;
error:
if (bRemoveFile)
CTRemoveFile(pszTmpPath);
if (fp)
fclose(fp);
if (pszTmpPath)
CTFreeString(pszTmpPath);
return ceError;
}
CENTERROR
CTCreateConfigSection(
PCFGSECTION* ppSectionList,
PCFGSECTION* pCreatedSection,
PCSTR pszSectionName
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCFGSECTION pSectionList = NULL;
PCFGSECTION pSection = NULL;
PCFGSECTION pTmpSection = NULL;
if (!ppSectionList || IsNullOrEmptyString(pszSectionName)) {
ceError = CENTERROR_INVALID_PARAMETER;
BAIL_ON_CENTERIS_ERROR(ceError);
}
pSectionList = *ppSectionList;
pSection = pSectionList;
while (pSection)
{
if (!strcmp(pSection->pszName, pszSectionName))
break;
pSection = pSection->pNext;
}
if (!pSection)
{
ceError = CTAllocateMemory(sizeof(CFGSECTION), (PVOID*)&pSection);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTAllocateString(pszSectionName, &pSection->pszName);
BAIL_ON_CENTERIS_ERROR(ceError);
if (!pSectionList)
{
pSectionList = pSection;
}
else
{
pTmpSection = pSectionList;
while (pTmpSection->pNext)
pTmpSection = pTmpSection->pNext;
pTmpSection->pNext = pSection;
}
}
*pCreatedSection = pSection;
pSection = NULL;
*ppSectionList = pSectionList;
return ceError;
error:
if (pSection)
CTFreeSection(pSection);
*pCreatedSection = NULL;
return ceError;
}
CENTERROR
CTGetConfigValueBySectionName(
PCFGSECTION pSectionList,
PCSTR pszSectionName,
PCSTR pszName,
PSTR* ppszValue
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCFGSECTION pSection = NULL;
while (pSectionList) {
if (!strcmp(pSectionList->pszName, pszSectionName)) {
pSection = pSectionList;
break;
}
pSectionList = pSectionList->pNext;
}
if (!pSection) {
ceError = CENTERROR_CFG_SECTION_NOT_FOUND;
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTGetConfigValueBySection(pSection,
pszName,
ppszValue);
goto error; /* Not uncommon, no need to log error. */
error:
return ceError;
}
CENTERROR
CTSetConfigValueBySectionName(
PCFGSECTION pSectionList,
PCSTR pszSectionName,
PCSTR pszName,
PCSTR pszValue
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCFGSECTION pSection = NULL;
PNVPAIR pNVPair = NULL;
/*PNVPAIR pTmpNVPair = NULL;*/
if (IsNullOrEmptyString(pszSectionName) ||
IsNullOrEmptyString(pszName)) {
ceError = CENTERROR_INVALID_PARAMETER;
BAIL_ON_CENTERIS_ERROR(ceError);
}
pSection = pSectionList;
while (pSection)
{
if (!strcmp(pSection->pszName, pszSectionName))
{
break;
}
pSection = pSection->pNext;
}
if (!pSection)
{
ceError = CTCreateConfigSection(&pSectionList, &pSection, pszSectionName);
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTSetConfigValueBySection(pSection,
pszName,
pszValue);
BAIL_ON_CENTERIS_ERROR(ceError);
return ceError;
error:
if (pNVPair)
{
CTFreeNVPair(pNVPair);
}
return ceError;
}
CENTERROR
CTDeleteConfigSection(
PCFGSECTION* ppSectionList,
PCSTR pszSectionName
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCFGSECTION pSection = NULL;
PCFGSECTION pIterSection = *ppSectionList;
PCFGSECTION pPrevSection = NULL;
if (IsNullOrEmptyString(pszSectionName)) {
ceError = CENTERROR_INVALID_PARAMETER;
BAIL_ON_CENTERIS_ERROR(ceError);
}
while (pIterSection) {
if (!strcmp(pszSectionName, pIterSection->pszName)) {
pSection = pIterSection;
break;
}
pPrevSection = pIterSection;
pIterSection = pIterSection->pNext;
}
if (pSection) {
if (!pPrevSection) {
*ppSectionList = pSection->pNext;
} else {
pPrevSection->pNext = pSection->pNext;
}
CTFreeSection(pSection);
}
error:
return ceError;
}
CENTERROR
CTDeleteNameValuePairBySection(
PCFGSECTION pSection,
PCSTR pszName
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PNVPAIR pNVPair = NULL;
PNVPAIR pPrevNVPair = NULL;
pNVPair = pSection->pNVPairList;
while (pNVPair) {
if (!strcmp(pNVPair->pszName, pszName)) {
break;
}
pPrevNVPair = pNVPair;
pNVPair = pNVPair->pNext;
}
if (pNVPair != NULL) {
if (pPrevNVPair) {
pPrevNVPair->pNext = pNVPair->pNext;
} else {
pSection->pNVPairList = pNVPair->pNext;
}
CTFreeNVPair(pNVPair);
}
/*error:*/
return ceError;
}
CENTERROR
CTDeleteNameValuePairBySectionName(
PCFGSECTION pSectionList,
PCSTR pszSectionName,
PCSTR pszName
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PCFGSECTION pSection = NULL;
if (IsNullOrEmptyString(pszSectionName) ||
IsNullOrEmptyString(pszName)) {
ceError = CENTERROR_INVALID_PARAMETER;
BAIL_ON_CENTERIS_ERROR(ceError);
}
while (pSectionList) {
if (!strcmp(pszSectionName, pszName)) {
pSection = pSectionList;
break;
}
pSectionList = pSectionList->pNext;
}
if (!pSection) {
ceError = CENTERROR_CFG_SECTION_NOT_FOUND;
BAIL_ON_CENTERIS_ERROR(ceError);
}
ceError = CTDeleteNameValuePairBySection(pSection, pszName);
BAIL_ON_CENTERIS_ERROR(ceError);
error:
return ceError;
}
CENTERROR
CTGetConfigValueBySection(
PCFGSECTION pSection,
PCSTR pszName,
PSTR* ppszValue
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PNVPAIR pNVPair = NULL;
pNVPair = pSection->pNVPairList;
while (pNVPair) {
if (!strcmp(pNVPair->pszName, pszName))
break;
pNVPair = pNVPair->pNext;
}
if (!pNVPair) {
ceError = CENTERROR_CFG_VALUE_NOT_FOUND;
goto error; /* Not uncommon, no need to log error. */
}
if (pNVPair->pszValue) {
ceError = CTAllocateString(pNVPair->pszValue, ppszValue);
BAIL_ON_CENTERIS_ERROR(ceError);
} else {
*ppszValue = NULL;
}
error:
return ceError;
}
CENTERROR
CTSetConfigValueBySection(
PCFGSECTION pSection,
PCSTR pszName,
PCSTR pszValue
)
{
CENTERROR ceError = CENTERROR_SUCCESS;
PNVPAIR pNVPair = NULL;
PNVPAIR pTmpNVPair = NULL;
pTmpNVPair = pSection->pNVPairList;
while (pTmpNVPair) {
if (!strcmp(pTmpNVPair->pszName, pszName)) {
pNVPair = pTmpNVPair;
break;
}
pTmpNVPair = pTmpNVPair->pNext;
}
if (pNVPair == NULL) {
ceError = CTAllocateMemory(sizeof(NVPAIR), (PVOID*)&pNVPair);
BAIL_ON_CENTERIS_ERROR(ceError);
ceError = CTAllocateString(pszName, &pNVPair->pszName);
BAIL_ON_CENTERIS_ERROR(ceError);
CTStripWhitespace(pNVPair->pszName);
if (!IsNullOrEmptyString(pszValue)) {
ceError = CTAllocateString(pszValue, &pNVPair->pszValue);
BAIL_ON_CENTERIS_ERROR(ceError);
}
if (!pSection->pNVPairList) {
pSection->pNVPairList = pNVPair;
pNVPair = NULL;
} else {
pTmpNVPair = pSection->pNVPairList;
while (pTmpNVPair->pNext != NULL)
pTmpNVPair = pTmpNVPair->pNext;
pTmpNVPair->pNext = pNVPair;
pNVPair = NULL;
}
} else {
if (pNVPair->pszValue) {
CTFreeString(pNVPair->pszValue);
pNVPair->pszValue = NULL;
if (!IsNullOrEmptyString(pszValue)) {
ceError = CTAllocateString(pszValue, &pNVPair->pszValue);
BAIL_ON_CENTERIS_ERROR(ceError);
}
}
}
return ceError;
error:
if (pNVPair) {
CTFreeNVPair(pNVPair);
}
return ceError;
}