📄 unixdmon.cpp
字号:
{ iFlags |= FLG_RDATA; }
else
{ return 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_RLIMITFSIZE, pVariable ) )
{
if ( AddResourceLimit( RLIMIT_FSIZE, "RLIMIT_FSIZE", pValue,
&tRFSize ) )
{ iFlags |= FLG_RFSIZE; }
else
{ return 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_USER, pVariable ) )
{
if ( !GetUid( pValue ) )
{ return 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_GROUP, pVariable ) )
{
if ( !GetGid( pValue ) )
{ return 0; };
}
else if ( !PIUtil_stricmp( KEY_CONF_PIDFILE, pVariable ) )
{
ofstream ofs( pValue );
if ( ofs.good() )
{
ofs << ::getpid() << endl;
}
else
{
PILog_addMessage( PIObject_getDB( pObject ),
PIObject_getConfigurationDB( pObject ), PILOG_ERROR,
"%sUNIXDaemon: Unable to open PID file: '%s'",
pWhere, pValue );
return 0;
};
}
else if ( !PIUtil_stricmp( KEY_CONF_LOCKFILENAME, pVariable ) )
{
const char *pTmp = tempnam( 0, "Pi3" );
assert( pTmp );
pLockFileName = PIUtil_strdup( pTmp );
/* ---
--- */
assert( pValue );
assert( pLockFileName );
ofstream ofs( pValue );
if ( ofs.good() ) {
ofs << pLockFileName << endl;
pMainLockFileName = PIUtil_strdup( pValue );
}
else
{
PILog_addMessage( PIObject_getDB( pObject ),
PIObject_getConfigurationDB( pObject ), PILOG_ERROR,
"UNIXDaemon: Could not write lockfile name '%s' \
into specified file '%s'.", pLockFileName, pValue );
*pLockFileName = '\0';
return 0;
};
}
else
{
PILog_addMessage( PIObject_getDB( pObject ),
PIObject_getConfigurationDB( pObject ), PILOG_ERROR,
"%sUNIXDaemon: Unknown parameter '%s'", pWhere, pVariable );
};
#endif
return 1;
};
/* --- --- */
static int ParameterFn( void *pData, const char *pVar, const char *pVal,
const char *pWhere )
{
assert( pData );
return ((UNIXDaemon *)pData)->Parameter( pVar, pVal, pWhere );
};
public:
/* --- --- */
UNIXDaemon( PIObject *pTheObject, int iArgc, const char *ppArgv[] )
: pObject( pTheObject ),
pServerObject( 0 ),
iOK( 0 ),
pMessage( 0 )
#if POSIX
, iFlags( 0 ),
tId( (uid_t)-1 ),
tGid( (gid_t)-1 ),
iNumberOfProcesses( 5 ), /* if this is changed then change the
documentation above */
pProcessIds( 0 ),
pMainLockFileName( 0 ),
pLockFileName( 0 ),
tParentPid( ::getpid() )
{
if ( !PIObject_readParameters( pObject, iArgc, ppArgv, ParameterFn,
this ) )
{ return; };
/* --- Generate lockfile ? --- */
if ( pLockFileName )
{
if ( !GenerateLockFile() )
{ return; };
};
pProcessIds = new pid_t[iNumberOfProcesses];
if ( !pProcessIds )
{ return; };
memset( pProcessIds, 0, sizeof( pid_t ) * iNumberOfProcesses );
#else
{
if ( !PIObject_readParameters( pObject, iArgc, ppArgv, ParameterFn,
this ) )
{ return; };
#endif
/* --- load up the server object --- */
pServerObject = PIObject_loadEx( pObject, KEY_CONF_SERVEROBJECT );
if ( !pServerObject )
{ return; };
iOK = 1;
};
/* --- --- */
virtual ~UNIXDaemon()
{
#if POSIX
/* ---
These cleanup tasks shutdown the server cleanly, this is not
something that should happen when a child process exists, so
return if this is a child process.
We can determine if this is a child process by comparing the
the current process id to tParentPid, the process id when
this object was constructed and before any fork's.
--- */
if ( ::getpid()!=tParentPid )
{ return; };
int i;
/* --- kill child processes --- */
if ( pProcessIds )
{
for( i=0; i<iNumberOfProcesses; i++ )
{
if ( pProcessIds[i] )
{
::kill( pProcessIds[i], SIGTERM );
};
};
};
/* ---
NOTE: maybe wait for notification that processes have died
--- */
/* --- remove the file containing the lockfile name --- */
if ( pMainLockFileName && *pMainLockFileName )
{ ::unlink( pMainLockFileName ); };
if ( pMainLockFileName )
{ PIUtil_free( pMainLockFileName ); };
/* --- remove the lockfile --- */
if ( pLockFileName && *pLockFileName )
{ ::unlink( pLockFileName ); };
if ( pLockFileName )
{ PIUtil_free( pLockFileName ); };
delete [] pProcessIds;
#endif
PIObject_delete( pServerObject, 0, 0 );
if ( pMessage ) { PIUtil_free( pMessage ); };
};
#if POSIX
/* --- signal handler --- */
static void SignalHandler( int iSignal )
{
switch( iSignal )
{
case SIGTERM:
exit( 0 );
break;
default:;
};
};
/* --- child function --- */
int ChildMain( int iArgc, const char *ppArgv[] )
{
/* --- ignore SIGINT --- */
signal( SIGINT, SIG_IGN );
/* --- quick exit on sigterm, don't bother freeing memory --- */
signal( SIGTERM, SignalHandler );
/* --- make sure we don't kill any siblings --- */
memset( pProcessIds, 0, sizeof( pid_t ) * iNumberOfProcesses );
/* --- set resource limits --- */
if ( iFlags & FLG_RCORE )
{
if ( !SetRLimit( RLIMIT_CORE, &tRCore, "RLIMIT_CORE" ) )
{ return PIAPI_ABORT; };
};
if ( iFlags & FLG_RCPU )
{
if ( !SetRLimit( RLIMIT_CPU, &tRCPU, "RLIMIT_CPU" ) )
{ return PIAPI_ABORT; };
};
if ( iFlags & FLG_RDATA )
{
if ( !SetRLimit( RLIMIT_DATA, &tRData, "RLIMIT_DATA" ) )
{ return PIAPI_ABORT; };
};
if ( iFlags & FLG_RFSIZE )
{
if ( !SetRLimit( RLIMIT_FSIZE, &tRFSize, "RLIMIT_FSIZE" ) )
{ return PIAPI_ABORT; };
};
#if RUN_MAIN_AS_ROOT
/*
** Change the effective user and group ids
*/
/* --- group id --- */
if ( iFlags & FLG_GID )
{
if ( ::setgid( tGid )==-1 )
{
Cerr() << "Could not set group id to '" << tGid <<
"' error code is " << errno << endl;
return PIAPI_ABORT;
};
};
/* --- user id --- */
if ( iFlags & FLG_UID )
{
if ( ::setuid( tId )==-1 )
{
Cerr() << "Could not set user id to '" << tId <<
"' error code is " << errno << endl;
return PIAPI_ABORT;
};
};
#endif
int iRet = PILogic_execute( pServerObject, iArgc, ppArgv );
/* ---
If there was an error write out details
--- */
if ( iRet )
{
Cerr() << "Error(s) during child execution:-" << endl;
PILog_writeDiagnostics( PIObject_getDB( pObject ), PILOG_ALL, 0 );
cout.flush();
cerr.flush();
};
return 0;
};
#endif
/* --- --- */
int DoExecute( int iArgc, const char *ppArgv[] )
{
/* --- Write start message? --- */
if ( pMessage )
{
cout << pMessage << endl;
};
#if !POSIX
return PILogic_execute( pServerObject, iArgc, ppArgv );
#else
assert( pProcessIds );
#if !RUN_MAIN_AS_ROOT
/*
** Change the effective user and group ids
*/
/* --- group id --- */
if ( iFlags & FLG_GID )
{
if ( ::setgid( tGid )==-1 )
{
Cerr() << "Could not set group id to '" << tGid <<
"' error code is " << errno << endl;
return PIAPI_ERROR;
};
};
/* --- user id --- */
if ( iFlags & FLG_UID )
{
if ( ::setuid( tId )==-1 )
{
Cerr() << "Could not set user id to '" << tId <<
"' error code is " << errno << endl;
return PIAPI_ABORT;
};
};
#endif
int iCurrentNumberOfChildren = 0;
for(;;)
{
/* --- create new child processes --- */
while( iCurrentNumberOfChildren<iNumberOfProcesses )
{
#if 0
/*
** LATER, XXX
**
** This is obselete
*/
/* ---
If a lockfile was created then before forking
check that the lockfile still exists, a child
may have removed it in an attempt to stop the server
because of a tight fork() loop caused by a problem with
the lockfile
--- */
struct stat tStat;
if ( pLockFileName && stat( pLockFileName, &tStat )==-1 )
{
Cerr() << "**" << endl;
Cerr() << "** Lockfile '" << pLockFileName <<
"' does not exist, aborting daemon." << endl;
Cerr() << "**" << endl;
Cerr() << "** This typically indicates a serious error in \
child process execution." << endl;
Cerr() << "**" << endl;
return PIAPI_ABORT;
};
#endif
int iChildPid = ::fork();
switch( iChildPid )
{
case -1:
/* --- assume this is EAGAIN for tables full --- */
sleep( 5 ); /* extremely sophisticated response */
break;
case 0:
if ( ChildMain( iArgc, ppArgv )==PIAPI_ABORT )
{
/* --- Abort the server --- */
if ( pLockFileName )
{ ::unlink( pLockFileName ); };
};
return PIAPI_COMPLETED;
default:
/* ---
this is the parent, record this new child.
--- */
{
iCurrentNumberOfChildren++;
assert( iCurrentNumberOfChildren <=
iNumberOfProcesses );
int i=0;
for(i=0; i<iNumberOfProcesses; i++ )
{
if ( pProcessIds[i]==0 )
{
pProcessIds[i] = iChildPid;
break;
};
};
assert( i<iNumberOfProcesses );
};
}; /* --- switch on fork --- */
}; /* --- loop while we have not reached max.# processes --- */
/* ---
Before we can create another process we must wait for one
to die
--- */
for(;;)
{
int iStatus;
pid_t tPid = ::wait( &iStatus );
if ( tPid==-1 )
{
if ( errno!=EINTR )
{
/* --- signal caught, exit --- */
Cerr() << "Unknown error from wait(): " << errno
<< endl;
};
return PIAPI_COMPLETED;
}
else
{
/* ---
if this child process did not exit normally, then
log a message
--- */
if ( !(WIFEXITED(iStatus)) )
{
Cerr() << "Child process " << tPid <<
" did not exit normally, status: " << iStatus
<< endl;
};
/* --- mark this process as reaped --- */
int iProcessSlot = -1; /* slot of exitted process */
for(int i=0; i<iNumberOfProcesses; i++ )
{
if ( pProcessIds[i]==tPid )
{
iProcessSlot = i;
pProcessIds[i] = 0;
break;
};
};
if ( iProcessSlot==-1 )
{
/* ---
This is not a child process we know about. This
could happen if a restart occurred (via SIGHUP) and
child processes from a previous iteration are
signalling.
In this case ignore the signal
---- */
}
else
{
/* ----
One of the current children has died, decrement the
child process count and break to allow a new one
to be created
--- */
iCurrentNumberOfChildren--;
break;
};
};
};
};
return PIAPI_COMPLETED;
#endif /* POSIX */
};
/* --- --- */
int Execute( int iArgc, const char *ppArgv[] )
{
int iRet = DoExecute( iArgc, ppArgv );
switch( iRet )
{
case PIAPI_COMPLETED:
break;
case PIAPI_ABORT:
CONFIG_ERR( pObject, "UNIXDaemon: A critical error occurred." );
break;
default:
CONFIG_ERR( pObject, "UNIXDaemon: An error occurred." );
};
return iRet;
};
/* --- --- */
inline int IsOK() { return iOK; };
};
/*____________________________________________________________________________*\
*
Function:
Synopsis:
Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_onClassLoad( PIClass_LoadAction eLoad, void * )
{
switch( eLoad )
{
case STARTUP:
default:;
};
return PIAPI_COMPLETED;
}
/*____________________________________________________________________________*\
*
Function:
Synopsis:
Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_constructor( PIObject *pObj, int iArgc,
const char *ppArgv[] )
{
UNIXDaemon *pUNIXDaemon = new UNIXDaemon( pObj, iArgc, ppArgv );
if (!( pUNIXDaemon && pUNIXDaemon->IsOK() ))
{
delete pUNIXDaemon;
return PIAPI_ERROR;
};
PIObject_setUserData( pObj, pUNIXDaemon );
return PIAPI_COMPLETED;
}
/*____________________________________________________________________________*\
*
Function:
Synopsis:
Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_copyConstructor( PIObject *, int, const char *[] )
{
/* --- this class doesn't support copy construction --- */
return PIAPI_ERROR;
}
/*____________________________________________________________________________*\
*
Function:
Synopsis:
Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_execute( PIObject *pObj, int iArgc,
const char *ppArgv[] )
{
if ( !pObj ) return PIAPI_ERROR;
return ((UNIXDaemon *)PIObject_getUserData(pObj))->Execute( iArgc, ppArgv );
}
/*____________________________________________________________________________*\
*
Function:
Synopsis:
Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_destructor( PIObject *pObj, int, const char *[] )
{
delete (UNIXDaemon *)PIObject_getUserData( pObj );
return PIAPI_COMPLETED;
}
#if 0
/*___+++CNF_BEGIN+++___*/
<Class>
Name UNIXDaemonClass
Type LogicExtension
Library Server
OnClassLoad UNIXDaemon_onClassLoad
Constructor UNIXDaemon_constructor
CopyConstructor UNIXDaemon_copyConstructor
Destructor UNIXDaemon_destructor
Execute UNIXDaemon_execute
</Class>
<Object>
Name UNIXDaemon
Class UNIXDaemonClass
</Object>
/*___+++CNF_END+++___*/
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -