blob: 8683154a51e12e18aae9b7762b76ee8cf5dce503 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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
//
// 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.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
*****************************************************************************
*
* File: ComRtUtils.cpp
* Description: Some common OS functions that are called by the
* executor (run-time) and may also b called by other components
*
* Created: 7/4/97
* Language: C++
*
*
*****************************************************************************
*/
#include "Platform.h"
#include "PortProcessCalls.h"
#include "ExCextdecs.h"
#include "str.h"
#include "ComRtUtils.h"
#include "charinfo.h"
#include "ComCextdecs.h"
#ifdef _DEBUG
#include <execinfo.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <fstream>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <cxxabi.h>
#endif
#include "nsk/nskcommonhi.h"
#define psecure_h_including_section
#define psecure_h_security_psb_get_
#include "security/psecure.h"
#define dsecure_h_including_section
#define dsecure_h_psb_selectors
#include "security/dsecure.h"
#include "fs/feerrors.h"
#include "ComDistribution.h"
#include "logmxevent.h"
#undef SQL_TEXT
#include "seabed/ms.h"
#include "seabed/fs.h"
#include "HdfsClient_JNI.h"
struct ModName {
public:
const char * name;
};
static const ModName internalSystemSchemaModNameList[] = {
{"CMNAMEMAPSQLM_N29_000"}
,{"CMSMDIOREADM_N29_000"}
,{"CMSMDIOWRITEM_N29_000"}
,{"MVQR_N29_000"}
,{"READDEF_N29_000"}
,{"SQLHIST_N29_000"}
,{"SQLUTILS_N29_000"}
,{"HP_ROUTINES_N29_000"}
,{"ANSINAMES_N29_000"}
,{"SECURITYDATA_N29_000"}
,{"USERLIST_N29_000"}
,{"SSQLSRVRDATA_N29_000"}
,{"QVP_N29_000"}
};
static const ModName internalMxcsSchemaModNameList[] = {
{"CATANSIMXGTI"},
{"CATANSIMXJAVA"},
{"CATANSIMX"}
};
// returns TRUE, if modName is an internal module name
NABoolean ComRtIsInternalModName(const char * modName)
{
Int32 i = 0;
for (i = 0; i < sizeof(internalSystemSchemaModNameList)/sizeof(ModName); i++)
{
if (strcmp(internalSystemSchemaModNameList[i].name, modName) == 0)
return TRUE;
}
for (i = 0; i < sizeof(internalMxcsSchemaModNameList)/sizeof(ModName); i++)
{
if (strcmp(internalMxcsSchemaModNameList[i].name, modName) == 0)
return TRUE;
}
return FALSE;
}
// returns 'next' internal 3-part system mod name.
// 'index' keeps track of the current mod name returned. It should
// be initialized to 0 on the first call to this method.
const char * ComRtGetNextInternalModName(Lng32 &index, char * modNameBuf)
{
if (index == (sizeof(internalSystemSchemaModNameList)
) / sizeof(ModName)
)
return NULL;
if (index < sizeof(internalSystemSchemaModNameList) / sizeof(ModName))
{
strcpy(modNameBuf, systemModulePrefix);
strcat(modNameBuf, internalSystemSchemaModNameList[index].name);
}
index++;
return modNameBuf;
}
// implementation of open, seek, read, close is platform-dependent
// (no use of C runtime on NSK, not even in the debug version)
// non NSK implementations uses IOSTREAM library
ModuleOSFile::ModuleOSFile() {}
ModuleOSFile::~ModuleOSFile() {}
Int32 ModuleOSFile::open(const char *fname)
{
fs_.open(fname, ios::in | ios::binary);
if (fs_.fail())
return 1;
else
return 0;
}
Int32 ModuleOSFile::close()
{
fs_.close();
if (fs_.fail())
return 1;
else
return 0;
}
Int32 ModuleOSFile::readpos(char *buf, Lng32 pos, Lng32 len, short &countRead)
{
// no explicit error handling for these operations
fs_.seekg(pos, ios::beg);
fs_.read(buf, len);
return 0;
}
// -----------------------------------------------------------------------
// Utility proc to move result into a buffer of limited size. Make
// sure the result buffer is always NUL-terminated.
// -----------------------------------------------------------------------
static Lng32 ComRtMoveResult(char *tgt,
const char *src,
Lng32 tgtBufferLength,
Lng32 srcLength)
{
if (tgtBufferLength > srcLength)
{
// the easy case, move result and add NUL terminator
// (don't rely on the source being NUL-terminated)
str_cpy_all(tgt,src,srcLength);
tgt[srcLength] = '\0';
return 0;
}
else
{
str_cpy_all(tgt,src,tgtBufferLength-1);
tgt[tgtBufferLength-1] = '\0';
return -1;
}
}
// -----------------------------------------------------------------------
// Get the directory name where NonStop SQL software resides
// (from registry on NT, $SYSTEM.SYSTEM on NSK)
// -----------------------------------------------------------------------
Lng32 ComRtGetInstallDir(
char *buffer,
Lng32 inputBufferLength,
Lng32 *resultLength) // OUT optional
{
if (resultLength)
*resultLength = 0;
Lng32 result = 0;
Lng32 lResultLen;
// For Linux, we need to decide what to do for the install directory.
// This is work that is TBD. For now, this is set to null, so that
// we can re-visit this once a decision has been made. This API
// is used by catman to determine where to put saved DDL for drop
// table commands.
lResultLen=0;
buffer[lResultLen] = '\0';
if (result == 0 && resultLength)
*resultLength = lResultLen;
return result;
}
static NABoolean canUseModuleDirEnvVar() {
// get session user id
return TRUE; // anything goes on NT
}
#define SYSTEMMODULESDIR "/usr/tandem/sqlmx/SYSTEMMODULES/"
#define USERMODULESDIR "/usr/tandem/sqlmx/USERMODULES/"
Lng32 ComRtGetModuleFileName(
const char *moduleName,
const char *moduleDir, // use this as the module dir, if not NULL.
char *buffer,
Lng32 inputBufferLength,
char * sysModuleDir,
char * userModuleDir,
Lng32 *resultLength,
short &isASystemModule) // OUT optional
{
if (resultLength)
*resultLength = 0;
// NOTE: this code is temporary until modules become SQL objects
// which may not be in this millennium
const char * envVal;
#define bufSize 512
char * mySQROOT;
char sysModuleDirNameBuf[bufSize];
char userModuleDirNameBuf[bufSize];
//Initialize the buffer
memset(sysModuleDirNameBuf, 0, bufSize);
memset(userModuleDirNameBuf, 0, bufSize);
mySQROOT = getenv("TRAF_HOME");
if (mySQROOT != NULL && strlen(mySQROOT) <= bufSize-100) {
strcpy(sysModuleDirNameBuf, mySQROOT);
strcpy(userModuleDirNameBuf, mySQROOT);
} else {
sysModuleDirNameBuf[0] = '\0';
userModuleDirNameBuf[0] = '\0';
assert(0);
}
//System Module location
strcat(sysModuleDirNameBuf,"/sql/sqlmx/SYSTEMMODULES/");
sysModuleDir = sysModuleDirNameBuf;
// User Module location
strcat(userModuleDirNameBuf,"/sql/sqlmx/USERMODULES/");
userModuleDir = userModuleDirNameBuf;
Int32 isSystemModule = 0;
// const char *systemModulePrefix = "NONSTOP_SQLMX_NSK.SYSTEM_SCHEMA.";
// const char *systemModulePrefixODBC = "NONSTOP_SQLMX_NSK.MXCS_SCHEMA.";
// int systemModulePrefixLen = str_len(systemModulePrefix);
// int systemModulePrefixLenODBC = str_len(systemModulePrefixODBC);
Int32 modNameLen = str_len(moduleName);
Lng32 lResultLen;
Lng32 result = 0;
return result;
}
// -----------------------------------------------------------------------
// Get the cluster (EXPAND node) name (returns "NSK" on NT)
// -----------------------------------------------------------------------
Lng32 ComRtGetOSClusterName(
char *buffer,
Lng32 inputBufferLength,
Lng32 *resultLength, // OUT optional
short * nodeNumber)
{
if (resultLength)
*resultLength = 0;
Lng32 result = 1; // positive "ldev"
Lng32 lResultLen = 0;
// for now, the cluster name on NT is always NSK
lResultLen = 3;
ComRtMoveResult(buffer,"NSK",inputBufferLength,lResultLen);
if (result > 0 && resultLength)
*resultLength = lResultLen;
return result;
}
// -----------------------------------------------------------------------
// Get the MP system catalog name.
// the guardian name of the system catalog is returned in sysCatBuffer and
// its size in sysCatLength.
// Error code or 0 is returned for error case and success case respectively.
// -----------------------------------------------------------------------
Lng32 ComRtGetMPSysCatName(
char *sysCatBuffer, // in/out
Lng32 inputBufferLength, // in
char *inputSysName, // in, must set to NULL if no name is passed.
Lng32 *sysCatLength, // out
short *detailError, // out
CollHeap *heap) // in
{
// the following enum is replicated from ComMPSysCat.h for detail error
enum MPSysCatErr { NSK_SYSTEM_NAME_ERROR
, NSK_CANNOT_LOCATE_MP_SYSTEM_CATALOG
, NSK_DEVICE_GETINFOBYLDEV_ERROR
, NSK_FILE_GETINFOBYNAME_ERROR
};
const Int32 DISPLAYBUFSIZE = 8000;
const Int32 FILENAMELEN = 36;
char mpSysCat[FILENAMELEN];
Lng32 nameSize = 0;
Lng32 error = 0;
*detailError = 0;
char *sysCatLoc = NULL;
#ifdef _DEBUG
sysCatLoc = getenv("MP_SYSTEM_CATALOG"); // for Dev+QA convenience
#endif
if (sysCatLoc)
{
if (inputBufferLength < str_len(sysCatLoc))
return -1;
Int32 locLen = str_len (sysCatLoc);
// add local system name if not specified.
//
if ((sysCatLoc[0] != '\\') && (sysCatLoc[0] == '$'))
{
mpSysCat[0] = '\\';
error = ComRtGetOSClusterName (&mpSysCat[1], sizeof(mpSysCat), &nameSize);
if (error || nameSize == 0)
{
*detailError = NSK_SYSTEM_NAME_ERROR;
return -1;
}
nameSize++;
mpSysCat[nameSize] = '.';
str_cpy_all(&mpSysCat[nameSize+1], sysCatLoc, locLen);
locLen = locLen + nameSize + 1;
str_cpy_all (sysCatBuffer, mpSysCat,locLen );
}
else
{
if (sysCatLoc[0] != '\\')
return -1;
str_cpy_all (sysCatBuffer, sysCatLoc, locLen);
}
sysCatBuffer[locLen] = '\0';
*sysCatLength = locLen;
}
else {
sysCatLoc = sysCatBuffer;
*sysCatLoc = '\0';
*sysCatLength = 0;
// Allows some debugging/testing of this code while on NT.
struct la_display_table_struct { char cat_volname[10], cat_subvolname[10]; };
la_display_table_struct la = { "??MPVOL ", "MPSYSCAT" };
la_display_table_struct *tab = &la;
char sysName[8] = "\\MPSYS ";
size_t i, z;
for (i = 0; i < 8; i++) //padded with blanks
{
if (sysName[i] == ' ') break;
}
str_cpy_all(sysCatLoc, sysName, i);
if (i)
sysCatLoc[i++] = '.';
z = i;
for (i = 2; i < 8; i++) // the first 2 chars are the sysnum, and the volume
// name is blank-padded
{
if (tab->cat_volname[i] == ' ') break;
}
//ComDEBUG(i > 2);
sysCatLoc[z++] = '$';
str_cpy_all(sysCatLoc + z, tab->cat_volname + 2, i - 2);
z += i - 2;
sysCatLoc[z++] = '.';
for (i = 0; i < 8; i++) //padded with blanks
{
if (tab->cat_subvolname[i] == ' ') break;
}
str_cpy_all(sysCatLoc + z, tab->cat_subvolname, i);
sysCatLoc[z+i] = '\0';
*sysCatLength = (Lng32)z+i;
}
return 0;
}
// -----------------------------------------------------------------------
// Upshift a simple char string
// -----------------------------------------------------------------------
//#define TOUPPER(c) (((c >= 'a') && (c <= 'z')) ? (c - 32) : c);
void ComRt_Upshift (char * buf)
{
// NOTE: buf is assumed to be non-NULL so it will not be checked again
// if (buf && (*buf != '\"'))
if (*buf != '\"')
{
// Assume that the name is in the form of an SQL92 <identifier>,
// meaning that it could be a (case-insensitive) unquoted name
// or a (case-sensitive) delimited identifier in double quotes.
// So, upshift the name if it's not in double quotes.
// NOTE: this code has a counterpart in the
// parser. Make sure both parts are kept in sync.
register char * pBuf = buf;
// NOTE: the string in buf is assumed to null terminated, so no need
// to worry about the loop not terminating appropriately
while (*pBuf)
{
*pBuf = TOUPPER(*pBuf);
++pBuf;
}
}
}
const char * ComRtGetEnvValueFromEnvvars(const char ** envvars,
const char * envvar,
Lng32 * envvarPos)
{
if (envvarPos)
*envvarPos = -1;
if (! envvars)
return NULL;
Lng32 envvarLen = str_len(envvar);
for (Int32 i = 0; envvars[i]; i++)
{
// Each envvar[i] is of the form: envvar=value
// search for '='
Int32 j = 0;
for (j = 0; ((envvars[i][j] != 0) && (envvars[i][j] != '=')); j++);
if (envvars[i][j] == '=')
{
if ((j == envvarLen) && (str_cmp(envvar, envvars[i], j) == 0))
{
if (envvarPos)
*envvarPos = i;
return &envvars[i][j+1];
}
}
}
return NULL;
}
#if defined (_DEBUG)
// -----------------------------------------------------------------------
// Convenient handling of envvars: Return a value if one exists
// NB: DEBUG mode only!
// -----------------------------------------------------------------------
NABoolean ComRtGetEnvValue(const char * envvar, const char ** envvarValue)
{
const char * ptr = getenv(envvar);
if (!ptr)
// envvar not there
return FALSE;
if (!strlen(ptr))
// envvar there but no value
return FALSE;
if (envvarValue)
// only return a value if caller asked for one
*envvarValue = ptr;
return TRUE;
}
NABoolean ComRtGetEnvValue(const char * envvar, Lng32 * envvarValue)
{
const char * ptr;
if (!ComRtGetEnvValue(envvar, &ptr))
// envvar not there or no value
return FALSE;
Int32 max = strlen(ptr);
Lng32 tempValue = 0;
for (Int32 i = 0;i < max;i++)
{
if (ptr[i] < '0' || ptr[i] > '9')
// value is not numeric
return FALSE;
tempValue = (tempValue * 10) + (ptr[i] - '0');
}
*envvarValue = tempValue;
return TRUE;
}
NABoolean ComRtGetValueFromFile (const char * envvar, char * valueBuffer,
const UInt32 valueBufferSizeInBytes)
{
// "envvar" supposedly specifies the name of a file, from which we
// read values.
// Return TRUE if value was read from the file, FALSE otherwise
// Only one file at a time can be handled - each time
static char * theFileName = NULL;
static char * theEnvVar;
static ifstream * theFile;
const char * tempFileName;
if (!ComRtGetEnvValue (envvar, &tempFileName))
{
// The requested envvar is not set.
// Close the corresponding file if we have it open
if (theFileName != NULL)
{
if (!strcmp (theEnvVar, envvar))
{
// The same envvar => we have the file open
delete theFile;
delete theFileName;
delete theEnvVar;
theFileName = NULL;
}
}
return FALSE;
}
if (theFileName != NULL)
{
// We already have a file open, see if it is the same
// env var and file name
if (strcmp (theFileName, tempFileName) || strcmp (theEnvVar, envvar))
{
// a different env var or file, close the previous one
delete theFile;
delete theFileName;
delete theEnvVar;
theFileName = NULL;
}
}
if (theFileName == NULL)
{
// Set the current env var name and file name and open the file
theFileName = new char [strlen(tempFileName) + 1];
strcpy (theFileName, tempFileName);
theEnvVar = new char [strlen(envvar) + 1];
strcpy (theEnvVar, envvar);
theFile = new ifstream (theFileName, ios::in);
}
if (theFile->good())
{
// Check to make sure the buffer is big enough:
// The buffer needs at least to be able to hold a NULL terminator
if (valueBufferSizeInBytes < 1)
return FALSE;
UInt32 valStrLimitInBytes = valueBufferSizeInBytes - 1;
// Read from the file if last read was OK
char tmpBuf[81];
theFile->getline(tmpBuf, 80, '\n');
if (theFile->good())
{
if (valStrLimitInBytes <= strlen(tmpBuf))
strcpy(valueBuffer, tmpBuf);
else
{
// The input string is too long, truncate it to fit the valueBuffer.
memcpy(valueBuffer, tmpBuf, valStrLimitInBytes);
valueBuffer[valStrLimitInBytes] = '\0';
}
return TRUE;
}
}
if (theFile->eof())
return FALSE;
if (theFile->bad() || theFile->fail())
{
// File is unusable, get rid of it and clear the
// current file
delete theFile;
delete theFileName;
theFileName = NULL;
}
return FALSE;
}
#endif // #if defined(_DEBUG) ...
// -----------------------------------------------------------------------
//
// ComRtGetProgramInfo()
//
// Outputs:
// 1) the pathname of the directory where the application program
// is being run from.
// For OSS processes, this will be the fully qualified oss directory
// pathname.
// For Guardian processes, pathname is not set
// 2) the process type (oss or guardian).
// 3) Other output values are: cpu, pin, nodename, nodename Len, processCreateTime
// and processNameString in the format <\node_name>.<cpu>,<pin>
//
// // Return status: 0, if all ok. <errnum>, in case of an error.
//
// -----------------------------------------------------------------------
Lng32 ComRtGetProgramInfo(char * pathName, /* out */
Lng32 pathNameMaxLen,
short &processType,/* out */
Int32 &cpu, /* cpu */
pid_t &pin, /* pin */
Lng32 &nodeNumber,
char * nodeName, // GuaNodeNameMaxLen+1
short &nodeNameLen,
Int64 &processCreateTime,
char *processNameString,
char *parentProcessNameString
, SB_Verif_Type *verifier
)
{
Lng32 retcode = 0;
processType = 2;
strcpy(nodeName, "NSK");
nodeNameLen = strlen("NSK");
NAProcessHandle myPhandle;
myPhandle.getmine();
myPhandle.decompose();
cpu = myPhandle.getCpu();
pin = myPhandle.getPin();
if (verifier)
*verifier = myPhandle.getSeqNum();
// Map the node number to cpu
nodeNumber = cpu;
strcpy(processNameString, myPhandle.getPhandleString());
MS_Mon_Process_Info_Type processInfo;
if ((retcode = msg_mon_get_process_info_detail(
processNameString, &processInfo))
!= XZFIL_ERR_OK)
return retcode;
processCreateTime = ComRtGetJulianFromUTC(processInfo.creation_time);
if (processInfo.parent_nid != -1 &&
processInfo.parent_pid != -1 && parentProcessNameString)
strcpy(parentProcessNameString, processInfo.parent_name);
else
parentProcessNameString = NULL;
return retcode;
}
Lng32 ComRtGetProcessPagesInUse(Int64 &pagesInUse /* out */)
{
pagesInUse = -1;
return 0;
}
// IN: if cpu, pin and nodeName are passed in, is that to find process.
// Otherwise, use current process
// OUT: processCreateTime: time when this process was created.
Lng32 ComRtGetProcessCreateTime(short *cpu, /* cpu */
pid_t *pin, /* pin */
short *nodeNumber,
Int64 &processCreateTime,
short &errorDetail
)
{
Lng32 retcode = 0;
MS_Mon_Process_Info_Type processInfo;
char processName[MS_MON_MAX_PROCESS_NAME];
Int32 lnxCpu = (Int32) (*cpu);
Int32 lnxPin = (Int32) (*pin);
processCreateTime = 0;
if ((retcode = msg_mon_get_process_name(lnxCpu, lnxPin, processName))
!= XZFIL_ERR_OK)
return retcode;
if ((retcode = msg_mon_get_process_info_detail(processName, &processInfo))
!= XZFIL_ERR_OK)
return retcode;
processCreateTime = ComRtGetJulianFromUTC(processInfo.creation_time);
return retcode;
}
Lng32 ComRtGetIsoMappingEnum()
{
return (Lng32)CharInfo::DefaultCharSet;
}
char * ComRtGetIsoMappingName()
{
Lng32 ime = ComRtGetIsoMappingEnum();
return (char*)CharInfo::getCharSetName((CharInfo::CharSet)ime);
}
Int32 ComRtGetCPUArray(Int32 *&cpuArray, NAHeap *heap)
{
Int32 nodeCount = 0;
Int32 configuredNodeCount=0;
Int32 nodeMax = 0;
MS_Mon_Node_Info_Entry_Type *nodeInfo = NULL;
cpuArray = NULL;
// Get the number of nodes to know how much info space to allocate
Int32 error = msg_mon_get_node_info(&nodeCount, 0, NULL);
if (error != 0)
return 0;
if (nodeCount <= 0)
return 0;
// Allocate the space for node info entries
nodeInfo = new(heap) MS_Mon_Node_Info_Entry_Type[nodeCount];
cpuArray = new(heap) Int32[nodeCount];
if (!nodeInfo || !cpuArray)
return 0;
// Get the node info
memset(nodeInfo, 0, sizeof(MS_Mon_Node_Info_Entry_Type) * nodeCount);
nodeMax = nodeCount;
error = msg_mon_get_node_info(&nodeCount, nodeMax, nodeInfo);
if (error != 0)
{
NADELETEBASIC(nodeInfo, heap);
NADELETEBASIC(cpuArray, heap);
cpuArray = NULL;
return 0;
}
if (nodeCount > nodeMax)
// very unlikely, could happen if a node just got added
nodeCount = nodeMax;
for (Int32 i = 0; i < nodeCount; i++)
{
if (!nodeInfo[i].spare_node)
{
cpuArray[configuredNodeCount] = nodeInfo[i].nid;
configuredNodeCount++;
}
}
NADELETEBASIC(nodeInfo, heap);
return configuredNodeCount;
}
NABoolean ComRtGetCpuStatus(char *nodeName, short cpuNum)
{
NABoolean retval = FALSE; // assume cpu is down
MS_Mon_Node_Info_Type nodeInfo;
memset(&nodeInfo, 0, sizeof(nodeInfo));
Int32 error = msg_mon_get_node_info_detail(cpuNum, &nodeInfo);
if ( XZFIL_ERR_OK == error ) {
if ( MS_Mon_State_Up == nodeInfo.node[0].state ) retval = TRUE;
}
return retval;
}
void genLinuxCorefile(const char *eventMsg)
{
if (eventMsg)
SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__, eventMsg, 0);
NAProcessHandle myPhandle;
myPhandle.getmine();
myPhandle.decompose();
char coreFile[PATH_MAX];
msg_mon_dump_process_name(NULL, myPhandle.getPhandleString(),
coreFile);
char coreLocationMessage[PATH_MAX + 200];
sprintf(coreLocationMessage,
"Core-file for this process created at %s.", coreFile);
SQLMXLoggingArea::logExecRtInfo(__FILE__, __LINE__,
coreLocationMessage, 0);
}
#ifdef _DEBUG
void saveTrafStack(LIST(TrafAddrStack*) *la, void *addr)
{
void *btArr[12];
size_t size;
char **strings;
size = backtrace(btArr, 12);
strings = backtrace_symbols(btArr, size);
TrafAddrStack *tas = NULL;
if (size > 0)
{
tas = (TrafAddrStack*) malloc(sizeof(TrafAddrStack));
if (tas)
{
tas->addr = addr;
tas->size = size;
tas->strings = strings;
la->insert(tas);
}
}
}
bool delTrafStack(LIST(TrafAddrStack*) *la, void *addr)
{
for (CollIndex i = 0; i < la->entries(); i++)
{
TrafAddrStack * tas = la->at(i);
if (tas->addr == addr)
{
free(tas->strings);
la->removeAt(i);
delete tas;
return (true);
}
}
return false; // should not happen
}
// helper function to de-mangle c++ names
void stackDemangle(char *stackString, char *callName, Int32 callNameLen)
{
char *nameStart = NULL, *nameOffset = NULL, *nameEnd = NULL;
for (char *loc = stackString; *loc; loc++)
{
if (*loc == '(')
nameStart = loc;
else if (*loc == '+')
nameOffset = loc;
else if (*loc == ')' && nameOffset)
{
nameEnd = loc;
break;
}
}
if (nameStart && nameOffset && nameEnd && nameStart < nameOffset)
{
Int32 stat;
size_t realSize = callNameLen;
char retedName[800];
*nameStart = 0;
*nameOffset++ = 0;
*nameEnd = 0;
char *ret = abi::__cxa_demangle(++nameStart, retedName, &realSize, &stat);
if (stat == 0)
{
sprintf(callName, " %s : %s+%s", stackString, ret, nameOffset);
}
else
{ // C function name?
sprintf(callName, " %s : %s()+%s", stackString, nameStart, nameOffset);
}
}
else // failed to parse
{
sprintf(callName, " %s", stackString);
}
}
void dumpTrafStack(LIST(TrafAddrStack*) *la, const char *header, bool toFile)
{
static THREAD_P Int32 fnValid = 0;
static THREAD_P char fn[120];
char funcName[800];
size_t size;
char **strings;
FILE *myFd = NULL;
if (la == NULL || la->entries() < 1)
return;
if (toFile)
{
if (fnValid == 0)
{
Int32 nid = 0;
Int32 pid = 0;
Int64 tid = 0;
char *progFileName = (char *) "noname";
char pName[MS_MON_MAX_PROCESS_NAME];
if (XZFIL_ERR_OK != msg_mon_get_my_info(&nid, &pid, &pName[0],
sizeof(pName), NULL, NULL, NULL, &tid))
tid = rand();
char *fname = getenv("TRAF_STACK_TRACE_FILE_NAME");
if (fname == NULL || *fname == 0)
sprintf(fn, "proc_%lu", tid);
else
sprintf(fn, "%s_%lu", fname, tid);
fnValid = 1;
}
if (fnValid)
myFd = fopen(fn, "a");
if (myFd == NULL)
{
if (header)
printf("%s:\n", header);
fnValid = 0;
}
else
{
if (header)
fprintf(myFd, "%s:\n", header);
}
}
for (CollIndex i = 0; i < la->entries(); i++)
{
TrafAddrStack * tas = la->at(i);
size = tas->size;
strings = tas->strings;
if (myFd)
{
if (header)
fprintf(myFd, ">>Unfreed at %p:\n", tas->addr);
for (size_t k = 0; k < size; k++)
{
stackDemangle(strings[k], funcName, 800);
fprintf(myFd, "%s\n", funcName);
}
fflush(myFd);
}
else
{
if (header)
printf(">>Unfreed at %p:\n", tas->addr);
for (size_t k = 0; k < size; k++)
{
stackDemangle(strings[k], funcName, 800);
printf("%s\n", funcName);
}
}
free(strings); // free the memory allocated by backtrace_symbols()
}
la->clear(); // all gone
if (myFd)
{
fprintf(myFd, "\n");
fclose(myFd);
myFd = NULL;
}
}
#endif // _DEBUG
Int16 getBDRClusterName(char *bdrClusterName)
{
MS_Mon_Reg_Get_Type regList;
Int16 error;
strcpy(bdrClusterName, "UNKNOWN");
if ((error = msg_mon_reg_get(MS_Mon_ConfigType_Cluster,
false,
(char *)"CLUSTER",
(char *)BDR_CLUSTER_NAME_KEY,
&regList)) == XZFIL_ERR_OK)
{
if (regList.num_returned > 0 &&
(strcmp(regList.list[0].key, BDR_CLUSTER_NAME_KEY) == 0))
{
strncpy(bdrClusterName, regList.list[0].value, BDR_CLUSTER_NAME_LEN);
Int16 i = BDR_CLUSTER_NAME_LEN-1;
while (bdrClusterName[i] == ' ')
i--;
bdrClusterName[i+1] = '\0';
}
}
return error;
}
int get_phandle_with_retry(char *pname, SB_Phandle_Type *phandle)
{
Int32 retrys = 0;
int lv_fserr = FEOK;
const Int32 NumRetries = 10;
timespec retryintervals[NumRetries] = {
{ 0, 10*1000*1000 } // 10 ms
, { 0, 100*1000*1000 } // 100 ms
, { 1, 0 } // 1 second
, { 3, 0 } // 3 seconds
, { 6, 0 } // 6 seconds
, { 10, 0 } // 10 seconds
, { 15, 0 } // 15 seconds
, { 15, 0 } // 15 seconds
, { 15, 0 } // 15 seconds
, { 15, 0 } // 15 seconds
} ;
for (;;)
{
lv_fserr = XFILENAME_TO_PROCESSHANDLE_(pname, strlen(pname), phandle);
if (retrys >= NumRetries)
break;
if ((lv_fserr == FEPATHDOWN) ||
(lv_fserr == FEOWNERSHIP))
nanosleep(&retryintervals[retrys++], NULL);
else
break;
}
return lv_fserr;
}
// A function to return the string "UNKNOWN (<val>)" which can be
// useful when displaying values from an enumeration and an unexpected
// value is encountered. The function is thread-safe. The returned
// string can be overwritten by another call to the function from the
// same thread.
static __thread char ComRtGetUnknownString_Buf[32];
const char *ComRtGetUnknownString(Int32 val)
{
sprintf(ComRtGetUnknownString_Buf, "UNKNOWN (%d)", (int) val);
return &(ComRtGetUnknownString_Buf[0]);
}
pid_t ComRtGetConfiguredPidMax()
{
FILE *fd_pid_max;
char buffer[100];
size_t bytesRead = 0;
pid_t pid_max = 0;
fd_pid_max = fopen("/proc/sys/kernel/pid_max", "r");
if (fd_pid_max != NULL) {
bytesRead = fread(buffer, 1, sizeof(buffer)-1, fd_pid_max);
if (ferror(fd_pid_max))
assert(false);
if (feof(fd_pid_max))
clearerr(fd_pid_max);
buffer[bytesRead] = '\0';
pid_max = atoi(buffer);
fclose(fd_pid_max);
return pid_max;
}
return 0;
}