summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2007-07-24 11:33:39 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2007-07-24 11:33:39 +0000
commit5cbb54ed6ad1934875b080286b9933400c817e85 (patch)
tree8c45cde2e6fe16df01a63f45b2a8ef82645308ef
parentf1e14aefde8c295a2cbd93b9118d32961b6c373f (diff)
downloadrsyslog-5cbb54ed6ad1934875b080286b9933400c817e85.tar.gz
rsyslog-5cbb54ed6ad1934875b080286b9933400c817e85.tar.xz
rsyslog-5cbb54ed6ad1934875b080286b9933400c817e85.zip
major task: made sure no selector_t is created for selector lines that can
not be successfully loaded. That forced me to change a lot of code, with potential for trouble.
-rw-r--r--omfile.c37
-rw-r--r--omfwd.c13
-rw-r--r--ommysql.c24
-rw-r--r--omshell.c11
-rw-r--r--omusrmsg.c28
-rw-r--r--rsyslog.h2
-rw-r--r--syslogd.c103
-rw-r--r--syslogd.h6
8 files changed, 125 insertions, 99 deletions
diff --git a/omfile.c b/omfile.c
index 61e4624a..2e7c39f9 100644
--- a/omfile.c
+++ b/omfile.c
@@ -67,8 +67,9 @@ static rsRetVal isCompatibleWithFeature(syslogFeature eFeat)
* removed.
* rgerhards 2005-06-21
*/
-static void cflineParseOutchannel(selector_t *f, uchar* p)
+static rsRetVal cflineParseOutchannel(selector_t *f, uchar* p)
{
+ rsRetVal iRet = RS_RET_OK;
size_t i;
struct outchannel *pOch;
char szBuf[128]; /* should be more than sufficient */
@@ -100,8 +101,7 @@ static void cflineParseOutchannel(selector_t *f, uchar* p)
"outchannel '%s' not found - ignoring action line",
szBuf);
logerror(errMsg);
- f->f_type = F_UNUSED;
- return;
+ return RS_RET_NOT_FOUND;
}
/* check if there is a file name in the outchannel... */
@@ -112,8 +112,7 @@ static void cflineParseOutchannel(selector_t *f, uchar* p)
"outchannel '%s' has no file name template - ignoring action line",
szBuf);
logerror(errMsg);
- f->f_type = F_UNUSED;
- return;
+ return RS_RET_ERR;
}
/* OK, we finally got a correct template. So let's use it... */
@@ -138,10 +137,12 @@ static void cflineParseOutchannel(selector_t *f, uchar* p)
if(szBuf[0] == '\0') /* no template? */
strcpy(szBuf, " TradFmt"); /* use default! */
- cflineSetTemplateAndIOV(f, szBuf);
+ iRet = cflineSetTemplateAndIOV(f, szBuf);
dprintf("[outchannel]filename: '%s', template: '%s', size: %lu\n", f->f_un.f_file.f_fname, szBuf,
f->f_un.f_file.f_sizeLimit);
+
+ return(iRet);
}
@@ -560,6 +561,7 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
* traditional mode lines.
*/
cflineParseOutchannel(f, p);
+ /* TODO: provide status back if successful F_UNUSED */
f->f_un.f_file.bDynamicName = 0;
f->f_un.f_file.fCreateMode = fCreateMode; /* preserve current setting */
f->f_un.f_file.fDirCreateMode = fDirCreateMode; /* preserve current setting */
@@ -571,19 +573,14 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
* a template name. rgerhards, 2007-07-03
*/
++p; /* eat '?' */
- cflineParseFileName(f, p);
+ cflineParseFileName(f, p); /* TODO: check if successful */
f->f_un.f_file.pTpl = tplFind((char*)f->f_un.f_file.f_fname,
strlen((char*) f->f_un.f_file.f_fname));
if(f->f_un.f_file.pTpl == NULL) {
logerrorSz("Template '%s' not found - dynaFile deactivated.", f->f_un.f_file.f_fname);
- f->f_type = F_UNUSED; /* that's it... :( */
- }
- if(f->f_type == F_UNUSED)
- /* safety measure to make sure we have a valid
- * selector line before we continue down below.
- * rgerhards 2005-07-29
- */
+ iRet = RS_RET_NOT_FOUND; /* that's it... :( */
break;
+ }
if(syncfile)
f->f_flags |= SYNC_FILE;
@@ -603,7 +600,7 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
*/
if((f->f_un.f_file.dynCache = (dynaFileCacheEntry**)
calloc(iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))) == NULL) {
- f->f_type = F_UNUSED;
+ iRet = RS_RET_OUT_OF_MEMORY;
dprintf("Could not allocate memory for dynaFileCache - selector disabled.\n");
}
break;
@@ -615,12 +612,7 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
* to use is specified. So we need to scan for the first coma first
* and then look at the rest of the line.
*/
- cflineParseFileName(f, p);
- if(f->f_type == F_UNUSED)
- /* safety measure to make sure we have a valid
- * selector line before we continue down below.
- * rgerhards 2005-07-29
- */
+ if((iRet = cflineParseFileName(f, p)) != RS_RET_OK)
break;
if(syncfile)
@@ -652,6 +644,9 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
break;
}
+ if(iRet == RS_RET_OK)
+ iRet = RS_RET_CONFLINE_PROCESSED;
+
if(iRet == RS_RET_CONFLINE_PROCESSED)
*pp = p;
return iRet;
diff --git a/omfwd.c b/omfwd.c
index 74b4c66e..54811432 100644
--- a/omfwd.c
+++ b/omfwd.c
@@ -414,14 +414,8 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
f->f_un.f_forw.f_addr = res;
}
- /* then try to find the template and re-set f_type to UNUSED
- * if it can not be found. */
- cflineSetTemplateAndIOV(f, szTemplateName);
- if(f->f_type == F_UNUSED)
- /* safety measure to make sure we have a valid
- * selector line before we continue down below.
- * rgerhards 2005-07-29
- */
+ /* then try to find the template */
+ if((iRet = cflineSetTemplateAndIOV(f, szTemplateName)) != RS_RET_OK)
break;
dprintf("forwarding host: '%s:%s/%s' template '%s'\n", q, getFwdSyslogPt(f),
@@ -439,6 +433,9 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
break;
}
+ if(iRet == RS_RET_OK)
+ iRet = RS_RET_CONFLINE_PROCESSED;
+
if(iRet == RS_RET_CONFLINE_PROCESSED)
*pp = p;
return iRet;
diff --git a/ommysql.c b/ommysql.c
index d5613ce8..4d87d950 100644
--- a/ommysql.c
+++ b/ommysql.c
@@ -339,29 +339,23 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
szTemplateName[0] = '\0';
} else {
/* we have a template specifier! */
- cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(char));
+ if((iRet = cflineParseTemplateName(&p, szTemplateName,
+ sizeof(szTemplateName) / sizeof(char))) != RS_RET_OK)
+ break;
}
if(szTemplateName[0] == '\0')
strcpy(szTemplateName, " StdDBFmt");
- cflineSetTemplateAndIOV(f, szTemplateName);
-
- /* we now check if the template was present. If not, we
- * can abort this run as the selector line has been
- * disabled. If we don't abort, we'll core dump
- * below. rgerhards 2005-07-29
- */
- if(f->f_type == F_UNUSED)
+ if((iRet = cflineSetTemplateAndIOV(f, szTemplateName)) != RS_RET_OK)
break;
-
+
dprintf(" template '%s'\n", szTemplateName);
/* If db used, the template have to use the SQL option.
This is for your own protection (prevent sql injection). */
if (f->f_pTpl->optFormatForSQL == 0) {
- f->f_type = F_UNUSED;
+ iRet = RS_RET_NO_SQL_STRING;
logerror("DB logging disabled. You have to use"
" the SQL or stdSQL option in your template!\n");
break;
@@ -372,9 +366,10 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
* Retries make no sense.
*/
if (iMySQLPropErr) {
- f->f_type = F_UNUSED;
+ iRet = RS_RET_ERR; /* re-vist error code when working on this module */
dprintf("Trouble with MySQL conncetion properties.\n"
"MySQL logging disabled.\n");
+ break;
} else {
initMySQL(f);
}
@@ -385,6 +380,9 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
break;
}
+ if(iRet == RS_RET_OK)
+ iRet = RS_RET_CONFLINE_PROCESSED;
+
if(iRet == RS_RET_CONFLINE_PROCESSED)
*pp = p;
return iRet;
diff --git a/omshell.c b/omshell.c
index 6b67dff4..80bec178 100644
--- a/omshell.c
+++ b/omshell.c
@@ -91,16 +91,19 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
case '^': /* bkalkbrenner 2005-09-20: execute shell command */
dprintf("exec\n");
++p;
- cflineParseFileName(f, p);
- if (f->f_type == F_FILE) {
- f->f_type = F_SHELL;
- }
+ if((iRet = cflineParseFileName(f, p)) == RS_RET_OK)
+ if (f->f_type == F_FILE) {
+ f->f_type = F_SHELL;
+ }
break;
default:
iRet = RS_RET_CONFLINE_UNPROCESSED;
break;
}
+ if(iRet == RS_RET_OK)
+ iRet = RS_RET_CONFLINE_PROCESSED;
+
if(iRet == RS_RET_CONFLINE_PROCESSED)
*pp = p;
return iRet;
diff --git a/omusrmsg.c b/omusrmsg.c
index da545f73..ecfc5862 100644
--- a/omusrmsg.c
+++ b/omusrmsg.c
@@ -233,6 +233,7 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
uchar *p, *q;
int i;
char szTemplateName[128];
+ rsRetVal iRet = RS_RET_CONFLINE_PROCESSED;
assert(pp != NULL);
assert(f != NULL);
@@ -249,19 +250,15 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
if(*(p+1) == ';') {
/* we have a template specifier! */
p += 2; /* eat "*;" */
- cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(uchar));
+ if((iRet = cflineParseTemplateName(&p, szTemplateName,
+ sizeof(szTemplateName) / sizeof(uchar))) != RS_RET_OK)
+ return iRet;
}
else /* assign default format if none given! */
szTemplateName[0] = '\0';
if(szTemplateName[0] == '\0')
strcpy(szTemplateName, " WallFmt");
- cflineSetTemplateAndIOV(f, szTemplateName);
- if(f->f_type != F_UNUSED)
- /* safety measure to make sure we have a valid
- * selector line before we continue down below.
- * rgerhards 2005-07-29
- */
+ if((iRet = cflineSetTemplateAndIOV(f, szTemplateName)) == RS_RET_OK)
dprintf(" template '%s'\n", szTemplateName);
} else {
/* everything else is currently treated as a user name
@@ -289,12 +286,13 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
if(*p == ';') {
/* we have a template specifier! */
++p; /* eat ";" */
- cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(char));
+ if((iRet = cflineParseTemplateName(&p, szTemplateName,
+ sizeof(szTemplateName) / sizeof(char))) != RS_RET_OK)
+ return iRet;
}
if(szTemplateName[0] == '\0')
strcpy(szTemplateName, " StdUsrMsgFmt");
- cflineSetTemplateAndIOV(f, szTemplateName);
+ iRet = cflineSetTemplateAndIOV(f, szTemplateName);
/* Please note that we would need to check if the template
* was found. If not, f->f_type would be F_UNUSED and we
* can NOT carry on processing. These checks can be seen
@@ -307,8 +305,12 @@ static rsRetVal parseSelectorAct(uchar **pp, selector_t *f)
*/
}
- *pp = p;
- return RS_RET_CONFLINE_PROCESSED;
+ if(iRet == RS_RET_OK)
+ iRet = RS_RET_CONFLINE_PROCESSED;
+
+ if(iRet == RS_RET_CONFLINE_PROCESSED)
+ *pp = p;
+ return iRet;
}
/* query an entry point
diff --git a/rsyslog.h b/rsyslog.h
index 149627bc..82515077 100644
--- a/rsyslog.h
+++ b/rsyslog.h
@@ -52,6 +52,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_CONFLINE_UNPROCESSED = -2001,/**< config line was not processed, pass to other module */
RS_RET_DISCARDMSG = -2002, /**< discard message (no error state, processing request!) */
RS_RET_INCOMPATIBLE = -2003, /**< function not compatible with requested feature */
+ RS_RET_NOENTRY = -2004, /**< do not create an entry for (whatever) - not necessary an error */
+ RS_RET_NO_SQL_STRING = -2005, /**< string is not suitable for use as SQL */
RS_RET_OK = 0 /**< operation successful */
};
typedef enum rsRetVal_ rsRetVal; /**< friendly type for global return value */
diff --git a/syslogd.c b/syslogd.c
index 0c3b117c..ea73370a 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -2327,12 +2327,14 @@ static void processMsg(msg_t *pMsg)
assert(pMsg != NULL);
+ /* log the message to the particular outputs */
+ if (!Initialized) {
+ fprintf(stderr, "%s\n", pMsg->pszMSG);
+ return;
#if 0 /* TODO: I temporarily disable the emergency logging system. We must re-think
* how this is done, as we now have modules.
* rgerhards, 2007-07-24
*/
- /* log the message to the particular outputs */
- if (!Initialized) {
/* If we reach this point, the daemon initialization FAILED. That is,
* syslogd is NOT actually running. So what we do here is just
* initialize a pointer to the system console and then output
@@ -2374,8 +2376,8 @@ static void processMsg(msg_t *pMsg)
}
}
return; /* we are done with emergency loging */
- }
#endif
+ }
bContinue = 1;
for (f = Files; f != NULL && bContinue ; f = f->f_next) {
@@ -4350,23 +4352,30 @@ static void init()
/* allocate next entry and add it */
f = (selector_t *)calloc(1, sizeof(selector_t));
/* TODO: check for NULL pointer (this is a general issue in this code...)! */
- if(nextp == NULL) {
- Files = f;
- }
- else {
- nextp->f_next = f;
- }
- nextp = f;
/* be careful: the default below must be set BEFORE calling cfline()! */
f->f_un.f_file.f_sizeLimit = 0; /* default value, use outchannels to configure! */
#if CONT_LINE
- cfline(cbuf, f);
+ if(cfline(cbuf, f) != RS_RET_OK) {
#else
- cfline(cline, f);
+ if(cfline(cline, f) != RS_RET_OK) {
#endif
- if (f->f_type == F_FORW || f->f_type == F_FORW_SUSP || f->f_type == F_FORW_UNKN) {
- Forwarding++;
+ /* creation of the entry failed, we need to discard it */
+ dprintf("selector line NOT successfully processed\n");
+ free(f);
+ } else {
+ /* successfully created an entry */
+ dprintf("selector line successfully processed\n");
+ if(nextp == NULL) {
+ Files = f;
+ }
+ else {
+ nextp->f_next = f;
+ }
+ nextp = f;
+ if (f->f_type == F_FORW || f->f_type == F_FORW_SUSP || f->f_type == F_FORW_UNKN) {
+ Forwarding++;
+ }
}
}
@@ -4438,7 +4447,7 @@ static void init()
if(Debug) {
printf("Active selectors:\n");
for (f = Files; f != NULL ; f = f->f_next) {
- if (f->f_type != F_UNUSED) {
+ if (1) {
if(f->pCSProgNameComp != NULL)
printf("tag: '%s'\n", rsCStrGetSzStr(f->pCSProgNameComp));
if(f->eHostnameCmpMode != HN_NO_COMP)
@@ -4505,6 +4514,10 @@ static void init()
for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++)
printf("%s, ", f->f_un.f_uname[i]);
break;
+
+ case F_UNUSED:
+ printf("UNUSED");
+ break;
}
if(f->f_ReduceRepeated)
printf(" [RepeatedMsgReduction]");
@@ -4561,8 +4574,9 @@ static void init()
* to a filed entry and allocates memory for its iovec.
* rgerhards 2004-11-19
*/
-void cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName)
+rsRetVal cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName)
{
+ rsRetVal iRet = RS_RET_OK;
char errMsg[512];
assert(f != NULL);
@@ -4580,21 +4594,22 @@ void cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName)
pTemplateName);
errno = 0;
logerror(errMsg);
- f->f_type = F_UNUSED;
+ iRet = RS_RET_NOT_FOUND;
} else {
if((f->f_iov = calloc(tplGetEntryCount(f->f_pTpl),
sizeof(struct iovec))) == NULL) {
errno = 0;
logerror("Could not allocate iovec memory - 1 selector line disabled\n");
- f->f_type = F_UNUSED;
+ iRet = RS_RET_ERR;
}
if((f->f_bMustBeFreed = calloc(tplGetEntryCount(f->f_pTpl),
sizeof(unsigned short))) == NULL) {
errno = 0;
logerror("Could not allocate bMustBeFreed memory - 1 selector line disabled\n");
- f->f_type = F_UNUSED;
+ iRet = RS_RET_ERR;
}
}
+ return iRet;
}
/* Helper to cfline() and its helpers. Parses a template name
@@ -4606,10 +4621,11 @@ void cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName)
* to be \0 in this case.
* rgerhards 2004-11-19
*/
-void cflineParseTemplateName(uchar** pp,
+rsRetVal cflineParseTemplateName(uchar** pp,
register char* pTemplateName, int iLenTemplate)
{
register uchar *p;
+ rsRetVal iRet = RS_RET_OK;
int i;
assert(pp != NULL);
@@ -4629,6 +4645,8 @@ void cflineParseTemplateName(uchar** pp,
*pTemplateName = '\0';
*pp = p;
+
+ return iRet;
}
/* Helper to cfline(). Parses a file name up until the first
@@ -4637,12 +4655,14 @@ void cflineParseTemplateName(uchar** pp,
* filed struct.
* rgerhards 2004-11-18
*/
-void cflineParseFileName(selector_t *f, uchar* p)
+rsRetVal cflineParseFileName(selector_t *f, uchar* p)
{
register char *pName;
int i;
+ rsRetVal iRet = RS_RET_OK;
char szTemplateName[128]; /* should be more than sufficient */
+ /* TODO: below is problematic from modularization standpoint */
if(*p == '|') {
f->f_type = F_PIPE;
++p;
@@ -4666,15 +4686,17 @@ void cflineParseFileName(selector_t *f, uchar* p)
if(*p == ';')
++p; /* eat it */
- cflineParseTemplateName(&p, szTemplateName,
- sizeof(szTemplateName) / sizeof(char));
+ if((iRet = cflineParseTemplateName(&p, szTemplateName,
+ sizeof(szTemplateName) / sizeof(char))) != RS_RET_OK)
+ return iRet;
if(szTemplateName[0] == '\0') /* no template? */
strcpy(szTemplateName, " TradFmt"); /* use default! */
- cflineSetTemplateAndIOV(f, szTemplateName);
-
- dprintf("filename: '%s', template: '%s'\n", f->f_un.f_file.f_fname, szTemplateName);
+ if((iRet = cflineSetTemplateAndIOV(f, szTemplateName)) == RS_RET_OK)
+ dprintf("filename: '%s', template: '%s'\n", f->f_un.f_file.f_fname, szTemplateName);
+
+ return iRet;
}
@@ -5068,12 +5090,14 @@ static rsRetVal cfline(char *line, register selector_t *f)
iRet = cflineProcessPropFilter(&p, f);
break;
case '!':
- iRet = cflineProcessTagSelector(&p);
- return iRet; /* in this case, we are done */
+ if((iRet = cflineProcessTagSelector(&p)) == RS_RET_OK)
+ iRet = RS_RET_NOENTRY;
+ break;
case '+':
case '-':
- iRet = cflineProcessHostSelector(&p);
- return iRet; /* in this case, we are done */
+ if((iRet = cflineProcessHostSelector(&p)) == RS_RET_OK)
+ iRet = RS_RET_NOENTRY;
+ break;
default:
iRet = cflineProcessTradPRIFilter(&p, f);
break;
@@ -5081,8 +5105,7 @@ static rsRetVal cfline(char *line, register selector_t *f)
/* check if that went well... */
if(iRet != RS_RET_OK) {
- f->f_type = F_UNUSED;
- return iRet;
+ return RS_RET_NOENTRY;
}
/* we now check if there are some global (BSD-style) filter conditions
@@ -5104,6 +5127,7 @@ static rsRetVal cfline(char *line, register selector_t *f)
pMod = omodGetNxt(NULL);
while(pMod != NULL) {
iRet = pMod->mod.om.parseSelectorAct(&p , f);
+ dprintf("modprobe %s: %d\n", modGetName(pMod), iRet);
if(iRet == RS_RET_CONFLINE_PROCESSED) {
dprintf("Module %s processed this config line.\n",
modGetName(pMod));
@@ -5118,16 +5142,20 @@ static rsRetVal cfline(char *line, register selector_t *f)
break;
}
else if(iRet != RS_RET_CONFLINE_UNPROCESSED) {
- /* we ignore any errors that might have occured - we can
- * not do anything at all, and it would block other modules
- * from initializing. -- rgerhards, 2007-07-24
+ /* In this case, the module would have handled the config
+ * line, but some error occured while doing so. This error should
+ * already by reported by the module. We do not try any other
+ * modules on this line, because we found the right one.
+ * rgerhards, 2007-07-24
*/
- dprintf("error %d parsing config line - continuing\n", (int) iRet);
+ dprintf("error %d parsing config line\n", (int) iRet);
+ break;
}
pMod = omodGetNxt(pMod);
}
- return RS_RET_OK;
+dprintf("cfline returns %d\n", iRet);
+ return (iRet == RS_RET_CONFLINE_PROCESSED) ? RS_RET_OK : RS_RET_NOENTRY;
}
@@ -5979,6 +6007,7 @@ int main(int argc, char **argv)
consfile.f_type = F_CONSOLE;
strcpy(consfile.f_un.f_file.f_fname, ctty);
+ /* TODO: check this */
cflineSetTemplateAndIOV(&consfile, " TradFmt");
gethostname(LocalHostName, sizeof(LocalHostName));
if ( (p = strchr(LocalHostName, '.')) ) {
diff --git a/syslogd.h b/syslogd.h
index 77e9acad..f2cfd6d2 100644
--- a/syslogd.h
+++ b/syslogd.h
@@ -84,9 +84,9 @@ int formatTimestamp3164(struct syslogTime *ts, char* pBuf, size_t iLenBuf);
void iovCreate(selector_t *f);
char *iovAsString(selector_t *f);
void untty(void);
-void cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName);
-void cflineParseTemplateName(uchar** pp, register char* pTemplateName, int iLenTemplate);
-void cflineParseFileName(selector_t *f, uchar* p);
+rsRetVal cflineSetTemplateAndIOV(selector_t *f, char *pTemplateName);
+rsRetVal cflineParseTemplateName(uchar** pp, register char* pTemplateName, int iLenTemplate);
+rsRetVal cflineParseFileName(selector_t *f, uchar* p);
int getSubString(uchar **ppSrc, char *pDst, size_t DstSize, char cSep);
extern int glblHadMemShortage; /* indicates if we had memory shortage some time during the run */