rsyslog/plugins/impstats/impstats.c
Rainer Gerhards 48c248d626 impstats: fix invalid counter definitions for getrusage() reporting
some of the counters were defined as  int (32 bit) vs. intctr_t (64 bit).
On some platforms "long" seems to be 64bit, and getrusage() provides
what we store as int via long. So this caused truncation and/or overflow.
This had undefined effects. Most often, everything worked fine
for values smaller than 2^31 but sometimes we got negative values.

closes https://github.com/rsyslog/rsyslog/issues/1517
2017-12-31 17:12:51 +01:00

630 lines
18 KiB
C

/* impstats.c
* A module to periodically output statistics gathered by rsyslog.
*
* Copyright 2010-2017 Adiscon GmbH.
*
* This file is part of rsyslog.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* -or-
* see COPYING.ASL20 in the source distribution
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "config.h"
#include "rsyslog.h"
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <string.h>
#include <pthread.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#ifdef OS_LINUX
#include <sys/types.h>
#include <dirent.h>
#endif
#include "dirty.h"
#include "cfsysline.h"
#include "module-template.h"
#include "errmsg.h"
#include "msg.h"
#include "srUtils.h"
#include "unicode-helper.h"
#include "glbl.h"
#include "statsobj.h"
#include "prop.h"
#include "ruleset.h"
MODULE_TYPE_INPUT
MODULE_TYPE_NOKEEP
MODULE_CNFNAME("impstats")
/* defines */
#define DEFAULT_STATS_PERIOD (5 * 60)
#define DEFAULT_FACILITY 5 /* syslog */
#define DEFAULT_SEVERITY 6 /* info */
/* Module static data */
DEF_IMOD_STATIC_DATA
DEFobjCurrIf(glbl)
DEFobjCurrIf(prop)
DEFobjCurrIf(statsobj)
DEFobjCurrIf(errmsg)
DEFobjCurrIf(ruleset)
typedef struct configSettings_s {
int iStatsInterval;
int iFacility;
int iSeverity;
int bJSON;
int bCEE;
} configSettings_t;
struct modConfData_s {
rsconf_t *pConf; /* our overall config object */
int iStatsInterval;
int iFacility;
int iSeverity;
int logfd; /* fd if logging to file, or -1 if closed */
ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */
statsFmtType_t statsFmt;
sbool bLogToSyslog;
sbool bResetCtrs;
sbool bBracketing;
char *logfile;
sbool configSetViaV2Method;
uchar *pszBindRuleset; /* name of ruleset to bind to */
};
static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */
static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */
static configSettings_t cs;
static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */
static prop_t *pInputName = NULL;
/* module-global parameters */
static struct cnfparamdescr modpdescr[] = {
{ "interval", eCmdHdlrInt, 0 },
{ "facility", eCmdHdlrInt, 0 },
{ "severity", eCmdHdlrInt, 0 },
{ "bracketing", eCmdHdlrBinary, 0 },
{ "log.syslog", eCmdHdlrBinary, 0 },
{ "resetcounters", eCmdHdlrBinary, 0 },
{ "log.file", eCmdHdlrGetWord, 0 },
{ "format", eCmdHdlrGetWord, 0 },
{ "ruleset", eCmdHdlrString, 0 }
};
static struct cnfparamblk modpblk =
{ CNFPARAMBLK_VERSION,
sizeof(modpdescr)/sizeof(struct cnfparamdescr),
modpdescr
};
/* resource use stats counters */
#ifdef OS_LINUX
static int st_openfiles;
#endif
static intctr_t st_ru_utime;
static intctr_t st_ru_stime;
static intctr_t st_ru_maxrss;
static intctr_t st_ru_minflt;
static intctr_t st_ru_majflt;
static intctr_t st_ru_inblock;
static intctr_t st_ru_oublock;
static intctr_t st_ru_nvcsw;
static intctr_t st_ru_nivcsw;
static statsobj_t *statsobj_resources;
static pthread_mutex_t hup_mutex = PTHREAD_MUTEX_INITIALIZER;
BEGINmodExit
CODESTARTmodExit
prop.Destruct(&pInputName);
/* release objects we used */
objRelease(glbl, CORE_COMPONENT);
objRelease(prop, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
objRelease(statsobj, CORE_COMPONENT);
objRelease(ruleset, CORE_COMPONENT);
ENDmodExit
BEGINisCompatibleWithFeature
CODESTARTisCompatibleWithFeature
if(eFeat == sFEATURENonCancelInputTermination)
iRet = RS_RET_OK;
ENDisCompatibleWithFeature
#ifdef OS_LINUX
/* count number of open files (linux specific) */
static void
countOpenFiles(void)
{
char proc_path[MAXFNAME];
DIR *dp;
struct dirent *files;
st_openfiles = 0;
snprintf(proc_path, sizeof(proc_path), "/proc/%d/fd", glblGetOurPid());
if((dp = opendir(proc_path)) == NULL) {
LogError(errno, RS_RET_ERR, "impstats: error reading %s\n", proc_path);
goto done;
}
while((files=readdir(dp)) != NULL) {
if(!strcmp(files->d_name, ".") || !strcmp(files->d_name, ".."))
continue;
st_openfiles++;
}
closedir(dp);
done:
return;
}
#endif
static void
initConfigSettings(void)
{
cs.iStatsInterval = DEFAULT_STATS_PERIOD;
cs.iFacility = DEFAULT_FACILITY;
cs.iSeverity = DEFAULT_SEVERITY;
cs.bJSON = 0;
cs.bCEE = 0;
}
/* actually submit a message to the rsyslog core
*/
static void
doSubmitMsg(uchar *line)
{
smsg_t *pMsg;
if(msgConstruct(&pMsg) != RS_RET_OK)
goto finalize_it;
MsgSetInputName(pMsg, pInputName);
MsgSetRawMsgWOSize(pMsg, (char*)line);
MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()));
MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp());
MsgSetRcvFromIP(pMsg, glbl.GetLocalHostIP());
MsgSetMSGoffs(pMsg, 0);
MsgSetRuleset(pMsg, runModConf->pBindRuleset);
MsgSetTAG(pMsg, UCHAR_CONSTANT("rsyslogd-pstats:"), sizeof("rsyslogd-pstats:") - 1);
pMsg->iFacility = runModConf->iFacility;
pMsg->iSeverity = runModConf->iSeverity;
pMsg->msgFlags = 0;
/* we do not use rate-limiting, as the stats message always need to be emitted */
submitMsg2(pMsg);
DBGPRINTF("impstats: submit [%d,%d] msg '%s'\n", runModConf->iFacility,
runModConf->iSeverity, line);
finalize_it:
return;
}
/* log stats message to file; limited error handling done */
static void
doLogToFile(const char *ln, const size_t lenLn)
{
struct iovec iov[4];
ssize_t nwritten;
ssize_t nexpect;
time_t t;
char timebuf[32];
pthread_mutex_lock(&hup_mutex);
if(lenLn == 0)
goto done;
if(runModConf->logfd == -1) {
runModConf->logfd = open(runModConf->logfile, O_WRONLY|O_CREAT|O_APPEND|O_CLOEXEC, S_IRUSR|S_IWUSR);
if(runModConf->logfd == -1) {
DBGPRINTF("impstats: error opening stats file %s\n",
runModConf->logfile);
goto done;
} else {
DBGPRINTF("impstats: opened stats file %s\n",
runModConf->logfile);
}
}
time(&t);
iov[0].iov_base = ctime_r(&t, timebuf);
iov[0].iov_len = nexpect = strlen(iov[0].iov_base) - 1; /* -1: strip \n */
iov[1].iov_base = (void*)": ";
iov[1].iov_len = 2;
nexpect += 2;
iov[2].iov_base = (void*)ln;
iov[2].iov_len = lenLn;
nexpect += lenLn;
iov[3].iov_base = (void*)"\n";
iov[3].iov_len = 1;
nexpect++;
nwritten = writev(runModConf->logfd, iov, 4);
if(nwritten != nexpect) {
dbgprintf("error writing stats file %s, nwritten %lld, expected %lld\n",
runModConf->logfile, (long long) nwritten, (long long) nexpect);
}
done:
pthread_mutex_unlock(&hup_mutex);
return;
}
/* submit a line to our log destinations. Line must be fully formatted as
* required (but may be a simple verb like "BEGIN" and "END".
*/
static rsRetVal
submitLine(const char *const ln, const size_t lenLn)
{
DEFiRet;
if(runModConf->bLogToSyslog)
doSubmitMsg((uchar*)ln);
if(runModConf->logfile != NULL)
doLogToFile(ln, lenLn);
RETiRet;
}
/* callback for statsobj
* Note: usrptr exists only to satisfy requirements of statsobj callback interface!
*/
static rsRetVal
doStatsLine(void __attribute__((unused)) *usrptr, const char *const str)
{
DEFiRet;
iRet = submitLine(str, strlen(str));
RETiRet;
}
/* the function to generate the actual statistics messages
* rgerhards, 2010-09-09
*/
static void
generateStatsMsgs(void)
{
struct rusage ru;
int r;
r = getrusage(RUSAGE_SELF, &ru);
if(r != 0) {
dbgprintf("impstats: getrusage() failed with error %d, zeroing out\n", errno);
memset(&ru, 0, sizeof(ru));
}
# ifdef OS_LINUX
countOpenFiles();
# endif
st_ru_utime = ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec;
st_ru_stime = ru.ru_stime.tv_sec * 1000000 + ru.ru_stime.tv_usec;
st_ru_maxrss = ru.ru_maxrss;
st_ru_minflt = ru.ru_minflt;
st_ru_majflt = ru.ru_majflt;
st_ru_inblock = ru.ru_inblock;
st_ru_oublock = ru.ru_oublock;
st_ru_nvcsw = ru.ru_nvcsw;
st_ru_nivcsw = ru.ru_nivcsw;
statsobj.GetAllStatsLines(doStatsLine, NULL, runModConf->statsFmt, runModConf->bResetCtrs);
}
BEGINbeginCnfLoad
CODESTARTbeginCnfLoad
loadModConf = pModConf;
pModConf->pConf = pConf;
/* init our settings */
loadModConf->configSetViaV2Method = 0;
loadModConf->iStatsInterval = DEFAULT_STATS_PERIOD;
loadModConf->iFacility = DEFAULT_FACILITY;
loadModConf->iSeverity = DEFAULT_SEVERITY;
loadModConf->statsFmt = statsFmt_Legacy;
loadModConf->logfd = -1;
loadModConf->logfile = NULL;
loadModConf->pszBindRuleset = NULL;
loadModConf->bLogToSyslog = 1;
loadModConf->bBracketing = 0;
loadModConf->bResetCtrs = 0;
bLegacyCnfModGlobalsPermitted = 1;
/* init legacy config vars */
initConfigSettings();
ENDbeginCnfLoad
BEGINsetModCnf
struct cnfparamvals *pvals = NULL;
char *mode;
int i;
CODESTARTsetModCnf
pvals = nvlstGetParams(lst, &modpblk, NULL);
if(pvals == NULL) {
errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module "
"config parameters [module(...)]");
ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS);
}
if(Debug) {
dbgprintf("module (global) param blk for impstats:\n");
cnfparamsPrint(&modpblk, pvals);
}
for(i = 0 ; i < modpblk.nParams ; ++i) {
if(!pvals[i].bUsed)
continue;
if(!strcmp(modpblk.descr[i].name, "interval")) {
loadModConf->iStatsInterval = (int) pvals[i].val.d.n;
} else if(!strcmp(modpblk.descr[i].name, "facility")) {
loadModConf->iFacility = (int) pvals[i].val.d.n;
} else if(!strcmp(modpblk.descr[i].name, "severity")) {
loadModConf->iSeverity = (int) pvals[i].val.d.n;
} else if(!strcmp(modpblk.descr[i].name, "bracketing")) {
loadModConf->bBracketing = (sbool) pvals[i].val.d.n;
} else if(!strcmp(modpblk.descr[i].name, "log.syslog")) {
loadModConf->bLogToSyslog = (sbool) pvals[i].val.d.n;
} else if(!strcmp(modpblk.descr[i].name, "resetcounters")) {
loadModConf->bResetCtrs = (sbool) pvals[i].val.d.n;
} else if(!strcmp(modpblk.descr[i].name, "log.file")) {
loadModConf->logfile = es_str2cstr(pvals[i].val.d.estr, NULL);
} else if(!strcmp(modpblk.descr[i].name, "format")) {
mode = es_str2cstr(pvals[i].val.d.estr, NULL);
if(!strcasecmp(mode, "json")) {
loadModConf->statsFmt = statsFmt_JSON;
} else if(!strcasecmp(mode, "json-elasticsearch")) {
loadModConf->statsFmt = statsFmt_JSON_ES;
} else if(!strcasecmp(mode, "cee")) {
loadModConf->statsFmt = statsFmt_CEE;
} else if(!strcasecmp(mode, "legacy")) {
loadModConf->statsFmt = statsFmt_Legacy;
} else {
errmsg.LogError(0, RS_RET_ERR, "impstats: invalid format %s",
mode);
}
free(mode);
} else if(!strcmp(modpblk.descr[i].name, "ruleset")) {
loadModConf->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL);
} else {
dbgprintf("impstats: program error, non-handled "
"param '%s' in beginCnfLoad\n", modpblk.descr[i].name);
}
}
loadModConf->configSetViaV2Method = 1;
bLegacyCnfModGlobalsPermitted = 0;
finalize_it:
if(pvals != NULL)
cnfparamvalsDestruct(pvals, &modpblk);
ENDsetModCnf
BEGINendCnfLoad
CODESTARTendCnfLoad
if(!loadModConf->configSetViaV2Method) {
/* persist module-specific settings from legacy config system */
loadModConf->iStatsInterval = cs.iStatsInterval;
loadModConf->iFacility = cs.iFacility;
loadModConf->iSeverity = cs.iSeverity;
if (cs.bCEE == 1) {
loadModConf->statsFmt = statsFmt_CEE;
} else if (cs.bJSON == 1) {
loadModConf->statsFmt = statsFmt_JSON;
} else {
loadModConf->statsFmt = statsFmt_Legacy;
}
}
ENDendCnfLoad
/* we need our special version of checkRuleset(), as we do not have any instances */
static rsRetVal
checkRuleset(modConfData_t *modConf)
{
ruleset_t *pRuleset;
rsRetVal localRet;
DEFiRet;
modConf->pBindRuleset = NULL; /* assume default ruleset */
if(modConf->pszBindRuleset == NULL)
FINALIZE;
localRet = ruleset.GetRuleset(modConf->pConf, &pRuleset, modConf->pszBindRuleset);
if(localRet == RS_RET_NOT_FOUND) {
errmsg.LogError(0, NO_ERRCODE, "impstats: ruleset '%s' not found - "
"using default ruleset instead", modConf->pszBindRuleset);
}
CHKiRet(localRet);
modConf->pBindRuleset = pRuleset;
finalize_it:
RETiRet;
}
/* to use HUP, we need to have an instanceData type, as this was
* originally designed for actions. However, we do not, and cannot,
* use the content. The core will always provide a NULL pointer.
*/
typedef struct _instanceData {
int dummy;
} instanceData;
BEGINdoHUP
CODESTARTdoHUP
DBGPRINTF("impstats: received HUP\n")
pthread_mutex_lock(&hup_mutex);
if(runModConf->logfd != -1) {
DBGPRINTF("impstats: closing log file due to HUP\n");
close(runModConf->logfd);
runModConf->logfd = -1;
}
pthread_mutex_unlock(&hup_mutex);
ENDdoHUP
BEGINcheckCnf
CODESTARTcheckCnf
if(pModConf->iStatsInterval == 0) {
errmsg.LogError(0, NO_ERRCODE, "impstats: stats interval zero not permitted, using "
"default of %d seconds", DEFAULT_STATS_PERIOD);
pModConf->iStatsInterval = DEFAULT_STATS_PERIOD;
}
iRet = checkRuleset(pModConf);
ENDcheckCnf
BEGINactivateCnf
rsRetVal localRet;
CODESTARTactivateCnf
runModConf = pModConf;
DBGPRINTF("impstats: stats interval %d seconds, reset %d, logToSyslog %d, logFile %s\n",
runModConf->iStatsInterval, runModConf->bResetCtrs, runModConf->bLogToSyslog,
runModConf->logfile == NULL ? "deactivated" : (char*)runModConf->logfile);
localRet = statsobj.EnableStats();
if(localRet != RS_RET_OK) {
errmsg.LogError(0, localRet, "impstats: error enabling statistics gathering");
ABORT_FINALIZE(RS_RET_NO_RUN);
}
/* initialize our own counters */
CHKiRet(statsobj.Construct(&statsobj_resources));
CHKiRet(statsobj.SetName(statsobj_resources, (uchar*)"resource-usage"));
CHKiRet(statsobj.SetOrigin(statsobj_resources, (uchar*)"impstats"));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("utime"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_utime));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("stime"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_stime));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("maxrss"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_maxrss));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("minflt"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_minflt));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("majflt"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_majflt));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("inblock"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_inblock));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("oublock"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_oublock));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("nvcsw"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_nvcsw));
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("nivcsw"),
ctrType_IntCtr, CTR_FLAG_NONE, &st_ru_nivcsw));
# ifdef OS_LINUX
CHKiRet(statsobj.AddCounter(statsobj_resources, UCHAR_CONSTANT("openfiles"),
ctrType_Int, CTR_FLAG_NONE, &st_openfiles));
# endif
CHKiRet(statsobj.ConstructFinalize(statsobj_resources));
finalize_it:
if(iRet != RS_RET_OK) {
errmsg.LogError(0, iRet, "impstats: error activating module");
iRet = RS_RET_NO_RUN;
}
ENDactivateCnf
BEGINfreeCnf
CODESTARTfreeCnf
if(runModConf->logfd != -1)
close(runModConf->logfd);
free(runModConf->logfile);
free(runModConf->pszBindRuleset);
ENDfreeCnf
BEGINrunInput
CODESTARTrunInput
/* this is an endless loop - it is terminated when the thread is
* signalled to do so. This, however, is handled by the framework,
* right into the sleep below. Note that we DELIBERATLY output
* final set of stats counters on termination request. Depending
* on configuration, they may not make it to the final destination...
*/
while(glbl.GetGlobalInputTermState() == 0) {
srSleep(runModConf->iStatsInterval, 0); /* seconds, micro seconds */
DBGPRINTF("impstats: woke up, generating messages\n");
if(runModConf->bBracketing)
submitLine("BEGIN", sizeof("BEGIN")-1);
generateStatsMsgs();
if(runModConf->bBracketing)
submitLine("END", sizeof("END")-1);
}
ENDrunInput
BEGINwillRun
CODESTARTwillRun
ENDwillRun
BEGINafterRun
CODESTARTafterRun
ENDafterRun
BEGINqueryEtryPt
CODESTARTqueryEtryPt
CODEqueryEtryPt_STD_IMOD_QUERIES
CODEqueryEtryPt_STD_CONF2_QUERIES
CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES
CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES
CODEqueryEtryPt_doHUP
ENDqueryEtryPt
static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
{
initConfigSettings();
return RS_RET_OK;
}
BEGINmodInit()
CODESTARTmodInit
*ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
CODEmodInit_QueryRegCFSLineHdlr
DBGPRINTF("impstats version %s loading\n", VERSION);
initConfigSettings();
CHKiRet(objUse(glbl, CORE_COMPONENT));
CHKiRet(objUse(prop, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(statsobj, CORE_COMPONENT));
CHKiRet(objUse(ruleset, CORE_COMPONENT));
/* the pstatsinverval is an alias to support a previous screwed-up syntax... */
CHKiRet(regCfSysLineHdlr2((uchar *)"pstatsinterval", 0, eCmdHdlrInt, NULL, &cs.iStatsInterval,
STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
CHKiRet(regCfSysLineHdlr2((uchar *)"pstatinterval", 0, eCmdHdlrInt, NULL, &cs.iStatsInterval,
STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
CHKiRet(regCfSysLineHdlr2((uchar *)"pstatfacility", 0, eCmdHdlrInt, NULL, &cs.iFacility,
STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
CHKiRet(regCfSysLineHdlr2((uchar *)"pstatseverity", 0, eCmdHdlrInt, NULL, &cs.iSeverity,
STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
CHKiRet(regCfSysLineHdlr2((uchar *)"pstatjson", 0, eCmdHdlrBinary, NULL, &cs.bJSON,
STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
CHKiRet(regCfSysLineHdlr2((uchar *)"pstatcee", 0, eCmdHdlrBinary, NULL, &cs.bCEE,
STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted));
CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables,
NULL, STD_LOADABLE_MODULE_ID));
CHKiRet(prop.Construct(&pInputName));
CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("impstats"), sizeof("impstats") - 1));
CHKiRet(prop.ConstructFinalize(pInputName));
ENDmodInit
/* vi:set ai:
*/