2012-02-19 12:53:41 +00:00
/ * * Enterprise Control Configuration and Logging
Copyright ( C ) 2012 Free Software Foundation , Inc .
Written by : Richard Frith - Macdonald < rfm @ gnu . org >
Date : Febrary 2010
Originally developed from 1996 to 2012 by Brainstorm , and donated to
the FSF .
This file is part of the GNUstep project .
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 3 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
Library General Public License for more details .
You should have received a copy of the GNU Lesser General Public
License along with this library ; if not , write to the Free
Software Foundation , Inc . , 51 Franklin Street , Fifth Floor ,
Boston , MA 02111 USA .
* /
2012-02-19 11:59:22 +00:00
# import < Foundation / NSArray . h >
# import < Foundation / NSAutoreleasePool . h >
# import < Foundation / NSConnection . h >
# import < Foundation / NSData . h >
# import < Foundation / NSDate . h >
# import < Foundation / NSDebug . h >
# import < Foundation / NSDictionary . h >
# import < Foundation / NSDistantObject . h >
# import < Foundation / NSException . h >
# import < Foundation / NSFileManager . h >
# import < Foundation / NSNotification . h >
# import < Foundation / NSObjCRuntime . h >
# import < Foundation / NSPort . h >
# import < Foundation / NSProcessInfo . h >
# import < Foundation / NSRunLoop . h >
# import < Foundation / NSScanner . h >
# import < Foundation / NSSerialization . h >
# import < Foundation / NSString . h >
# import < Foundation / NSTimer . h >
# import < Foundation / NSUserDefaults . h >
# import < Foundation / NSValue . h >
# import < GNUstepBase / GSObjCRuntime . h >
2013-08-22 18:11:15 +00:00
# import < GNUstepBase / NSObject + GNUstepBase . h >
2012-02-19 11:59:22 +00:00
# import "EcProcess.h"
# import "EcLogger.h"
# import "EcAlarm.h"
# import "EcAlarmDestination.h"
# import "EcHost.h"
# import "EcUserDefaults.h"
# import "EcBroadcastProxy.h"
# include "config.h"
# ifdef HAVE_SYS _SIGNAL _H
# include < sys / signal . h >
# endif
# ifdef HAVE_SYS _FILE _H
# include < sys / file . h >
# endif
# ifdef HAVE_SYS _FCNTL _H
# include < sys / fcntl . h >
# endif
# ifdef HAVE_UNISTD _H
# include < unistd . h >
# endif
# ifdef HAVE_PWD _H
# include < pwd . h >
# endif
2012-02-19 14:42:50 +00:00
# ifdef HAVE_SYS _TIME _H
# include < sys / time . h >
# endif
# ifdef HAVE_SYS _RESOURCE _H
# include < sys / resource . h >
# endif
2015-07-03 19:23:42 +00:00
# include < stdio . h >
2012-02-19 14:42:50 +00:00
2012-02-19 11:59:22 +00:00
# if ! defined ( EC_DEFAULTS _PREFIX )
# define EC_DEFAULTS _PREFIX nil
# endif
# if ! defined ( EC_DEFAULTS _STRICT )
# define EC_DEFAULTS _STRICT NO
# endif
# if ! defined ( EC_EFFECTIVE _USER )
2012-10-09 12:53:56 +00:00
# define EC_EFFECTIVE _USER nil
2012-02-19 11:59:22 +00:00
# endif
2014-11-02 14:30:24 +00:00
@ interface EcDefaultRegistration : NSObject
{
NSString * name ; // The name / key of the default ( without prefix )
NSString * type ; // The type text for the default
NSString * help ; // The help text for the default
SEL cmd ; // method to update when default values change
id obj ; // The latest value of the default
}
+ ( void ) defaultsChanged : ( NSUserDefaults * ) defs ;
+ ( void ) registerDefault : ( NSString * ) name
withTypeText : ( NSString * ) type
andHelpText : ( NSString * ) help
action : ( SEL ) cmd ;
+ ( void ) showHelp ;
@ end
2012-02-19 11:59:22 +00:00
/ * Lock for controlling access to per - process singleton instance .
* /
2012-03-09 09:22:09 +00:00
static NSRecursiveLock * ecLock = nil ;
2012-02-19 11:59:22 +00:00
static BOOL cmdFlagDaemon = NO ;
static BOOL cmdFlagTesting = NO ;
static BOOL cmdIsQuitting = NO ;
2014-05-16 22:13:43 +00:00
static BOOL cmdIsRunning = NO ;
2015-03-26 11:33:02 +00:00
static BOOL cmdKeepStderr = NO ;
2013-12-05 16:39:00 +00:00
static NSInteger cmdQuitStatus = 0 ;
2012-02-19 11:59:22 +00:00
static NSString * cmdInst = nil ;
static NSString * cmdName = nil ;
static NSString * cmdUser = nil ;
static NSUserDefaults * cmdDefs = nil ;
static NSString * cmdDebugName = nil ;
static NSMutableDictionary * cmdLogMap = nil ;
2014-11-26 08:59:50 +00:00
static NSDate * started = nil ; / * Time object was created . * /
2015-07-09 12:08:58 +00:00
static NSDate * memStats = nil ; / * Time stats were started . * /
2014-11-26 08:59:50 +00:00
static NSTimeInterval lastIP = 0.0 ; / * Time of last input to object . * /
static NSTimeInterval lastOP = 0.0 ; / * Time of last output by object . * /
2012-02-19 11:59:22 +00:00
static Class cDateClass = 0 ;
static Class dateClass = 0 ;
static Class stringClass = 0 ;
2012-02-19 14:42:50 +00:00
static int cmdSignalled = 0 ;
2012-02-19 11:59:22 +00:00
static RETSIGTYPE
ihandler ( int sig )
{
static BOOL beenHere = NO ;
signal ( sig , ihandler ) ;
if ( NO = = beenHere )
{
beenHere = YES ;
signal ( SIGABRT , SIG_DFL ) ;
abort ( ) ;
}
exit ( sig ) ;
# if RETSIGTYPE ! = void
return 0 ;
# endif
}
static RETSIGTYPE
qhandler ( int sig )
{
2013-08-20 09:05:39 +00:00
if ( SIGHUP = = sig )
{
static int hupCount = 0 ;
/ * We allow multiple HUP signals since , while shutting down we may
* attempt to write out messages to our terminal , generating more
* signals , and we want to ignore those and shut down cleanly .
* /
if ( hupCount + + < 1000 )
{
cmdSignalled = 0 ; // Allow signal to be set .
}
}
2012-02-19 11:59:22 +00:00
/ * We store the signal value in a global variable and return to normal
2013-08-19 09:05:07 +00:00
* processing . . . that way later code can check on the state of the
2012-02-19 11:59:22 +00:00
* variable and take action outside the handler .
* We can ' t act immediately here inside the handler as the signal may
* have interrupted some vital library ( eg malloc ( ) ) and left it in a
* state such that our code can ' t continue . For instance if we try to
* cleanup after a signal and call free ( ) , the process may hang waiting
2015-07-03 19:23:42 +00:00
* for a lock that the interupted function still holds .
2012-02-19 11:59:22 +00:00
* /
2012-02-19 14:42:50 +00:00
if ( 0 = = cmdSignalled )
2012-02-19 11:59:22 +00:00
{
2013-08-20 09:05:39 +00:00
cmdSignalled = sig ; // Record signal for event loop .
2012-02-19 11:59:22 +00:00
}
else
{
static BOOL beenHere = NO ;
2013-08-20 09:05:39 +00:00
/ * We have been signalled more than once . . . so let ' s try to
* crash rather than continuing .
* /
2012-02-19 11:59:22 +00:00
if ( NO = = beenHere )
{
beenHere = YES ;
signal ( SIGABRT , SIG_DFL ) ;
abort ( ) ;
}
2013-08-20 09:05:39 +00:00
exit ( cmdSignalled ) ; // Exit with * first * signal number
2012-02-19 11:59:22 +00:00
}
# if RETSIGTYPE ! = void
return 0 ;
# endif
}
NSString *
cmdVersion ( NSString * ver )
{
2013-08-22 18:11:15 +00:00
static NSString * version = @ "1997-2013" ;
2012-02-19 11:59:22 +00:00
if ( ver ! = nil )
{
ASSIGNCOPY ( version , ver ) ;
}
return version ;
}
static NSString * homeDir = nil ;
NSString *
cmdHomeDir ( )
{
return homeDir ;
}
void
cmdSetHome ( NSString * home )
{
ASSIGNCOPY ( homeDir , home ) ;
}
2015-02-23 14:42:27 +00:00
static NSString * logsDir = nil ;
NSString *
ecLogsSubdirectory ( )
{
return logsDir ;
}
void
ecSetLogsSubdirectory ( NSString * pathComponent )
{
ASSIGNCOPY ( logsDir , pathComponent ) ;
}
2012-02-19 11:59:22 +00:00
static NSString * userDir = nil ;
static NSString *
cmdUserDir ( )
{
if ( userDir = = nil )
return NSHomeDirectoryForUser ( cmdUser ) ;
else
return userDir ;
}
static NSString *
cmdSetUserDirectory ( NSString * dir )
{
if ( dir = = nil )
{
dir = NSHomeDirectoryForUser ( cmdUser ) ;
}
else if ( [ dir isAbsolutePath ] = = NO )
{
dir = [ NSHomeDirectoryForUser ( cmdUser )
stringByAppendingPathComponent : dir ] ;
}
ASSIGNCOPY ( userDir , dir ) ;
return userDir ;
}
static NSString * dataDir = nil ;
/ *
* Return the current logging directory - if ' today ' is not nil , treat it as
* the name of a subdirectory in which todays logs should be archived .
* Create the directory path if necessary .
* /
NSString *
cmdLogsDir ( NSString * date )
{
NSFileManager * mgr = [ NSFileManager defaultManager ] ;
NSString * str = cmdUserDir ( ) ;
2015-02-23 14:42:27 +00:00
NSString * component ;
2012-02-19 11:59:22 +00:00
BOOL flag ;
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 11:59:22 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
NSLog ( @ "Unable to create directory - %@" , str ) ;
return nil ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
NSLog ( @ "The path '%@' is not a directory" , str ) ;
return nil ;
}
2015-02-23 14:42:27 +00:00
component = ecLogsSubdirectory ( ) ;
if ( nil = = component )
{
component = @ "DebugLogs" ;
}
str = [ str stringByAppendingPathComponent : component ] ;
2012-02-19 11:59:22 +00:00
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 11:59:22 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
NSLog ( @ "Unable to create directory - %@" , str ) ;
return nil ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
NSLog ( @ "The path '%@' is not a directory" , str ) ;
return nil ;
}
if ( date ! = nil )
{
str = [ str stringByAppendingPathComponent : date ] ;
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 11:59:22 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
NSLog ( @ "Unable to create directory - %@" , str ) ;
return nil ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
NSLog ( @ "The path '%@' is not a directory" , str ) ;
return nil ;
}
}
if ( homeDir ! = nil )
{
str = [ str stringByAppendingPathComponent : homeDir ] ;
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 11:59:22 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
NSLog ( @ "Unable to create directory - %@" , str ) ;
return nil ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
NSLog ( @ "The path '%@' is not a directory" , str ) ;
return nil ;
}
}
return str ;
}
NSString *
cmdLogKey ( EcLogType t )
{
switch ( t )
{
case LT_DEBUG : return @ "Debug" ;
case LT_WARNING : return @ "Warn" ;
case LT_ERROR : return @ "Error" ;
case LT_AUDIT : return @ "Audit" ;
case LT_ALERT : return @ "Alert" ;
default : return @ "UnknownLogType" ;
}
}
NSString *
cmdLogName ( )
{
2012-05-08 16:08:30 +00:00
static NSString * cmdLogName = nil ;
2012-02-19 11:59:22 +00:00
2012-05-08 16:08:30 +00:00
if ( nil = = cmdLogName )
2012-02-19 11:59:22 +00:00
{
2012-05-08 16:08:30 +00:00
[ ecLock lock ] ;
if ( nil = = cmdLogName )
2012-02-19 11:59:22 +00:00
{
2012-05-08 16:08:30 +00:00
NSString * n = [ EcProc cmdName ] ;
if ( nil = = n )
{
n = [ [ NSProcessInfo processInfo ] processName ] ;
}
cmdLogName = [ n copy ] ;
2012-02-19 11:59:22 +00:00
}
2012-05-08 16:08:30 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
}
2012-05-08 16:08:30 +00:00
return cmdLogName ;
2012-02-19 11:59:22 +00:00
}
NSString *
cmdLogFormat ( EcLogType t , NSString * fmt )
{
static NSString * h = nil ;
NSCalendarDate * c = [ [ cDateClass alloc ] init ] ;
NSString * f = cmdLogKey ( t ) ;
NSString * n = cmdLogName ( ) ;
NSString * d ;
NSString * result ;
if ( h = = nil )
{
2012-05-08 16:08:30 +00:00
h = [ [ [ NSHost currentHost ] wellKnownName ] copy ] ;
2012-02-19 11:59:22 +00:00
}
2015-05-07 06:44:22 +00:00
d = [ c descriptionWithCalendarFormat : @ "%Y-%m-%d %H:%M:%S.%F %z" locale : nil ] ;
2012-02-19 11:59:22 +00:00
result = [ stringClass stringWithFormat : @ "%@(%@): %@ %@ - %@\n" ,
n , h , d , f , fmt ] ;
RELEASE ( c ) ;
return result ;
}
EcProcess * EcProc = nil ;
2012-10-12 17:20:45 +00:00
static NSConnection * EcProcConnection = nil ;
2012-02-19 11:59:22 +00:00
static EcAlarmDestination * alarmDestination = nil ;
static EcLogger * alertLogger = nil ;
static EcLogger * auditLogger = nil ;
static EcLogger * debugLogger = nil ;
static EcLogger * errorLogger = nil ;
static EcLogger * warningLogger = nil ;
static NSMutableSet * cmdActions = nil ;
static id cmdServer = nil ;
static id cmdPTimer = nil ;
2012-11-23 12:45:09 +00:00
static NSDictionary * cmdConf = nil ;
2012-02-19 11:59:22 +00:00
static NSDictionary * cmdOperators = nil ;
static NSDate * cmdFirst = nil ;
static NSDate * cmdLast = nil ;
static BOOL cmdIsTransient = NO ;
static NSMutableSet * cmdDebugModes = nil ;
static NSMutableDictionary * cmdDebugKnown = nil ;
static NSMutableString * replyBuffer = nil ;
static SEL cmdTimSelector = 0 ;
static NSTimeInterval cmdTimInterval = 60.0 ;
static NSMutableArray * noNetConfig = nil ;
static NSMutableDictionary * servers = nil ;
2013-04-30 08:13:45 +00:00
static int coreSize = -2 ; // Not yet set
2013-04-30 06:57:37 +00:00
2012-02-19 11:59:22 +00:00
static NSString * hostName = nil ;
2012-05-08 16:08:30 +00:00
static NSString *
ecHostName ( )
{
NSString * name ;
[ ecLock lock ] ;
2012-10-05 14:40:19 +00:00
if ( nil = = hostName )
{
hostName = [ [ [ NSHost currentHost ] wellKnownName ] retain ] ;
}
2012-05-08 16:08:30 +00:00
name = [ hostName retain ] ;
[ ecLock unlock ] ;
return [ name autorelease ] ;
}
2012-02-19 11:59:22 +00:00
2015-07-05 11:39:18 +00:00
static uint64_t memMaximum = 0 ;
static uint64_t memAllowed = 0 ;
2015-07-07 15:11:34 +00:00
static uint64_t memAvge = 0 ; // current period average
static uint64_t memStrt = 0 ; // usage at first check
static uint64_t memLast = 0 ; // usage at last check
static uint64_t memPrev = 0 ; // usage at previous warning
static uint64_t memPeak = 0 ; // peak usage
static uint64_t memWarn = 0 ; // next warning point
static uint64_t memSlot = 0 ; // minute counter
static uint64_t memRoll [ 10 ] ; // last N values
2015-07-03 19:23:42 +00:00
# define MEMCOUNT ( sizeof ( memRoll ) / sizeof ( * memRoll ) )
2015-07-07 15:11:34 +00:00
static NSDate * memTime = nil ; // Time of last alert
2012-02-19 11:59:22 +00:00
2014-11-01 09:18:02 +00:00
# ifndef __MINGW __
static int reservedPipe [ 2 ] = { 0 , 0 } ;
static NSInteger descriptorsMaximum = 0 ;
# endif
2012-02-19 11:59:22 +00:00
static NSString *
findAction ( NSString * cmd )
{
2012-07-05 13:15:27 +00:00
NSString * found = nil ;
2012-02-19 11:59:22 +00:00
cmd = [ cmd lowercaseString ] ;
2012-07-05 13:15:27 +00:00
[ ecLock lock ] ;
if ( nil = = ( found = [ cmdActions member : cmd ] ) )
2012-02-19 11:59:22 +00:00
{
NSEnumerator * enumerator ;
NSString * name ;
enumerator = [ cmdActions objectEnumerator ] ;
while ( nil ! = ( name = [ enumerator nextObject ] ) )
{
if ( YES = = [ name hasPrefix : cmd ] )
{
if ( nil = = found )
{
found = name ;
}
else
{
2012-07-05 13:15:27 +00:00
found = nil ; // Ambiguous
break ;
2012-02-19 11:59:22 +00:00
}
}
}
}
2012-07-05 13:15:27 +00:00
cmd = [ found retain ] ;
[ ecLock unlock ] ;
return [ cmd autorelease ] ;
2012-02-19 11:59:22 +00:00
}
static NSString *
2012-03-09 09:22:09 +00:00
ecCommandHost ( )
2012-02-19 11:59:22 +00:00
{
NSString * host ;
host = [ cmdDefs stringForKey : @ "CommandHost" ] ;
if ( nil = = host )
{
host = @ "" ; / * Local host * /
}
return host ;
}
static NSString *
2012-03-09 09:22:09 +00:00
ecCommandName ( )
2012-02-19 11:59:22 +00:00
{
NSString * name ;
name = [ cmdDefs stringForKey : @ "CommandName" ] ;
if ( nil = = name )
{
name = @ "Command" ;
}
return name ;
}
NSString * cmdDefaultDbg = @ "defaultMode" ;
NSString * cmdConnectDbg = @ "connectMode" ;
NSString * cmdDetailDbg = @ "detailMode" ;
static int comp_len = 0 ;
static int
comp ( const char * s0 , const char * s1 )
{
comp_len = 0 ;
if ( s0 = = 0 ) {
s0 = "" ;
}
if ( s1 = = 0 ) {
s1 = "" ;
}
while ( * s0 ) {
if ( * s0 ! = * s1 ) {
char c0 = islower ( * s0 ) ? toupper ( * s0 ) : * s0 ;
char c1 = islower ( * s1 ) ? toupper ( * s1 ) : * s1 ;
if ( c0 ! = c1 ) {
if ( c0 ! = ' \ 0 ' ) {
comp_len = -1 ; / * s0 is not a substring of s1 . * /
}
return ( -1 ) ;
}
}
comp_len + + ;
s0 + + ;
s1 + + ;
}
if ( * s0 ! = * s1 ) {
return ( -1 ) ;
}
return ( 0 ) ;
}
static NSString *
findMode ( NSDictionary * d , NSString * s )
{
NSArray * a = [ d allKeys ] ;
NSString * o ;
unsigned int i ;
const char * s0 = [ s UTF8String ] ;
const char * s1 ;
int best_pos = -1 ;
int best_len = 0 ;
for ( i = 0 ; i < [ a count ] ; i + + )
{
o = ( NSString * ) [ a objectAtIndex : i ] ;
s1 = [ o UTF8String ] ;
if ( comp ( s0 , s1 ) = = 0 )
{
return o ;
}
if ( comp_len > best_len )
{
best_len = comp_len ;
best_pos = i ;
}
}
if ( best_pos >= 0 )
{
return ( NSString * ) [ a objectAtIndex : best_pos ] ;
}
return nil ;
}
/ *
* Auxiliary object representing a remote server a subclass might need
* to connect to . This class is for EcProcess . m internal use .
* /
@ interface RemoteServer : NSObject
{
/ * This is the string which identifies this server * /
NSString * defaultName ;
/ * These are the actual name and host for this server , as obtained
by configuration for the ` defaultName ' server * /
NSString * name ;
NSString * host ;
/ * The same for multiple servers * /
NSArray * multiple ;
/ * The real object representing the remote server . * /
id proxy ;
/ * An object responding to cmdMadeConnectionToServer : and / or
cmdLostConnectionToServer : * /
id delegate ;
}
/ * Initialize the object - string is the default server name * /
- ( id ) initWithDefaultName : ( NSString * ) string
delegate : ( id ) object ;
- ( NSString * ) defaultName ;
- ( void ) setName : ( NSString * ) string ;
- ( NSString * ) name ;
- ( void ) setHost : ( NSString * ) string ;
- ( void ) setMultiple : ( NSArray * ) config ;
- ( NSArray * ) multiple ;
/ *
* Return a proxy to the remote server ; create one if needed by making
* a connection , using name and host .
* If the server is multiple , create a EcBroadcastProxy object , and returns
* that object .
* /
- ( id ) proxy ;
/ *
* Internal connection management methods
* /
- ( id ) connectionBecameInvalid : ( NSNotification * ) notification ;
- ( BOOL ) connection : ( NSConnection * ) ancestor
shouldMakeNewConnection : ( NSConnection * ) newConn ;
2012-10-12 14:59:15 +00:00
- ( void ) BCP : ( EcBroadcastProxy * ) proxy
lostConnectionToServer : ( NSString * ) name
host : ( NSString * ) host ;
- ( void ) BCP : ( EcBroadcastProxy * ) proxy
madeConnectionToServer : ( NSString * ) name
host : ( NSString * ) host ;
2012-02-19 11:59:22 +00:00
/ *
* Returns YES if the connection is ALIVE , NO if the connection is DEAD
* /
- ( BOOL ) isConnected ;
- ( NSString * ) description ;
- ( void ) update ;
@ end
@ implementation RemoteServer
- ( id ) initWithDefaultName : ( NSString * ) string
delegate : ( id ) object
{
self = [ super init ] ;
if ( self ! = nil )
{
ASSIGNCOPY ( defaultName , string ) ;
ASSIGN ( name , defaultName ) ;
host = @ "*" ;
multiple = nil ;
proxy = nil ;
delegate = object ;
/ *
* Grab configuration information .
* /
[ self update ] ;
}
return self ;
}
- ( void ) dealloc
{
DESTROY ( defaultName ) ;
DESTROY ( name ) ;
DESTROY ( host ) ;
DESTROY ( multiple ) ;
DESTROY ( proxy ) ;
[ [ NSNotificationCenter defaultCenter ] removeObserver : self ] ;
[ super dealloc ] ;
}
- ( NSString * ) defaultName
{
return defaultName ;
}
- ( void ) setName : ( NSString * ) string
{
if ( [ name isEqual : string ] = = NO )
{
ASSIGNCOPY ( name , string ) ;
DESTROY ( proxy ) ;
}
}
- ( NSString * ) name
{
return name ;
}
- ( void ) setHost : ( NSString * ) string
{
if ( [ host isEqual : string ] = = NO )
{
ASSIGNCOPY ( host , string ) ;
DESTROY ( proxy ) ;
}
}
- ( NSString * ) host
{
return host ;
}
- ( void ) setMultiple : ( NSArray * ) config
{
if ( [ multiple isEqual : config ] = = NO )
{
ASSIGNCOPY ( multiple , config ) ;
DESTROY ( proxy ) ;
}
}
- ( NSArray * ) multiple
{
return multiple ;
}
- ( id ) proxy
{
if ( nil = = proxy )
{
if ( nil = = multiple )
{
[ EcProc cmdDbg : cmdConnectDbg
msg : @ "Looking for service %@ on host %@" , name , host ] ;
proxy = [ NSConnection rootProxyForConnectionWithRegisteredName : name
host : host
usingNameServer : [ NSSocketPortNameServer sharedInstance ] ] ;
if ( proxy ! = nil )
{
id connection = [ proxy connectionForProxy ] ;
RETAIN ( proxy ) ;
[ connection setDelegate : self ] ;
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
selector : @ selector ( connectionBecameInvalid : )
name : NSConnectionDidDieNotification
object : connection ] ;
if ( [ delegate respondsToSelector :
@ selector ( cmdMadeConnectionToServer : ) ] = = YES )
{
[ delegate cmdMadeConnectionToServer : defaultName ] ;
}
[ EcProc cmdDbg : cmdConnectDbg
msg : @ "Connected to %@ server on host %@" ,
name , host ] ;
}
else
{
[ EcProc cmdDbg : cmdConnectDbg
msg : @ "Failed to contact %@ server on host %@" ,
name , host ] ;
}
}
else / * a multiple server * /
{
proxy = [ [ EcBroadcastProxy alloc ] initWithReceivers : multiple ] ;
[ proxy BCPsetDelegate : self ] ;
}
}
return proxy ;
}
- ( id ) connectionBecameInvalid : ( NSNotification * ) notification
{
id connection = [ notification object ] ;
[ [ NSNotificationCenter defaultCenter ]
removeObserver : self
name : NSConnectionDidDieNotification
object : connection ] ;
if ( [ connection isKindOfClass : [ NSConnection class ] ] )
{
2012-10-12 18:07:34 +00:00
if ( connection = = [ proxy connectionForProxy ] )
2012-02-19 11:59:22 +00:00
{
[ EcProc cmdDbg : cmdConnectDbg
msg : @ "lost connection - clearing %@." ,
name ] ;
if ( [ delegate respondsToSelector :
@ selector ( cmdLostConnectionToServer : ) ] = = YES )
{
[ delegate cmdLostConnectionToServer : defaultName ] ;
}
RELEASE ( proxy ) ;
proxy = nil ;
}
}
else
{
[ self error : "non-Connection sent invalidation" ] ;
}
return self ;
}
/ * Debugging purposes only * /
- ( BOOL ) connection : ( NSConnection * ) ancestor
shouldMakeNewConnection : ( NSConnection * ) newConn
{
[ EcProc cmdDbg : cmdConnectDbg
msg : @ "New connection 0x%p created" , newConn ] ;
return YES ;
}
- ( BOOL ) isConnected
{
if ( proxy ! = nil )
{
return YES ;
}
else
{
return NO ;
}
}
- ( NSString * ) description
{
if ( multiple = = nil )
{
NSString * status ;
if ( proxy ! = nil )
{
status = @ "LIVE" ;
}
else
{
status = @ "DEAD" ;
}
return [ NSString stringWithFormat :
@ "Connection to server `%@' on host `%@' is %@" ,
name , host , status ] ;
}
else / * multiple server * /
{
if ( proxy = = nil )
{
return [ NSString stringWithFormat :
@ "Multiple connection to servers %@\n"
@ " has not yet been initialized" ,
multiple ] ;
}
else
{
return [ proxy BCPstatus ] ;
}
}
}
- ( void ) BCP : ( EcBroadcastProxy * ) proxy
lostConnectionToServer : ( NSString * ) name
host : ( NSString * ) host
{
if ( [ delegate respondsToSelector :
@ selector ( cmdLostConnectionToServer : ) ] = = YES )
{
/ * FIXME : How do we inform delegate of this ? Is it of any use ? * /
// [ delegate cmdLostConnectionToServer : defaultName ] ;
}
}
- ( void ) BCP : ( EcBroadcastProxy * ) proxy
madeConnectionToServer : ( NSString * ) name
host : ( NSString * ) host
{
if ( [ delegate respondsToSelector :
@ selector ( cmdLostConnectionToServer : ) ] = = YES )
{
/ * FIXME : How do we inform delegate of this ? Is it of any use ? * /
// [ delegate cmdMadConnectionToServer : defaultName ] ;
}
}
- ( void ) update
{
NSString * configKey ;
id configValue ;
configKey = [ defaultName stringByAppendingString : @ "Name" ] ;
configValue = [ cmdDefs stringForKey : configKey ] ;
if ( nil ! = configValue )
{
[ self setName : configValue ] ;
}
configKey = [ defaultName stringByAppendingString : @ "Host" ] ;
configValue = [ cmdDefs stringForKey : configKey ] ;
if ( nil ! = configValue )
{
[ self setHost : configValue ] ;
}
configKey = [ defaultName stringByAppendingString : @ "BroadCast" ] ;
configValue = [ cmdDefs arrayForKey : configKey ] ;
if ( nil ! = configValue )
{
[ self setMultiple : configValue ] ;
}
}
@ end
2014-11-02 14:30:24 +00:00
@ interface EcProcess ( Defaults )
- ( void ) _defMemory : ( id ) val ;
- ( void ) _defRelease : ( id ) val ;
- ( void ) _defTesting : ( id ) val ;
@ end
2012-02-19 11:59:22 +00:00
@ interface EcProcess ( Private )
- ( void ) cmdMesgrelease : ( NSArray * ) msg ;
- ( void ) cmdMesgtesting : ( NSArray * ) msg ;
2015-07-08 09:06:26 +00:00
- ( void ) _memCheck ;
2012-02-19 11:59:22 +00:00
- ( NSString * ) _moveLog : ( NSString * ) name to : ( NSString * ) sub ;
- ( void ) _timedOut : ( NSTimer * ) timer ;
2012-11-23 12:45:09 +00:00
- ( void ) _update : ( NSMutableDictionary * ) info ;
2012-02-19 11:59:22 +00:00
@ end
@ implementation EcProcess
2013-08-22 18:11:15 +00:00
+ ( void ) atExit
{
if ( [ NSObject shouldCleanUp ] )
{
DESTROY ( EcProc ) ;
DESTROY ( EcProcConnection ) ;
DESTROY ( alarmDestination ) ;
DESTROY ( alertLogger ) ;
DESTROY ( auditLogger ) ;
DESTROY ( cmdActions ) ;
DESTROY ( cmdConf ) ;
DESTROY ( cmdDebugKnown ) ;
DESTROY ( cmdDebugModes ) ;
DESTROY ( cmdDebugName ) ;
DESTROY ( cmdDefs ) ;
DESTROY ( cmdFirst ) ;
DESTROY ( cmdInst ) ;
DESTROY ( cmdLast ) ;
DESTROY ( cmdLogMap ) ;
DESTROY ( cmdName ) ;
DESTROY ( cmdOperators ) ;
DESTROY ( cmdPTimer ) ;
DESTROY ( cmdServer ) ;
DESTROY ( cmdUser ) ;
DESTROY ( dataDir ) ;
DESTROY ( debugLogger ) ;
DESTROY ( ecLock ) ;
DESTROY ( errorLogger ) ;
DESTROY ( homeDir ) ;
DESTROY ( hostName ) ;
DESTROY ( noNetConfig ) ;
DESTROY ( replyBuffer ) ;
DESTROY ( servers ) ;
DESTROY ( started ) ;
DESTROY ( userDir ) ;
DESTROY ( warningLogger ) ;
}
}
2014-04-28 06:40:03 +00:00
+ ( NSMutableDictionary * ) ecInitialDefaults
{
2015-01-26 12:50:42 +00:00
NSProcessInfo * pi ;
2014-04-28 06:40:03 +00:00
id objects [ 2 ] ;
id keys [ 2 ] ;
NSString * prefix ;
2015-01-26 12:50:42 +00:00
pi = [ NSProcessInfo processInfo ] ;
objects [ 0 ] = [ pi processName ] ;
2014-04-28 06:40:03 +00:00
objects [ 1 ] = @ "." ;
prefix = EC_DEFAULTS _PREFIX ;
if ( nil = = prefix )
{
prefix = @ "" ;
}
keys [ 0 ] = [ prefix stringByAppendingString : @ "ProgramName" ] ;
keys [ 1 ] = [ prefix stringByAppendingString : @ "HomeDirectory" ] ;
return [ NSMutableDictionary dictionaryWithObjects : objects
forKeys : keys
count : 2 ] ;
}
2014-11-02 14:30:24 +00:00
+ ( void ) ecRegisterDefault : ( NSString * ) name
withTypeText : ( NSString * ) type
andHelpText : ( NSString * ) help
action : ( SEL ) cmd
{
[ EcDefaultRegistration registerDefault : name
withTypeText : type
andHelpText : help
action : cmd ] ;
}
2014-07-30 10:44:08 +00:00
+ ( void ) ecSetup
{
if ( nil ! = EcProc )
{
[ NSException raise : NSGenericException
format : @ "+ecSetup called when EcProcess is already set up" ] ;
}
[ [ self alloc ] init ] ;
}
2013-11-04 07:28:57 +00:00
- ( void ) _commandRemove
{
id connection = [ cmdServer connectionForProxy ] ;
if ( nil ! = connection )
{
[ connection setDelegate : nil ] ;
[ [ NSNotificationCenter defaultCenter ]
removeObserver : self
name : NSConnectionDidDieNotification
object : connection ] ;
[ connection invalidate ] ;
}
DESTROY ( cmdServer ) ;
}
- ( void ) _connectionRegistered
{
2014-01-16 09:36:34 +00:00
[ alarmDestination domanage : nil ] ;
2013-11-04 07:28:57 +00:00
}
2012-02-19 11:59:22 +00:00
static NSString * noFiles = @ "No log files to archive" ;
- ( id ) cmdConfig : ( NSString * ) key
{
return [ cmdDefs objectForKey : key ] ;
}
2012-02-19 14:42:50 +00:00
- ( NSString * ) cmdDataDirectory
{
if ( dataDir = = nil )
{
NSFileManager * mgr = [ NSFileManager defaultManager ] ;
NSString * str = cmdUserDir ( ) ;
BOOL flag ;
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 14:42:50 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
NSLog ( @ "Unable to create directory - %@" , str ) ;
return nil ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
NSLog ( @ "The path '%@' is not a directory" , str ) ;
return nil ;
}
str = [ str stringByAppendingPathComponent : @ "Data" ] ;
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 14:42:50 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
NSLog ( @ "Unable to create directory - %@" , str ) ;
return nil ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
NSLog ( @ "The path '%@' is not a directory" , str ) ;
return nil ;
}
if ( homeDir ! = nil )
{
str = [ str stringByAppendingPathComponent : homeDir ] ;
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 14:42:50 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
NSLog ( @ "Unable to create directory - %@" , str ) ;
return nil ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
NSLog ( @ "The path '%@' is not a directory" , str ) ;
return nil ;
}
}
ASSIGNCOPY ( dataDir , str ) ;
}
return dataDir ;
}
2012-02-19 11:59:22 +00:00
- ( NSUserDefaults * ) cmdDefaults
{
return cmdDefs ;
}
- ( void ) cmdDefaultsChanged : ( NSNotification * ) n
{
2012-11-23 12:45:09 +00:00
NSEnumerator * enumerator ;
2012-02-19 11:59:22 +00:00
NSDictionary * dict ;
NSString * mode ;
2012-11-23 12:45:09 +00:00
NSString * str ;
2013-04-30 06:57:37 +00:00
int i ;
2012-02-19 11:59:22 +00:00
2014-11-02 14:30:24 +00:00
[ EcDefaultRegistration defaultsChanged : cmdDefs ] ;
2012-11-23 12:45:09 +00:00
enumerator = [ cmdDebugKnown keyEnumerator ] ;
2012-02-19 11:59:22 +00:00
while ( nil ! = ( mode = [ enumerator nextObject ] ) )
{
NSString * key = [ @ "Debug-" stringByAppendingString : mode ] ;
if ( YES = = [ cmdDefs boolForKey : key ] )
{
[ cmdDebugModes addObject : mode ] ;
}
else
{
[ cmdDebugModes removeObject : mode ] ;
}
}
dict = [ cmdDefs dictionaryForKey : @ "WellKnownHostNames" ] ;
if ( nil ! = dict )
{
[ NSHost setWellKnownNames : dict ] ;
2012-10-05 14:40:19 +00:00
[ ecLock lock ] ;
2012-05-08 16:08:30 +00:00
ASSIGN ( hostName , [ [ NSHost currentHost ] wellKnownName ] ) ;
2012-10-05 14:40:19 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
}
2012-11-23 12:45:09 +00:00
if ( ( str = [ cmdDefs stringForKey : @ "CmdInterval" ] ) ! = nil )
{
[ self setCmdInterval : [ str floatValue ] ] ;
}
2014-11-01 09:18:02 +00:00
# ifndef __MINGW __
descriptorsMaximum = [ cmdDefs integerForKey : @ "DescriptorsMaximum" ] ;
# endif
2015-07-05 11:39:18 +00:00
memAllowed = ( uint64_t ) [ cmdDefs integerForKey : @ "MemoryAllowed" ] ;
2015-07-08 09:06:26 +00:00
# if SIZEOF_VOIDP = = 4
2015-07-05 07:37:18 +00:00
if ( memAllowed > 200000 )
2012-11-23 12:45:09 +00:00
{
2015-07-05 07:37:18 +00:00
memAllowed = 0 ;
2013-08-20 14:35:26 +00:00
}
2015-07-08 09:06:26 +00:00
# endif
2013-08-20 14:35:26 +00:00
2015-07-05 11:39:18 +00:00
memMaximum = ( uint64_t ) [ cmdDefs integerForKey : @ "MemoryMaximum" ] ;
2015-07-08 09:06:26 +00:00
# if SIZEOF_VOIDP = = 4
2015-07-03 19:23:42 +00:00
if ( memMaximum > 200000 )
2013-08-20 14:35:26 +00:00
{
memMaximum = 0 ; // Disabled
2012-11-23 12:45:09 +00:00
}
2015-07-08 09:06:26 +00:00
# endif
2012-11-23 12:45:09 +00:00
2013-04-30 08:13:45 +00:00
str = [ cmdDefs stringForKey : @ "CoreSize" ] ;
if ( nil = = str )
2013-04-30 06:57:37 +00:00
{
2015-07-03 19:23:42 +00:00
i = 2 * 1024 ; // 2 GB default
2013-04-30 08:13:45 +00:00
}
else
{
i = [ str intValue ] ;
if ( i < 0 )
{
i = -1 ; // unlimited
}
2013-04-30 06:57:37 +00:00
}
if ( i ! = coreSize )
{
struct rlimit rlim ;
rlim_t want ;
coreSize = i ;
2013-04-30 08:13:45 +00:00
if ( coreSize < 0 )
{
want = RLIM_INFINITY ;
}
else
{
want = i * 1024 * 1024 ;
}
if ( getrlimit ( RLIMIT_CORE , & rlim ) < 0 )
2013-04-30 06:57:37 +00:00
{
2013-04-30 08:13:45 +00:00
NSLog ( @ "Unable to get core file size limit: %d" , errno ) ;
}
else
{
if ( RLIM_INFINITY ! = rlim . rlim_max && rlim . rlim_max < want )
2013-04-30 06:57:37 +00:00
{
2013-09-20 09:59:21 +00:00
int maxMB = ( int ) ( rlim . rlim_max / ( 1024 * 1024 ) ) ;
if ( RLIM_INFINITY = = want )
{
NSLog ( @ "Hard limit for core file size (%dMB)"
@ " less than requested (unlimited); using %dMB." ,
maxMB , maxMB ) ;
}
else
{
NSLog ( @ "Hard limit for core file size (%dMB)"
@ " less than requested (%dMB); using %dMB." ,
maxMB , coreSize , maxMB ) ;
}
want = rlim . rlim_max ;
2013-04-30 06:57:37 +00:00
}
2013-09-20 09:59:21 +00:00
rlim . rlim_cur = want ;
if ( setrlimit ( RLIMIT_CORE , & rlim ) < 0 )
2013-04-30 06:57:37 +00:00
{
2013-09-20 09:59:21 +00:00
if ( coreSize > 0 )
{
NSLog ( @ "Unable to set core file size limit to %uMB"
@ ", errno: %d" , coreSize , errno ) ;
}
else if ( coreSize < 0 )
{
NSLog ( @ "Unable to set core file size unlimited"
@ ", errno: %d" , errno ) ;
}
else
2013-04-30 06:57:37 +00:00
{
2013-09-20 09:59:21 +00:00
NSLog ( @ "Unable to set core dumps disabled"
@ ", errno: %d" , errno ) ;
2013-04-30 06:57:37 +00:00
}
}
}
}
2012-11-23 12:45:09 +00:00
if ( servers ! = nil )
{
NSEnumerator * e ;
RemoteServer * server ;
e = [ servers objectEnumerator ] ;
while ( ( server = [ e nextObject ] ) )
{
[ server update ] ;
}
}
2012-02-19 11:59:22 +00:00
}
- ( NSString * ) cmdInstance
{
return cmdInst ;
}
- ( BOOL ) cmdIsDaemon
{
return cmdFlagDaemon ;
}
- ( BOOL ) cmdIsTesting
{
return cmdFlagTesting ;
}
- ( NSDate * ) cmdLastIP
{
2014-11-26 08:59:50 +00:00
if ( 0.0 = = lastIP )
{
return nil ;
}
return [ dateClass dateWithTimeIntervalSinceReferenceDate : lastIP ] ;
2012-02-19 11:59:22 +00:00
}
- ( NSDate * ) cmdLastOP
{
2014-11-26 08:59:50 +00:00
if ( 0.0 = = lastOP )
{
return nil ;
}
return [ dateClass dateWithTimeIntervalSinceReferenceDate : lastOP ] ;
2012-02-19 11:59:22 +00:00
}
- ( void ) cmdLogEnd : ( NSString * ) name
{
NSFileHandle * hdl ;
if ( [ name length ] = = 0 )
{
NSLog ( @ "Attempt to end log with empty filename" ) ;
return ;
}
name = [ name lastPathComponent ] ;
2015-05-14 13:47:30 +00:00
[ self ecDoLock ] ;
2012-02-19 11:59:22 +00:00
hdl = [ cmdLogMap objectForKey : name ] ;
if ( hdl ! = nil )
{
2014-04-28 09:00:24 +00:00
NSString * path ;
NSDictionary * attr ;
NSFileManager * mgr ;
/ *
* Ensure that all data is written to file .
2012-02-19 11:59:22 +00:00
* /
fflush ( stderr ) ;
2015-05-14 13:14:32 +00:00
NS_DURING
[ hdl closeFile ] ;
NS_HANDLER
2015-05-14 13:47:30 +00:00
NS_ENDHANDLER
2012-02-19 11:59:22 +00:00
2014-04-28 09:00:24 +00:00
/ *
* If the file is empty , remove it , otherwise move to archive directory .
2012-02-19 11:59:22 +00:00
* /
2014-04-28 09:00:24 +00:00
path = [ cmdLogsDir ( nil ) stringByAppendingPathComponent : name ] ;
mgr = [ NSFileManager defaultManager ] ;
attr = [ mgr fileAttributesAtPath : path traverseLink : NO ] ;
if ( [ [ attr objectForKey : NSFileSize ] intValue ] = = 0 )
{
[ mgr removeFileAtPath : path handler : nil ] ;
}
2012-02-19 11:59:22 +00:00
else
2014-04-28 09:00:24 +00:00
{
NSDate * when ;
NSString * where ;
when = [ NSDate date ] ;
where = [ when descriptionWithCalendarFormat : @ "%Y-%m-%d"
timeZone : nil locale : nil ] ;
if ( where ! = nil )
{
[ self _moveLog : name to : where ] ;
}
}
2012-02-19 11:59:22 +00:00
/ *
* Unregister filename .
* /
[ cmdLogMap removeObjectForKey : name ] ;
}
2015-05-14 13:47:30 +00:00
[ self ecUnLock ] ;
2012-02-19 11:59:22 +00:00
}
- ( NSFileHandle * ) cmdLogFile : ( NSString * ) name
{
NSFileHandle * hdl ;
NSString * status = nil ;
if ( [ name length ] = = 0 )
{
NSLog ( @ "Attempt to log with empty filename" ) ;
return nil ;
}
name = [ name lastPathComponent ] ;
2015-05-14 13:47:30 +00:00
[ self ecDoLock ] ;
2012-02-19 11:59:22 +00:00
hdl = [ cmdLogMap objectForKey : name ] ;
if ( hdl = = nil )
{
NSFileManager * mgr = [ NSFileManager defaultManager ] ;
NSString * path ;
path = [ cmdLogsDir ( nil ) stringByAppendingPathComponent : name ] ;
if ( [ mgr fileExistsAtPath : path ] = = YES )
{
NSDictionary * attr ;
NSDate * when ;
NSString * where ;
attr = [ mgr fileAttributesAtPath : path traverseLink : NO ] ;
when = [ attr objectForKey : NSFileModificationDate ] ;
where = [ when descriptionWithCalendarFormat : @ "%Y-%m-%d"
timeZone : nil locale : nil ] ;
if ( where ! = nil )
{
status = [ self _moveLog : name to : where ] ;
}
}
/ *
* Create the file if necessary , and open it for updating .
* /
if ( [ mgr isWritableFileAtPath : path ] = = NO
&& [ mgr createFileAtPath : path contents : nil attributes : nil ] = = NO )
{
NSLog ( @ "File '%@' is not writable and can't be created" , path ) ;
}
else
{
hdl = [ NSFileHandle fileHandleForUpdatingAtPath : path ] ;
if ( hdl = = nil )
{
if ( status ! = nil )
{
NSLog ( @ "%@" , status ) ;
}
NSLog ( @ "Unable to log to %@" , path ) ;
}
else
{
[ hdl seekToEndOfFile ] ;
}
}
if ( hdl = = nil )
{
2015-05-14 13:47:30 +00:00
[ self ecUnLock ] ;
2012-02-19 11:59:22 +00:00
return nil ;
}
/ *
* As a special case , if this is the default debug file
* we must set it up to write to stderr .
* /
2015-03-26 11:33:02 +00:00
if ( NO = = cmdKeepStderr && [ name isEqual : cmdDebugName ] = = YES )
2012-02-19 11:59:22 +00:00
{
int desc ;
desc = [ hdl fileDescriptor ] ;
if ( desc ! = 2 )
{
dup2 ( desc , 2 ) ;
2015-05-14 13:14:32 +00:00
NS_DURING
[ hdl closeFile ] ;
NS_HANDLER
2015-05-14 13:47:30 +00:00
NS_ENDHANDLER
2012-02-19 11:59:22 +00:00
hdl = [ NSFileHandle fileHandleWithStandardError ] ;
}
}
/ *
* Store the file handle in the dictionary for later use .
* /
[ cmdLogMap setObject : hdl forKey : name ] ;
if ( status ! = nil )
{
NSLog ( @ "%@" , status ) ;
}
}
2015-05-14 13:47:30 +00:00
[ hdl retain ] ;
[ self ecUnLock ] ;
return [ hdl autorelease ] ;
2012-02-19 11:59:22 +00:00
}
2012-02-20 11:01:04 +00:00
- ( void ) cmdLostConnectionToServer : ( NSString * ) name
{
return ;
}
- ( void ) cmdMadeConnectionToServer : ( NSString * ) name
{
return ;
}
2012-02-19 11:59:22 +00:00
- ( NSString * ) cmdName
{
return cmdName ;
}
2012-02-19 14:42:50 +00:00
- ( int ) cmdSignalled
2012-02-19 11:59:22 +00:00
{
2012-02-19 14:42:50 +00:00
return cmdSignalled ;
2012-02-19 11:59:22 +00:00
}
2014-09-16 18:57:07 +00:00
- ( void ) ecLoggersChanged : ( NSNotification * ) n
{
DESTROY ( alertLogger ) ;
DESTROY ( auditLogger ) ;
DESTROY ( debugLogger ) ;
DESTROY ( errorLogger ) ;
DESTROY ( warningLogger ) ;
}
2013-04-08 15:50:32 +00:00
- ( NSDate * ) ecStarted
2012-02-19 11:59:22 +00:00
{
2012-02-19 14:42:50 +00:00
return started ;
2012-02-19 11:59:22 +00:00
}
2013-04-09 11:31:01 +00:00
- ( oneway void ) alarm : ( in bycopy EcAlarm * ) event
{
[ alarmDestination alarm : event ] ;
}
- ( EcAlarm * ) alarmConfigurationFor : ( NSString * ) managedObject
specificProblem : ( NSString * ) specificProblem
additionalText : ( NSString * ) additionalText
critical : ( BOOL ) isCritical
{
EcAlarmSeverity severity ;
NSString * action ;
EcAlarm * a ;
if ( YES = = isCritical )
{
severity = EcAlarmSeverityCritical ;
}
else
{
severity = EcAlarmSeverityMajor ;
}
action = @ "Check/correct configuration" ; // FIXME . . . localize
a = [ EcAlarm alarmForManagedObject : managedObject
at : nil
withEventType : EcAlarmEventTypeProcessingError
probableCause : EcAlarmConfigurationOrCustomizationError
specificProblem : specificProblem
perceivedSeverity : severity
proposedRepairAction : action
additionalText : additionalText ] ;
[ self alarm : a ] ;
return a ;
}
2012-11-30 14:26:23 +00:00
- ( NSArray * ) alarms
{
return [ alarmDestination alarms ] ;
}
2013-04-09 11:31:01 +00:00
- ( void ) clearConfigurationFor : ( NSString * ) managedObject
specificProblem : ( NSString * ) specificProblem
additionalText : ( NSString * ) additionalText
2012-02-19 11:59:22 +00:00
{
2013-04-09 11:31:01 +00:00
EcAlarm * a ;
a = [ EcAlarm alarmForManagedObject : managedObject
at : nil
withEventType : EcAlarmEventTypeProcessingError
probableCause : EcAlarmConfigurationOrCustomizationError
specificProblem : specificProblem
perceivedSeverity : EcAlarmSeverityCleared
proposedRepairAction : nil
additionalText : additionalText ] ;
[ self alarm : a ] ;
2012-02-19 11:59:22 +00:00
}
- ( oneway void ) domanage : ( in bycopy NSString * ) managedObject
{
[ alarmDestination domanage : managedObject ] ;
}
- ( oneway void ) unmanage : ( in bycopy NSString * ) managedObject
{
[ alarmDestination unmanage : managedObject ] ;
}
2015-01-26 12:50:42 +00:00
- ( int ) processIdentifier
{
static int pi = 0 ;
if ( 0 = = pi )
{
pi = [ [ NSProcessInfo processInfo ] processIdentifier ] ;
}
return pi ;
}
2012-02-19 11:59:22 +00:00
- ( void ) setCmdInterval : ( NSTimeInterval ) interval
{
if ( interval > 60.0 )
{
2012-06-12 07:46:29 +00:00
NSLog ( @ "Ignored attempt to set timer interval to %g ... using 60.0" , interval ) ;
2012-02-19 11:59:22 +00:00
interval = 60.0 ;
}
if ( interval < 0.001 )
{
NSLog ( @ "Ignored attempt to set timer interval to %g ... using 10.0" , interval ) ;
interval = 10.0 ;
}
if ( interval ! = cmdTimInterval )
{
cmdTimInterval = interval ;
[ self triggerCmdTimeout ] ;
}
}
2012-03-09 09:22:09 +00:00
- ( NSString * ) ecCopyright
2012-02-19 11:59:22 +00:00
{
return @ "" ;
}
2012-05-09 13:18:32 +00:00
- ( void ) ecDoLock
{
[ ecLock lock ] ;
}
- ( void ) ecUnLock
{
[ ecLock unlock ] ;
}
2012-02-19 11:59:22 +00:00
+ ( void ) initialize
{
2012-03-09 09:22:09 +00:00
if ( nil = = ecLock )
2012-02-19 11:59:22 +00:00
{
2012-03-09 09:22:09 +00:00
ecLock = [ NSRecursiveLock new ] ;
2012-02-19 11:59:22 +00:00
dateClass = [ NSDate class ] ;
cDateClass = [ NSCalendarDate class ] ;
stringClass = [ NSString class ] ;
cmdLogMap = [ [ NSMutableDictionary alloc ] initWithCapacity : 4 ] ;
cmdDebugModes = [ [ NSMutableSet alloc ] initWithCapacity : 4 ] ;
cmdDebugKnown = [ [ NSMutableDictionary alloc ] initWithCapacity : 4 ] ;
[ cmdDebugKnown setObject : @ "Mode for distributed object connections"
forKey : cmdConnectDbg ] ;
[ cmdDebugKnown setObject : @ "Standard mode for basic debug information"
forKey : cmdDefaultDbg ] ;
[ cmdDebugKnown setObject : @ "Detailed but general purpose debugging"
forKey : cmdDetailDbg ] ;
[ cmdDebugModes addObject : cmdDefaultDbg ] ;
2014-11-02 14:30:24 +00:00
[ self ecRegisterDefault : @ "Memory"
withTypeText : @ "YES/NO"
andHelpText : @ "Enable memory allocation checks"
action : @ selector ( _defMemory : ) ] ;
[ self ecRegisterDefault : @ "Release"
withTypeText : @ "YES/NO"
andHelpText : @ "Turn on double release checks (debug)"
action : @ selector ( _defRelease : ) ] ;
[ self ecRegisterDefault : @ "Testing"
withTypeText : @ "YES/NO"
andHelpText : @ "Run in test mode (if supported)"
action : @ selector ( _defTesting : ) ] ;
2012-02-19 11:59:22 +00:00
/ *
* Set the timeouts for the default connection so that
* they will be inherited by other connections .
* A two minute timeout is long enough for almost all
* circumstances .
* /
[ [ NSConnection defaultConnection ] setRequestTimeout : 120.0 ] ;
[ [ NSConnection defaultConnection ] setReplyTimeout : 120.0 ] ;
2013-08-22 18:11:15 +00:00
[ self registerAtExit ] ;
2012-02-19 11:59:22 +00:00
}
}
- ( void ) addServerToList : ( NSString * ) serverName
{
[ self addServerToList : serverName for : nil ] ;
}
- ( void ) addServerToList : ( NSString * ) serverName for : ( id ) anObject
{
RemoteServer * remote ;
if ( ( serverName = = nil )
|| ( [ serverName isKindOfClass : [ NSString class ] ] = = NO ) )
{
NSLog ( @ "Warning: invalid string passed to addServerToList:for:" ) ;
return ;
}
if ( anObject = = nil )
{
anObject = self ;
}
if ( servers = = nil )
{
servers = [ [ NSMutableDictionary alloc ] initWithCapacity : 2 ] ;
}
remote = [ [ RemoteServer alloc ] initWithDefaultName : serverName
delegate : anObject ] ;
[ servers setObject : remote forKey : serverName ] ;
[ remote release ] ;
}
- ( void ) removeServerFromList : ( NSString * ) serverName
{
if ( ( serverName = = nil )
|| ( [ serverName isKindOfClass : [ NSString class ] ] = = NO ) )
{
NSLog ( @ "Warning: invalid array passed to removeServerFromList:" ) ;
return ;
}
[ servers removeObjectForKey : serverName ] ;
}
- ( id ) cmdConnectionBecameInvalid : ( NSNotification * ) notification
{
id connection ;
connection = [ notification object ] ;
2013-11-04 07:28:57 +00:00
[ connection setDelegate : nil ] ;
2012-02-19 11:59:22 +00:00
[ [ NSNotificationCenter defaultCenter ]
removeObserver : self
name : NSConnectionDidDieNotification
object : connection ] ;
if ( cmdServer ! = nil && connection = = [ cmdServer connectionForProxy ] )
{
[ alarmDestination setDestination : nil ] ;
DESTROY ( cmdServer ) ;
NSLog ( @ "lost connection 0x%p to command server\n" , connection ) ;
/ *
* Cause timeout to go off really soon so we will try to
* re - establish the link to the server .
* /
2015-05-14 13:47:30 +00:00
[ self triggerCmdTimeout ] ;
2012-02-19 11:59:22 +00:00
}
else
{
2013-11-04 07:28:57 +00:00
NSLog ( @ "unknown connection sent invalidation\n" ) ;
2012-02-19 11:59:22 +00:00
}
return self ;
}
2012-05-25 19:10:27 +00:00
- ( void ) cmdAlert : ( NSString * ) fmt arguments : ( va_list ) args
2012-02-19 11:59:22 +00:00
{
if ( nil = = alertLogger )
{
alertLogger = [ [ EcLogger loggerForType : LT_ALERT ] retain ] ;
}
2012-05-25 19:10:27 +00:00
[ alertLogger log : fmt arguments : args ] ;
}
- ( void ) cmdAlert : ( NSString * ) fmt , . . .
{
va_list ap ;
2012-02-19 11:59:22 +00:00
va_start ( ap , fmt ) ;
2012-05-25 19:10:27 +00:00
[ self cmdAlert : fmt arguments : ap ] ;
2012-02-19 11:59:22 +00:00
va_end ( ap ) ;
}
- ( NSString * ) cmdArchive : ( NSString * ) subdir
{
NSString * status = @ "" ;
if ( [ cmdLogMap count ] = = 0 )
{
status = noFiles ;
}
else
{
2015-05-14 13:47:30 +00:00
NSEnumerator * enumerator ;
2012-02-19 11:59:22 +00:00
NSString * name ;
2015-05-14 13:47:30 +00:00
[ self ecDoLock ] ;
enumerator = [ [ cmdLogMap allKeys ] objectEnumerator ] ;
[ self ecUnLock ] ;
2012-02-19 11:59:22 +00:00
if ( subdir = = nil )
{
NSCalendarDate * when = [ NSCalendarDate date ] ;
int y , m , d ;
y = [ when yearOfCommonEra ] ;
m = [ when monthOfYear ] ;
d = [ when dayOfMonth ] ;
subdir = [ stringClass stringWithFormat : @ "%04d-%02d-%02d" , y , m , d ] ;
}
while ( ( name = [ enumerator nextObject ] ) ! = nil )
{
NSString * s ;
s = [ self _moveLog : name to : subdir ] ;
if ( [ status length ] > 0 )
status = [ status stringByAppendingString : @ "\n" ] ;
status = [ status stringByAppendingString : s ] ;
[ self cmdLogEnd : name ] ;
if ( cmdIsQuitting = = NO )
{
[ self cmdLogFile : name ] ;
}
}
}
return status ;
}
2012-05-25 19:10:27 +00:00
- ( void ) cmdAudit : ( NSString * ) fmt arguments : ( va_list ) args
2012-02-19 11:59:22 +00:00
{
if ( nil = = auditLogger )
{
auditLogger = [ [ EcLogger loggerForType : LT_AUDIT ] retain ] ;
}
2012-05-25 19:10:27 +00:00
[ auditLogger log : fmt arguments : args ] ;
}
- ( void ) cmdAudit : ( NSString * ) fmt , . . .
{
va_list ap ;
2012-02-19 11:59:22 +00:00
va_start ( ap , fmt ) ;
2012-05-25 19:10:27 +00:00
[ self cmdAudit : fmt arguments : ap ] ;
2012-02-19 11:59:22 +00:00
va_end ( ap ) ;
}
2012-05-25 19:10:27 +00:00
- ( void ) cmdDbg : ( NSString * ) type msg : ( NSString * ) fmt arguments : ( va_list ) args
2012-02-19 11:59:22 +00:00
{
if ( nil ! = [ cmdDebugModes member : type ] )
{
if ( nil = = debugLogger )
{
debugLogger = [ [ EcLogger loggerForType : LT_DEBUG ] retain ] ;
}
2012-05-25 19:10:27 +00:00
[ debugLogger log : fmt arguments : args ] ;
2012-02-19 11:59:22 +00:00
}
}
2012-05-25 19:10:27 +00:00
- ( void ) cmdDbg : ( NSString * ) type msg : ( NSString * ) fmt , . . .
{
va_list ap ;
va_start ( ap , fmt ) ;
[ self cmdDbg : type msg : fmt arguments : ap ] ;
va_end ( ap ) ;
}
- ( void ) cmdDebug : ( NSString * ) fmt arguments : ( va_list ) args
2012-02-19 11:59:22 +00:00
{
if ( nil ! = [ cmdDebugModes member : cmdDefaultDbg ] )
{
if ( nil = = debugLogger )
{
debugLogger = [ [ EcLogger loggerForType : LT_DEBUG ] retain ] ;
}
2012-05-25 19:10:27 +00:00
[ debugLogger log : fmt arguments : args ] ;
2012-02-19 11:59:22 +00:00
}
}
2012-05-25 19:10:27 +00:00
- ( void ) cmdDebug : ( NSString * ) fmt , . . .
2012-02-19 11:59:22 +00:00
{
va_list ap ;
2012-05-25 19:10:27 +00:00
va_start ( ap , fmt ) ;
[ self cmdDebug : fmt arguments : ap ] ;
va_end ( ap ) ;
}
- ( void ) cmdError : ( NSString * ) fmt arguments : ( va_list ) args
{
2012-02-19 11:59:22 +00:00
if ( nil = = errorLogger )
{
errorLogger = [ [ EcLogger loggerForType : LT_ERROR ] retain ] ;
}
2012-05-25 19:10:27 +00:00
[ errorLogger log : fmt arguments : args ] ;
}
- ( void ) cmdError : ( NSString * ) fmt , . . .
{
va_list ap ;
2012-02-19 11:59:22 +00:00
va_start ( ap , fmt ) ;
2012-05-25 19:10:27 +00:00
[ self cmdError : fmt arguments : ap ] ;
2012-02-19 11:59:22 +00:00
va_end ( ap ) ;
}
- ( void ) cmdFlushLogs
{
[ alertLogger flush ] ;
[ auditLogger flush ] ;
[ debugLogger flush ] ;
[ errorLogger flush ] ;
[ warningLogger flush ] ;
}
- ( NSTimeInterval ) cmdInterval
{
return cmdTimInterval ;
}
- ( BOOL ) cmdIsClient
{
return YES ;
}
- ( void ) log : ( NSString * ) message type : ( EcLogType ) t
{
switch ( t )
{
case LT_DEBUG :
[ self cmdDebug : @ "%@" , message ] ;
break ;
case LT_WARNING :
[ self cmdWarn : @ "%@" , message ] ;
break ;
case LT_ERROR :
[ self cmdError : @ "%@" , message ] ;
break ;
case LT_ALERT :
[ self cmdAlert : @ "%@" , message ] ;
break ;
case LT_AUDIT :
[ self cmdAudit : @ "%@" , message ] ;
break ;
default :
[ self cmdError : @ "%@" , message ] ;
break ;
}
}
- ( NSMutableDictionary * ) cmdOperator : ( NSString * ) name password : ( NSString * ) pass
{
NSMutableDictionary * d = ( NSMutableDictionary * ) cmdOperators ;
if ( d = = nil || [ d isKindOfClass : [ NSDictionary class ] ] = = NO )
{
return nil ;
}
d = [ d objectForKey : name ] ;
if ( d = = nil || [ d isKindOfClass : [ NSDictionary class ] ] = = NO )
{
return nil ;
}
d = [ d mutableCopy ] ;
if ( pass ! = nil && [ [ d objectForKey : @ "Password" ] isEqual : pass ] = = YES )
{
[ d setObject : @ "yes" forKey : @ "Password" ] ;
}
else
{
[ d setObject : @ "no" forKey : @ "Password" ] ;
}
return AUTORELEASE ( d ) ;
}
- ( id ) cmdNewServer
{
static BOOL connecting = NO ;
if ( NO = = connecting )
{
/ *
* Use the ' cmdLast ' variable to ensure that we don ' t try to
* check memory usage or connect to the command server more
* than once every 10 sec .
* /
if ( cmdLast = = nil || [ cmdLast timeIntervalSinceNow ] < -10.0 )
{
2014-03-25 18:44:47 +00:00
int mayRetry ;
2012-02-19 11:59:22 +00:00
connecting = YES ;
2014-03-25 18:44:47 +00:00
/ * The first time we try to connect to the Command server
* ( on startup ) we should retry for several seconds in case
* the whole system is coming up and the Command server has
* not yet been started .
* /
mayRetry = ( nil = = cmdLast ? 10 : 0 ) ;
2012-02-19 11:59:22 +00:00
ASSIGN ( cmdLast , [ dateClass date ] ) ;
if ( cmdFirst = = nil )
{
ASSIGN ( cmdFirst , cmdLast ) ;
}
if ( cmdServer = = nil && YES = = [ self cmdIsClient ] )
{
NSString * name = nil ;
NSString * host = nil ;
id proxy ;
NS_DURING
{
2014-03-25 18:44:47 +00:00
NSSocketPortNameServer * ns ;
2012-03-09 09:22:09 +00:00
host = ecCommandHost ( ) ;
name = ecCommandName ( ) ;
2012-02-19 11:59:22 +00:00
2014-03-25 18:44:47 +00:00
ns = [ NSSocketPortNameServer sharedInstance ] ;
2012-02-19 11:59:22 +00:00
proxy = [ NSConnection
rootProxyForConnectionWithRegisteredName : name
host : host
2014-03-25 18:44:47 +00:00
usingNameServer : ns ] ;
while ( nil = = proxy && mayRetry - - > 0 )
{
[ NSThread sleepForTimeInterval : 1.0 ] ;
proxy = [ NSConnection
rootProxyForConnectionWithRegisteredName : name
host : host
usingNameServer : ns ] ;
}
2012-02-19 11:59:22 +00:00
}
NS_HANDLER
{
proxy = nil ;
NSLog ( @ "Exception connecting to Command server %@ on %@): %@" ,
name , host , localException ) ;
}
NS_ENDHANDLER
if ( proxy ! = nil )
{
NSMutableDictionary * r = nil ;
[ proxy setProtocolForProxy : @ protocol ( Command ) ] ;
NS_DURING
{
NSData * d ;
d = [ proxy registerClient : self
name : cmdLogName ( )
transient : cmdIsTransient ] ;
r = [ NSPropertyListSerialization
propertyListWithData : d
options : NSPropertyListMutableContainers
format : 0
error : 0 ] ;
}
NS_HANDLER
{
r = [ NSMutableDictionary dictionaryWithCapacity : 1 ] ;
[ r setObject : [ localException reason ]
forKey : @ "rejected" ] ;
NSLog ( @ "Caught exception registering with Command: %@" ,
localException ) ;
}
NS_ENDHANDLER
/ * We could be rejected or told to back off ,
* otherwise we continue as normal .
* /
if ( r ! = nil && [ r objectForKey : @ "rejected" ] ! = nil )
{
NSLog ( @ "Rejected by Command - %@" ,
[ r objectForKey : @ "rejected" ] ) ;
2013-08-20 14:35:26 +00:00
cmdIsQuitting = YES ;
2012-02-19 11:59:22 +00:00
[ self cmdQuit : 0 ] ; / * Rejected by server . * /
}
else if ( nil = = r || nil = = [ r objectForKey : @ "back-off" ] )
{
NSConnection * connection ;
cmdServer = [ proxy retain ] ;
connection = [ cmdServer connectionForProxy ] ;
[ connection enableMultipleThreads ] ;
if ( nil = = alarmDestination )
{
alarmDestination = [ EcAlarmDestination new ] ;
}
[ alarmDestination setDestination : cmdServer ] ;
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
selector : @ selector ( cmdConnectionBecameInvalid : )
name : NSConnectionDidDieNotification
object : connection ] ;
2012-11-23 12:45:09 +00:00
[ self _update : r ] ;
2013-11-04 07:28:57 +00:00
/ * If we just connected to the command server ,
* and we have a registered connection , then we
* can tell it that any alarm for failure to
* register must be cleared .
* /
if ( nil ! = cmdServer && [ EcProcConnection isValid ] )
{
[ self _connectionRegistered ] ;
}
2012-02-19 11:59:22 +00:00
}
}
}
connecting = NO ;
}
else if ( cmdServer = = nil && YES = = [ self cmdIsClient ] )
{
NSLog ( @ "Unable to connect to Command server ... not retry time yet" ) ;
}
}
return cmdServer ;
}
- ( void ) cmdUnregister
{
if ( nil ! = cmdServer )
{
NS_DURING
{
[ cmdServer unregisterByObject : self ] ;
}
NS_HANDLER
{
2013-11-04 07:28:57 +00:00
[ self _commandRemove ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "Caught exception unregistering from Command: %@" ,
localException ) ;
}
NS_ENDHANDLER
2013-11-04 07:28:57 +00:00
[ self _commandRemove ] ;
2012-02-19 11:59:22 +00:00
}
}
2012-05-25 19:10:27 +00:00
- ( void ) cmdWarn : ( NSString * ) fmt arguments : ( va_list ) args
2012-02-19 11:59:22 +00:00
{
if ( nil = = warningLogger )
{
warningLogger = [ [ EcLogger loggerForType : LT_WARNING ] retain ] ;
}
2012-05-25 19:10:27 +00:00
[ warningLogger log : fmt arguments : args ] ;
}
- ( void ) cmdWarn : ( NSString * ) fmt , . . .
{
va_list ap ;
2012-02-19 11:59:22 +00:00
va_start ( ap , fmt ) ;
2012-05-25 19:10:27 +00:00
[ self cmdWarn : fmt arguments : ap ] ;
2012-02-19 11:59:22 +00:00
va_end ( ap ) ;
}
2012-03-09 09:22:09 +00:00
- ( void ) ecNewDay : ( NSCalendarDate * ) when
2012-02-19 11:59:22 +00:00
{
NSString * sub ;
/ * New day . . . archive debug / log files into a subdirectory based on
* the current date . This is yesterday ' s debug , so we use yesterday .
* /
sub = [ [ when dateByAddingYears : 0 months : 0 days : -1 hours : 0 minutes : 0
seconds : 0 ] descriptionWithCalendarFormat : @ "%Y-%m-%d" ] ;
NSLog ( @ "%@" , [ self cmdArchive : sub ] ) ;
}
2012-03-09 09:22:09 +00:00
- ( void ) ecNewHour : ( NSCalendarDate * ) when
2012-02-19 11:59:22 +00:00
{
return ;
}
2012-03-09 09:22:09 +00:00
- ( void ) ecNewMinute : ( NSCalendarDate * ) when
2012-02-19 11:59:22 +00:00
{
2014-11-01 09:18:02 +00:00
# ifndef __MINGW __
if ( NO = = cmdIsQuitting )
{
NSString * shutdown = nil ;
int p [ 2 ] ;
if ( pipe ( p ) = = 0 )
{
if ( 0 = = reservedPipe [ 1 ] )
{
reservedPipe [ 0 ] = p [ 0 ] ;
reservedPipe [ 1 ] = p [ 1 ] ;
}
else
{
close ( p [ 0 ] ) ;
close ( p [ 1 ] ) ;
}
if ( descriptorsMaximum > 0 )
{
if ( p [ 0 ] > descriptorsMaximum || p [ 1 ] > descriptorsMaximum )
{
shutdown = [ NSString stringWithFormat :
@ "Open file descriptor limit (%lu) exceeded" ,
( unsigned long ) descriptorsMaximum ] ;
}
}
}
else
{
shutdown = @ "Process ran out of file descriptors" ;
}
if ( nil ! = shutdown )
{
/ * We hope that closing two reserved file descriptors will allow
* us to shut down gracefully and restart .
* /
if ( reservedPipe [ 1 ] > 0 )
{
close ( reservedPipe [ 0 ] ) ; reservedPipe [ 0 ] = 0 ;
close ( reservedPipe [ 1 ] ) ; reservedPipe [ 1 ] = 0 ;
}
[ self cmdError : @ "%@" , shutdown ] ;
cmdIsQuitting = YES ;
[ self cmdQuit : -1 ] ;
return ;
}
}
# endif
2014-06-20 16:32:12 +00:00
/ * We want to be sure we work with reasonably up to date information .
* /
[ NSHost flushHostCache ] ;
2015-07-08 09:06:26 +00:00
[ self _memCheck ] ;
2012-02-19 11:59:22 +00:00
}
2012-03-09 09:22:09 +00:00
- ( void ) ecHadIP : ( NSDate * ) when
2012-02-19 11:59:22 +00:00
{
2014-11-26 08:59:50 +00:00
if ( nil = = when )
2012-02-19 11:59:22 +00:00
{
2014-11-26 08:59:50 +00:00
lastIP = [ dateClass timeIntervalSinceReferenceDate ] ;
}
else
{
lastIP = [ when timeIntervalSinceReferenceDate ] ;
2012-02-19 11:59:22 +00:00
}
}
2012-03-09 09:22:09 +00:00
- ( void ) ecHadOP : ( NSDate * ) when
2012-02-19 11:59:22 +00:00
{
2014-11-26 08:59:50 +00:00
if ( nil = = when )
{
lastOP = [ dateClass timeIntervalSinceReferenceDate ] ;
}
else
2012-02-19 11:59:22 +00:00
{
2014-11-26 08:59:50 +00:00
lastOP = [ when timeIntervalSinceReferenceDate ] ;
2012-02-19 11:59:22 +00:00
}
}
2012-03-09 09:22:09 +00:00
- ( NSUInteger ) ecNotLeaked
2012-02-19 11:59:22 +00:00
{
return 0 ;
}
2012-03-09 09:22:09 +00:00
- ( int ) ecRun
2012-02-19 11:59:22 +00:00
{
2012-12-06 08:08:39 +00:00
NSAutoreleasePool * arp ;
NSConnection * c ;
NSRunLoop * loop ;
2012-02-19 11:59:22 +00:00
2012-12-06 08:08:39 +00:00
arp = [ NSAutoreleasePool new ] ;
2012-02-19 11:59:22 +00:00
if ( YES = = cmdIsTransient )
{
2014-05-16 22:13:43 +00:00
[ self cmdWarn : @ "Attempted to run transient process." ] ;
2012-08-02 11:30:15 +00:00
[ self cmdFlushLogs ] ;
2012-12-06 08:08:39 +00:00
[ arp release ] ;
2012-02-19 11:59:22 +00:00
return 1 ;
}
2012-10-12 17:20:45 +00:00
NSAssert ( nil = = EcProcConnection , NSGenericException ) ;
2012-02-19 11:59:22 +00:00
c = [ [ NSConnection alloc ] initWithReceivePort : ( NSPort * ) [ NSSocketPort port ]
2012-10-12 17:20:45 +00:00
sendPort : nil ] ;
2012-02-19 11:59:22 +00:00
[ c setRootObject : self ] ;
if ( [ c registerName : [ self cmdName ]
withNameServer : [ NSSocketPortNameServer sharedInstance ] ] = = NO )
{
2013-11-04 07:28:57 +00:00
EcAlarm * a ;
2012-02-19 11:59:22 +00:00
DESTROY ( c ) ;
2013-11-04 07:28:57 +00:00
NSLog ( @ "Unable to register with name server. Perhaps a copy of this process is already running (or is hung or blocked waiting for a database query etc), or perhaps an old version was killed and is still registered. Check the state of any running process and and check the process registration with gdomap." ) ;
a = [ EcAlarm alarmForManagedObject : nil
at : nil
withEventType : EcAlarmEventTypeProcessingError
probableCause : EcAlarmSoftwareProgramAbnormallyTerminated
2013-12-09 21:55:18 +00:00
specificProblem : @ "Unable to register"
2013-11-04 07:28:57 +00:00
perceivedSeverity : EcAlarmSeverityMajor
proposedRepairAction :
_ ( @ "Check for running copy of process and/or registration in gdomap." )
additionalText : _ ( @ "Process probably already running (possibly hung/delayed) or problem in name registration with distributed objects system (gdomap)" ) ] ;
[ self alarm : a ] ;
[ alarmDestination shutdown ] ;
cmdIsQuitting = YES ;
2012-08-02 11:30:15 +00:00
[ self cmdFlushLogs ] ;
2012-12-06 08:08:39 +00:00
[ arp release ] ;
2012-02-19 11:59:22 +00:00
return 2 ;
}
2014-09-04 21:24:19 +00:00
else
{
EcAlarm * a ;
a = [ EcAlarm alarmForManagedObject : nil
at : nil
withEventType : EcAlarmEventTypeProcessingError
probableCause : EcAlarmSoftwareProgramAbnormallyTerminated
specificProblem : @ "Unable to register"
perceivedSeverity : EcAlarmSeverityCleared
proposedRepairAction : nil
additionalText : nil ] ;
[ self alarm : a ] ;
}
2012-02-19 11:59:22 +00:00
[ c setDelegate : self ] ;
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
2013-03-18 07:42:41 +00:00
selector : @ selector ( cmdConnectionBecameInvalid : )
2012-02-19 11:59:22 +00:00
name : NSConnectionDidDieNotification
object : c ] ;
2012-12-06 08:08:39 +00:00
EcProcConnection = c ;
2012-02-19 11:59:22 +00:00
2013-11-04 07:28:57 +00:00
[ self _connectionRegistered ] ;
2012-02-19 11:59:22 +00:00
[ self cmdAudit : @ "Started `%@'" , [ self cmdName ] ] ;
2014-05-16 16:39:05 +00:00
[ self cmdFlushLogs ] ;
2014-05-16 22:13:43 +00:00
cmdIsRunning = YES ;
2012-02-19 11:59:22 +00:00
2012-12-06 08:08:39 +00:00
loop = [ NSRunLoop currentRunLoop ] ;
while ( YES = = [ EcProcConnection isValid ] )
2012-02-19 11:59:22 +00:00
{
NS_DURING
{
2012-12-06 08:08:39 +00:00
NSDate * d = [ loop limitDateForMode : NSDefaultRunLoopMode ] ;
2012-12-06 08:10:57 +00:00
if ( 0 = = cmdSignalled )
{
[ loop acceptInputForMode : NSDefaultRunLoopMode beforeDate : d ] ;
}
2012-12-06 08:08:39 +00:00
if ( 0 ! = cmdSignalled )
2012-02-19 14:42:50 +00:00
{
2012-12-06 08:08:39 +00:00
int sig = cmdSignalled ;
cmdSignalled = 0 ;
2013-08-20 14:35:26 +00:00
cmdIsQuitting = YES ;
2012-12-06 08:08:39 +00:00
[ self cmdQuit : sig ] ;
2012-02-19 14:42:50 +00:00
}
2012-02-19 11:59:22 +00:00
}
NS_HANDLER
{
[ self cmdAlert : @ "Problem running server: %@" , localException ] ;
}
NS_ENDHANDLER ;
2012-12-06 15:41:36 +00:00
[ arp emptyPool ] ;
2012-02-19 11:59:22 +00:00
}
2012-12-06 08:08:39 +00:00
[ arp release ] ;
2012-02-19 11:59:22 +00:00
/ * finish server * /
2013-08-20 14:35:26 +00:00
cmdIsQuitting = YES ;
2012-02-19 11:59:22 +00:00
[ self cmdQuit : 0 ] ;
2014-05-16 22:13:43 +00:00
cmdIsRunning = NO ;
2012-10-12 17:20:45 +00:00
DESTROY ( EcProcConnection ) ;
2012-02-19 11:59:22 +00:00
return 0 ;
}
2013-03-18 07:42:41 +00:00
- ( void ) ecTestLog : ( NSString * ) fmt arguments : ( va_list ) args
{
if ( YES = = cmdFlagTesting )
{
NSLogv ( fmt , args ) ;
}
}
- ( void ) ecTestLog : ( NSString * ) fmt , . . .
{
if ( YES = = cmdFlagTesting )
{
va_list ap ;
va_start ( ap , fmt ) ;
[ self ecTestLog : fmt arguments : ap ] ;
va_end ( ap ) ;
}
}
2013-07-12 19:05:52 +00:00
- ( NSString * ) ecUserDirectory
{
return cmdUserDir ( ) ;
}
2012-02-19 11:59:22 +00:00
- ( void ) setCmdDebug : ( NSString * ) mode withDescription : ( NSString * ) desc
{
[ cmdDebugKnown setObject : desc forKey : mode ] ;
}
- ( void ) setCmdTimeout : ( SEL ) sel
{
cmdTimSelector = sel ;
[ self triggerCmdTimeout ] ;
}
- ( void ) triggerCmdTimeout
{
2015-05-14 13:47:30 +00:00
if ( NO = = [ NSThread isMainThread ] )
{
[ self performSelectorOnMainThread : _cmd
withObject : nil
waitUntilDone : NO ] ;
return ;
}
2012-02-19 11:59:22 +00:00
if ( cmdPTimer ! = nil )
{
/ *
* If the timer is due to go off soon - don ' t reset it -
* continually resetting could lead to it never firing .
* /
if ( [ [ cmdPTimer fireDate ] timeIntervalSinceNow ] <= 0.01 )
{
return ;
}
[ cmdPTimer invalidate ] ;
cmdPTimer = nil ;
}
cmdPTimer = [ NSTimer scheduledTimerWithTimeInterval : 0.001
target : self
selector : @ selector ( _timedOut : )
userInfo : nil
repeats : NO ] ;
}
- ( BOOL ) cmdDebugMode : ( NSString * ) mode
{
if ( [ cmdDebugModes member : mode ] = = nil )
return NO ;
return YES ;
}
- ( void ) cmdDebugMode : ( NSString * ) mode active : ( BOOL ) flag
{
if ( ( mode = findMode ( cmdDebugKnown , mode ) ) ! = nil )
{
if ( flag = = YES && [ cmdDebugModes member : mode ] = = nil )
{
[ cmdDebugModes addObject : mode ] ;
}
if ( flag = = NO && [ cmdDebugModes member : mode ] ! = nil )
{
[ cmdDebugModes removeObject : mode ] ;
}
}
}
2015-01-26 12:50:42 +00:00
- ( oneway void ) cmdGnip : ( id < CmdPing > ) from
sequence : ( unsigned ) num
extra : ( in bycopy NSData * ) data
2012-02-19 11:59:22 +00:00
{
[ self cmdDbg : cmdConnectDbg msg : @ "cmdGnip: %lx sequence: %u extra: %lx" ,
( unsigned long ) from , num , ( unsigned long ) data ] ;
}
- ( BOOL ) cmdIsConnected
{
return cmdServer ! = nil ;
}
- ( BOOL ) cmdMatch : ( NSString * ) val toKey : ( NSString * ) key
{
unsigned int len = [ val length ] ;
if ( len = = 0 )
{
return NO ;
}
if ( len > [ key length ] )
{
return NO ;
}
if ( [ key compare : val
options : NSCaseInsensitiveSearch | NSLiteralSearch
range : NSMakeRange ( 0 , len ) ] ! = NSOrderedSame )
{
return NO ;
}
return YES ;
}
2012-07-05 13:15:27 +00:00
- ( void ) cmdMesgCache
{
NSEnumerator * enumerator ;
NSString * name ;
/ * The cmdActions set contains the names of all the commands this
* instance will accept from the Command server . These are methods
* taking an array of strings as an argument and returning a string
* as their result . All have names of the form cmdMesgXXX : where
* XXX is the ( lowercase ) command .
* /
[ ecLock lock ] ;
if ( nil = = cmdActions )
{
cmdActions = [ NSMutableSet new ] ;
}
[ cmdActions removeAllObjects ] ;
enumerator = [ GSObjCMethodNames ( self , YES ) objectEnumerator ] ;
while ( nil ! = ( name = [ enumerator nextObject ] ) )
{
NSRange r = [ name rangeOfString : @ ":" ] ;
if ( [ name hasPrefix : @ "cmdMesg" ] && 1 = = r . length && r . location > 7 )
{
name = [ name substringWithRange : NSMakeRange ( 7 , r . location - 7 ) ] ;
if ( YES = = [ name isEqual : [ name lowercaseString ] ] )
{
[ cmdActions addObject : name ] ;
}
}
}
2012-07-09 10:18:24 +00:00
[ ecLock unlock ] ;
2012-07-05 13:15:27 +00:00
}
2012-02-19 11:59:22 +00:00
- ( NSString * ) cmdMesg : ( NSArray * ) msg
{
NSMutableString * saved ;
NSString * result ;
NSString * cmd ;
SEL sel ;
if ( msg = = nil || [ msg count ] < 1 )
{
return @ "no command specified\n" ;
}
cmd = findAction ( [ msg objectAtIndex : 0 ] ) ;
if ( nil = = cmd )
{
return @ "unrecognised command\n" ;
}
sel = NSSelectorFromString ( [ NSString stringWithFormat : @ "cmdMesg%@:" , cmd ] ) ;
saved = replyBuffer ;
replyBuffer = [ NSMutableString stringWithCapacity : 50000 ] ;
NS_DURING
{
[ self performSelector : sel withObject : msg ] ;
}
NS_HANDLER
{
[ self cmdPrintf : @ "\n%@ during command\n" , localException ] ;
}
NS_ENDHANDLER
result = replyBuffer ;
replyBuffer = saved ;
return result ;
}
/ *
* Name - cmdMesgData : from :
* Purpose - Invoke other methods to handle commands .
* /
- ( void ) cmdMesgData : ( NSData * ) dat from : ( NSString * ) name
{
NSArray * msg ;
NSString * val ;
msg = [ NSPropertyListSerialization
propertyListWithData : dat
options : NSPropertyListMutableContainers
format : 0
error : 0 ] ;
val = [ self cmdMesg : msg ] ;
if ( cmdServer )
{
NS_DURING
{
[ cmdServer reply : val to : name from : cmdLogName ( ) ] ;
}
NS_HANDLER
{
2013-11-04 07:28:57 +00:00
[ self _commandRemove ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "Caught exception sending client reply to Command: %@ %@" ,
name , localException ) ;
}
NS_ENDHANDLER
}
}
2012-11-16 16:35:41 +00:00
- ( void ) cmdMesgalarms : ( NSArray * ) msg
{
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "reports current alarms" ] ;
}
else
{
if ( [ [ msg objectAtIndex : 0 ] isEqualToString : @ "help" ] )
{
[ self cmdPrintf : @ "\nThe alarms command is used to report the" ] ;
[ self cmdPrintf : @ " alarms currently active for this process.\n" ] ;
2012-11-23 13:51:06 +00:00
[ self cmdPrintf : @ "NB. Each individual process identifies current" ] ;
[ self cmdPrintf : @ " alarms by address within the process.\n" ] ;
[ self cmdPrintf : @ "This differs from the Control server which" ] ;
[ self cmdPrintf : @ " uses a unique notification ID intended\n" ] ;
[ self cmdPrintf : @ "for working with external SNMP systems.\n" ] ;
2012-11-16 16:35:41 +00:00
}
else
{
NSArray * a = [ alarmDestination alarms ] ;
if ( 0 = = [ a count ] )
{
[ self cmdPrintf : @ "No alarms currently active.\n" ] ;
}
else
{
int i ;
a = [ a sortedArrayUsingSelector : @ selector ( compare : ) ] ;
[ self cmdPrintf : @ "Current alarms -\n" ] ;
for ( i = 0 ; i < [ a count ] ; i + + )
{
EcAlarm * alarm = [ a objectAtIndex : i ] ;
[ self cmdPrintf : @ "%@\n" , [ alarm description ] ] ;
}
}
}
}
}
2012-02-19 11:59:22 +00:00
- ( void ) cmdMesgarchive : ( NSArray * ) msg
{
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "archives log files" ] ;
}
else
{
2012-11-16 16:35:41 +00:00
if ( [ [ msg objectAtIndex : 0 ] caseInsensitiveCompare : @ "help" ]
= = NSOrderedSame )
2012-02-19 11:59:22 +00:00
{
[ self cmdPrintf : @ "\nThe archive command is used to archive the" ] ;
[ self cmdPrintf : @ " debug file to a subdirectory.\n" ] ;
[ self cmdPrintf : @ "You should not need it - as archiving should" ] ;
[ self cmdPrintf : @ "be done automatically at midnight.\n" ] ;
}
else
{
[ self cmdPrintf : @ "\n%@\n" , [ self cmdArchive : nil ] ] ;
}
}
}
2012-11-16 16:35:41 +00:00
- ( void ) cmdMesgclear : ( NSArray * ) msg
{
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "clears current alarms" ] ;
}
else
{
if ( [ [ msg objectAtIndex : 0 ] isEqualToString : @ "help" ] )
{
[ self cmdPrintf : @ "\nThe clear command is used to clear the" ] ;
[ self cmdPrintf : @ " alarms currently active for this process.\n" ] ;
2012-11-23 12:45:09 +00:00
[ self cmdPrintf : @ "You may use the word 'all' or a space separated" ] ;
2012-11-23 13:51:06 +00:00
[ self cmdPrintf : @ " list of alarm addresses.\n" ] ;
[ self cmdPrintf : @ "NB. Each individual process identifies current" ] ;
[ self cmdPrintf : @ " alarms by address within the process.\n" ] ;
[ self cmdPrintf : @ "This differs from the Control server which" ] ;
[ self cmdPrintf : @ " uses a unique notification ID intended\n" ] ;
[ self cmdPrintf : @ "for working with external SNMP systems.\n" ] ;
2012-11-16 16:35:41 +00:00
}
else
{
NSArray * a = [ alarmDestination alarms ] ;
NSUInteger count = [ msg count ] ;
if ( count < 2 )
{
[ self cmdPrintf : @ "The 'clear' command requires an alarm"
@ " notificationID or the word all\n" ] ;
}
else
{
NSUInteger alarmCount = [ a count ] ;
EcAlarm * alarm ;
NSUInteger index ;
for ( index = 1 ; index < count ; index + + )
{
2015-07-03 07:32:18 +00:00
NSUInteger addr ;
2012-11-16 16:35:41 +00:00
NSString * arg = [ msg objectAtIndex : index ] ;
if ( [ arg caseInsensitiveCompare : _ ( @ "all" ) ]
= = NSOrderedSame )
{
NSUInteger i ;
for ( i = 0 ; i < alarmCount ; i + + )
{
alarm = [ a objectAtIndex : i ] ;
[ self cmdPrintf : @ "Clearing %@\n" , alarm ] ;
alarm = [ alarm clear ] ;
[ alarmDestination alarm : alarm ] ;
}
}
2015-07-03 07:32:18 +00:00
else if ( 1 = = sscanf ( [ arg UTF8String ] , "%" PRIxPTR , & addr ) )
2012-11-16 16:35:41 +00:00
{
NSUInteger i ;
alarm = nil ;
for ( i = 0 ; i < alarmCount ; i + + )
{
alarm = [ a objectAtIndex : i ] ;
2015-07-03 07:32:18 +00:00
if ( ( NSUInteger ) alarm = = addr )
2012-11-16 16:35:41 +00:00
{
break ;
}
alarm = nil ;
}
if ( nil = = alarm )
{
[ self cmdPrintf :
2012-11-23 12:45:09 +00:00
@ "No alarm found with the address '%@'\n" ,
2012-11-16 16:35:41 +00:00
arg ] ;
}
else
{
[ self cmdPrintf : @ "Clearing %@\n" , alarm ] ;
alarm = [ alarm clear ] ;
[ alarmDestination alarm : alarm ] ;
}
}
2012-11-23 12:45:09 +00:00
else
{
[ self cmdPrintf : @ "Not a hexadecimal address: '%@'\n" ,
arg ] ;
}
2012-11-16 16:35:41 +00:00
}
}
}
}
}
2012-02-19 11:59:22 +00:00
- ( void ) cmdMesgdebug : ( NSArray * ) msg
{
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "turns on debug logging" ] ;
}
else
{
2012-11-16 16:35:41 +00:00
if ( [ [ msg objectAtIndex : 0 ] caseInsensitiveCompare : @ "help" ]
= = NSOrderedSame )
2012-02-19 11:59:22 +00:00
{
[ self cmdPrintf : @ "\nWithout parameters, the debug command is " ] ;
[ self cmdPrintf : @ "used to list the currently active " ] ;
[ self cmdPrintf : @ "debug modes.\n" ] ;
[ self cmdPrintf : @ "With the single parameter 'default', the debug " ] ;
[ self cmdPrintf : @ "command is used to revert to default " ] ;
[ self cmdPrintf : @ "debug settings.\n" ] ;
[ self cmdPrintf : @ "With the single parameter 'all', the debug " ] ;
[ self cmdPrintf : @ "command is used to activate all " ] ;
[ self cmdPrintf : @ "debugging.\n" ] ;
[ self cmdPrintf : @ "With any other parameter, the debug command " ] ;
[ self cmdPrintf : @ "is used to activate one of the " ] ;
[ self cmdPrintf : @ "debug modes listed below.\n\n" ] ;
[ self cmdPrintf : @ "%@\n" , cmdDebugKnown ] ;
}
else if ( [ msg count ] > 1 )
{
NSString * mode = ( NSString * ) [ msg objectAtIndex : 1 ] ;
NSString * key ;
if ( [ mode caseInsensitiveCompare : @ "default" ] = = NSOrderedSame )
{
NSEnumerator * enumerator = [ cmdDebugKnown keyEnumerator ] ;
while ( nil ! = ( mode = [ enumerator nextObject ] ) )
{
key = [ @ "Debug-" stringByAppendingString : mode ] ;
[ cmdDefs setCommand : nil forKey : key ] ;
}
[ self cmdPrintf : @ "Now using debug settings from config.\n" ] ;
}
else if ( [ mode caseInsensitiveCompare : @ "all" ] = = NSOrderedSame )
{
NSEnumerator * enumerator = [ cmdDebugKnown keyEnumerator ] ;
while ( nil ! = ( mode = [ enumerator nextObject ] ) )
{
key = [ @ "Debug-" stringByAppendingString : mode ] ;
[ cmdDefs setCommand : @ "YES" forKey : key ] ;
}
[ self cmdPrintf : @ "All debugging is now active.\n" ] ;
}
else
{
[ self cmdPrintf : @ "debug mode '" ] ;
if ( ( mode = findMode ( cmdDebugKnown , mode ) ) = = nil )
{
[ self cmdPrintf : @ "%@' is not known.\n" , mode ] ;
}
else
{
[ self cmdPrintf : @ "%@" , mode ] ;
if ( [ cmdDebugModes member : mode ] = = nil )
{
[ self cmdPrintf : @ "' is now active." ] ;
}
else
{
[ self cmdPrintf : @ "' is already active." ] ;
}
key = [ @ "Debug-" stringByAppendingString : mode ] ;
[ cmdDefs setCommand : @ "YES" forKey : key ] ;
}
}
}
else
{
[ self cmdPrintf : @ "%@\n" , [ EcLogger loggerForType : LT_DEBUG ] ] ;
[ self cmdPrintf : @ "Current active debug modes -\n" ] ;
if ( [ cmdDebugModes count ] = = 0 )
{
[ self cmdPrintf : @ "\nNone.\n" ] ;
}
else
{
[ self cmdPrintf : @ "%@\n" , cmdDebugModes ] ;
}
}
}
}
- ( void ) cmdMesghelp : ( NSArray * ) msg
{
2012-07-05 13:15:27 +00:00
NSEnumerator * e ;
2012-02-19 11:59:22 +00:00
NSString * cmd ;
SEL sel ;
2012-07-05 13:15:27 +00:00
[ ecLock lock ] ;
e = [ cmdActions objectEnumerator ] ;
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "provides helpful information :-)" ] ;
return ;
}
else if ( [ msg count ] > 1 )
{
NSString * found ;
cmd = [ msg objectAtIndex : 1 ] ;
found = findAction ( cmd ) ;
if ( [ cmd caseInsensitiveCompare : @ "control" ] = = NSOrderedSame )
{
[ self cmdPrintf : @ "Detailed help on the 'control' command -\n" ] ;
[ self cmdPrintf : @ "This command enables you to send an" ] ;
[ self cmdPrintf : @ "instruction to the 'Control' server rather\n" ] ;
[ self cmdPrintf : @ "than to the currently connected server.\n" ] ;
[ self cmdPrintf : @ "Everything typed on the line after the word" ] ;
[ self cmdPrintf : @ " 'control' is treated as a command to\n" ] ;
[ self cmdPrintf : @ "the 'Control' server process.\n" ] ;
[ self cmdPrintf : @ "\nTo disconnect from the server type -\n" ] ;
[ self cmdPrintf : @ " control connect\n" ] ;
[ self cmdPrintf : @ "\nTo disconnect from the host type -\n" ] ;
[ self cmdPrintf : @ " control host\n" ] ;
return ;
}
else if ( nil = = found )
{
[ self cmdPrintf : @ "Unable to find the '%@' command -\n" , cmd ] ;
}
else if ( [ found caseInsensitiveCompare : @ "help" ] ! = NSOrderedSame )
{
NSMutableArray * m ;
[ self cmdPrintf : @ "Detailed help on the '%@' command -\n" , found ] ;
sel = NSSelectorFromString (
[ NSString stringWithFormat : @ "cmdMesg%@:" , found ] ) ;
/ * To get the help on a command , we invoke that command
* by passing the command and arguments ( ie , the msg array ) .
* The command implementation should check the argument 0 -
* if it is "help" , it should print out help on itself .
* Save expanded ( unabbreviated ) commands so the methods
* getting the help request don ' t need to recheck the values .
* /
m = [ [ msg mutableCopy ] autorelease ] ;
[ m replaceObjectAtIndex : 0 withObject : @ "help" ] ;
[ m replaceObjectAtIndex : 1 withObject : found ] ;
[ self performSelector : sel withObject : m ] ;
return ;
}
}
[ self cmdPrintf : @ "\n" ] ;
[ self cmdPrintf : @ "For help on a particular command, type 'help <cmd>'\n" ] ;
[ self cmdPrintf : @ "\n" ] ;
[ self cmdPrintf : @ "These are the commands available to you -\n" ] ;
[ self cmdPrintf : @ "\n" ] ;
while ( ( cmd = [ e nextObject ] ) ! = nil )
{
unsigned l ;
sel = NSSelectorFromString (
[ NSString stringWithFormat : @ "cmdMesg%@:" , cmd ] ) ;
[ self cmdPrintf : @ "%@ - " , cmd ] ;
l = [ cmd length ] ;
while ( l + + < 9 )
{
[ self cmdPrintf : @ " " ] ;
}
[ self performSelector : sel withObject : nil ] ;
[ self cmdPrintf : @ "\n" ] ;
}
}
- ( void ) cmdMesgnodebug : ( NSArray * ) msg
{
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "turns off debug logging" ] ;
}
else
{
2012-11-16 16:35:41 +00:00
if ( [ [ msg objectAtIndex : 0 ] caseInsensitiveCompare : @ "help" ]
= = NSOrderedSame )
2012-02-19 11:59:22 +00:00
{
[ self cmdPrintf : @ "\n" ] ;
[ self cmdPrintf : @ "Without parameters, the nodebug command is " ] ;
[ self cmdPrintf : @ "used to list the currently inactive\n" ] ;
[ self cmdPrintf : @ "debug modes.\n" ] ;
[ self cmdPrintf : @ "With the single parameter 'all', the nodebug " ] ;
[ self cmdPrintf : @ "command is used to deactivate all\n" ] ;
[ self cmdPrintf : @ "debugging.\n" ] ;
[ self cmdPrintf : @ "With the single parameter 'default', the " ] ;
[ self cmdPrintf : @ "nodebug command is used to revert to default " ] ;
[ self cmdPrintf : @ "debug settings.\n" ] ;
[ self cmdPrintf : @ "With any other parameter, the nodebug command is" ] ;
[ self cmdPrintf : @ " used to deactivate one of the\n" ] ;
[ self cmdPrintf : @ "debug modes listed below.\n" ] ;
[ self cmdPrintf : @ "\n" ] ;
[ self cmdPrintf : @ "%@\n" , cmdDebugKnown ] ;
}
else if ( [ msg count ] > 1 )
{
NSString * mode = ( NSString * ) [ msg objectAtIndex : 1 ] ;
NSString * key ;
if ( [ mode caseInsensitiveCompare : @ "default" ] = = NSOrderedSame )
{
NSEnumerator * enumerator = [ cmdDebugKnown keyEnumerator ] ;
while ( nil ! = ( mode = [ enumerator nextObject ] ) )
{
key = [ @ "Debug-" stringByAppendingString : mode ] ;
[ cmdDefs setCommand : nil forKey : key ] ;
}
[ self cmdPrintf : @ "Now using debug settings from config.\n" ] ;
}
else if ( [ mode caseInsensitiveCompare : @ "all" ] = = NSOrderedSame )
{
NSEnumerator * enumerator = [ cmdDebugKnown keyEnumerator ] ;
while ( nil ! = ( mode = [ enumerator nextObject ] ) )
{
key = [ @ "Debug-" stringByAppendingString : mode ] ;
[ cmdDefs setCommand : @ "NO" forKey : key ] ;
}
[ self cmdPrintf : @ "All debugging is now inactive.\n" ] ;
}
else
{
[ self cmdPrintf : @ "debug mode '" ] ;
if ( ( mode = findMode ( cmdDebugKnown , mode ) ) = = nil )
{
[ self cmdPrintf : @ "%@' is not known.\n" , mode ] ;
}
else
{
[ self cmdPrintf : @ "%@' is " , mode ] ;
if ( [ cmdDebugModes member : mode ] = = nil )
{
[ self cmdPrintf : @ "already inactive.\n" ] ;
}
else
{
[ self cmdPrintf : @ "now deactivated.\n" ] ;
}
key = [ @ "Debug-" stringByAppendingString : mode ] ;
[ cmdDefs setCommand : @ "NO" forKey : key ] ;
}
}
}
else
{
NSArray * a = [ cmdDebugKnown allKeys ] ;
NSMutableSet * s = [ NSMutableSet setWithArray : a ] ;
/ *
* Find items known but not active .
* /
[ s minusSet : cmdDebugModes ] ;
[ self cmdPrintf : @ "Current inactive debug modes -\n" ] ;
if ( a = = 0 )
{
[ self cmdPrintf : @ "none.\n" ] ;
}
else
{
[ self cmdPrintf : @ "%@\n" , s ] ;
}
}
}
}
- ( void ) cmdMesgmemory : ( NSArray * ) msg
{
2015-07-08 09:06:26 +00:00
if ( [ msg count ] = = 0 )
2012-02-19 11:59:22 +00:00
{
[ self cmdPrintf : @ "controls recording of memory management statistics" ] ;
}
else
{
2015-07-09 12:08:58 +00:00
[ self cmdPrintf : @ "\n%@ on %@ running since %@\n\n" ,
cmdLogName ( ) , ecHostName ( ) , [ self ecStarted ] ] ;
2012-11-16 16:35:41 +00:00
if ( [ [ msg objectAtIndex : 0 ] caseInsensitiveCompare : @ "help" ]
2015-07-08 09:06:26 +00:00
= = NSOrderedSame || ( [ msg count ] > 1
&& [ [ msg objectAtIndex : 1 ] caseInsensitiveCompare : @ "help" ]
= = NSOrderedSame ) )
2012-02-19 11:59:22 +00:00
{
2015-07-08 09:06:26 +00:00
[ self cmdPrintf : @ " \ n \
Without parameters , \ n \
the memory command is used to list the changes in the numbers of objects \ n \
allocated since the command was last issued . \ n \
With the single parameter ' all ' , \ n \
the memory command is used to list the cumulative totals of objects \ n \
2015-07-09 12:08:58 +00:00
allocated since the gathering of memory usage statistics was turned on . \ n \
With the single parameter ' current ' , \ n \
the memory command is used to list the current totals of objects \ n \
allocated ( and not deallocated ) since the gathering of memory usage \ n \
statistics was turned on . \ n \
2015-07-08 09:06:26 +00:00
With the single parameter ' yes ' , \ n \
the memory command is used to turn on gathering of memory usage statistics . \ n \
With the single parameter ' no ' , \ n \
the memory command is used to turn off gathering of memory usage statistics . \ n \
With the single parameter ' default ' , \ n \
the gathering of memory usage statistics reverts to the default setting . \ n \
With two parameters ( ' class ' and a class name ) , \ n \
new instances of the class are recorded . \ n \
With two parameters ( ' list ' and a class ) , \ n \
recorded instances of the class are reported . \ n \
With two parameters ( ' allowed ' and a number ) , \ n \
the threshold for warnings about process size is set ( in MB ) . \ n \
Set to ' default ' to revert to the default . \ n \
With two parameters ( ' increment ' and a number ) , \ n \
the size increment between warnings about process size is set ( in KB \ n \
from 10 to 1000000 ) . Set to ' default ' to revert to the default . \ n \
With two parameters ( ' percentage ' and a number ) , \ n \
the percentage increment between warnings about process memory size is \ n \
set ( from 1 to 1000 ) . Set to ' default ' to revert to the default . \ n \
With two parameters ( ' maximum ' and a number ) , \ n \
the maximum process size ( in MB ) is set . On reaching the limit , the \ n \
process restarts unless the limit is zero ( meaning no maximum ) . \ n \
Set to ' default ' to revert to the default . " ] ;
2012-02-19 11:59:22 +00:00
[ self cmdPrintf : @ "\n" ] ;
}
2014-05-08 10:49:24 +00:00
else if ( [ msg count ] = = 2 )
2012-02-19 11:59:22 +00:00
{
NSString * word = [ msg objectAtIndex : 1 ] ;
2015-07-09 12:08:58 +00:00
if ( [ word caseInsensitiveCompare : @ "current" ] = = NSOrderedSame )
{
if ( NO = = [ cmdDefs boolForKey : @ "Memory" ] )
{
[ self cmdPrintf :
@ "Memory statistics were not being gathered.\n" ] ;
[ self cmdPrintf : @ "Memory statistics Will start from NOW.\n" ] ;
}
else
{
const char * list ;
list = ( const char * ) GSDebugAllocationList ( NO ) ;
[ self cmdPrintf : @ "Memory current stats at %@:\n%s" ,
[ NSDate date ] , list ] ;
}
[ cmdDefs setCommand : @ "YES" forKey : @ "Memory" ] ;
}
else if ( [ word caseInsensitiveCompare : @ "default" ] = = NSOrderedSame )
2012-02-19 11:59:22 +00:00
{
[ cmdDefs setCommand : nil forKey : @ "Memory" ] ;
[ self cmdPrintf : @ "Memory checking: %s\n" ,
[ cmdDefs boolForKey : @ "Memory" ] ? "YES" : "NO" ] ;
}
else if ( [ word caseInsensitiveCompare : @ "all" ] = = NSOrderedSame )
{
if ( NO = = [ cmdDefs boolForKey : @ "Memory" ] )
{
[ self cmdPrintf :
@ "Memory statistics were not being gathered.\n" ] ;
[ self cmdPrintf : @ "Memory statistics Will start from NOW.\n" ] ;
}
else
{
const char * list ;
list = ( const char * ) GSDebugAllocationList ( NO ) ;
2015-07-09 12:08:58 +00:00
[ self cmdPrintf : @ "Memory total allocation stats at %@:\n%s" ,
[ NSDate date ] , list ] ;
2012-02-19 11:59:22 +00:00
}
[ cmdDefs setCommand : @ "YES" forKey : @ "Memory" ] ;
}
else if ( [ word boolValue ] = = YES )
{
if ( NO = = [ cmdDefs boolForKey : @ "Memory" ] )
{
[ self cmdPrintf :
@ "Memory statistics were not being gathered.\n" ] ;
[ self cmdPrintf : @ "Statistics Will start from NOW.\n" ] ;
}
else
{
[ self cmdPrintf :
@ "Memory statistics are already being gathered.\n" ] ;
}
[ cmdDefs setCommand : @ "YES" forKey : @ "Memory" ] ;
}
else
{
if ( NO = = [ cmdDefs boolForKey : @ "Memory" ] )
{
[ self cmdPrintf :
@ "Memory statistics were not being gathered.\n" ] ;
}
[ self cmdPrintf : @ "Memory statistics are turned off NOW.\n" ] ;
[ cmdDefs setCommand : @ "NO" forKey : @ "Memory" ] ;
}
}
2014-05-08 10:49:24 +00:00
else if ( [ msg count ] = = 3 )
{
2015-07-08 09:06:26 +00:00
NSString * op = [ msg objectAtIndex : 1 ] ;
NSString * arg = [ msg objectAtIndex : 2 ] ;
NSInteger val = [ arg integerValue ] ;
if ( [ op caseInsensitiveCompare : @ "allowed" ] = = NSOrderedSame )
{
if ( val <= 0 )
{
[ cmdDefs setCommand : nil forKey : @ "MemoryAllowed" ] ;
if ( 0 = = memAllowed )
{
/ * The threshold was set back to zero . . . to be
* calculated from a ten minute baseline .
* /
memSlot = 0 ;
}
[ self cmdPrintf : @ "MemoryAllowed using default value.\n" ] ;
}
else
{
arg = [ NSString stringWithFormat : @ "%" PRIu64 , ( uint64_t ) val ] ;
[ cmdDefs setCommand : arg forKey : @ "MemoryAllowed" ] ;
[ self cmdPrintf : @ "MemoryAllowed set to %@MB.\n" , arg ] ;
}
memWarn = memAllowed * 1024 * 1024 ;
DESTROY ( memTime ) ;
[ self _memCheck ] ;
}
else if ( [ op caseInsensitiveCompare : @ "increment" ] = = NSOrderedSame )
2014-05-08 10:49:24 +00:00
{
2015-07-08 09:06:26 +00:00
if ( val <= 10 || val > 1000000 )
{
[ cmdDefs setCommand : nil forKey : @ "MemoryIncrement" ] ;
[ self cmdPrintf : @ "MemoryIncrement using default value.\n" ] ;
}
else
{
arg = [ NSString stringWithFormat : @ "%" PRIu64 , ( uint64_t ) val ] ;
[ cmdDefs setCommand : arg forKey : @ "MemoryIncrement" ] ;
[ self cmdPrintf : @ "MemoryIncrement set to %@KB.\n" , arg ] ;
}
2014-05-08 10:49:24 +00:00
}
2015-07-08 09:06:26 +00:00
else if ( [ op caseInsensitiveCompare : @ "percentage" ] = = NSOrderedSame )
2014-05-08 10:49:24 +00:00
{
2015-07-08 09:06:26 +00:00
if ( val <= 0 || val > 1000 )
2014-05-08 10:49:24 +00:00
{
2015-07-08 09:06:26 +00:00
[ cmdDefs setCommand : nil forKey : @ "MemoryPercentage" ] ;
[ self cmdPrintf : @ "MemoryPercentage using default value.\n" ] ;
2014-05-08 10:49:24 +00:00
}
2015-07-08 09:06:26 +00:00
else
2014-05-08 10:49:24 +00:00
{
2015-07-08 09:06:26 +00:00
arg = [ NSString stringWithFormat : @ "%" PRIu64 , ( uint64_t ) val ] ;
[ cmdDefs setCommand : arg forKey : @ "MemoryPercentage" ] ;
[ self cmdPrintf : @ "MemoryPercentage set to %@.\n" , arg ] ;
}
}
else if ( [ op caseInsensitiveCompare : @ "maximum" ] = = NSOrderedSame )
{
if ( val <= 0 )
{
if ( [ arg caseInsensitiveCompare : @ "default" ] = = NSOrderedSame )
2014-05-08 10:49:24 +00:00
{
2015-07-08 09:06:26 +00:00
[ cmdDefs setCommand : nil forKey : @ "MemoryMaximum" ] ;
[ self cmdPrintf : @ "MemoryMaximum using default value.\n" ] ;
2014-05-08 10:49:24 +00:00
}
2015-07-08 09:06:26 +00:00
else
{
[ cmdDefs setCommand : @ "0" forKey : @ "MemoryMaximum" ] ;
[ self cmdPrintf : @ "MemoryMaximum restart turned off.\n" ] ;
}
}
else
{
arg = [ NSString stringWithFormat : @ "%" PRIu64 , ( uint64_t ) val ] ;
[ cmdDefs setCommand : arg forKey : @ "MemoryMaximum" ] ;
[ self cmdPrintf : @ "MemoryMaximum set to %@MB.\n" , arg ] ;
}
}
else
{
Class c = NSClassFromString ( arg ) ;
if ( Nil = = c )
{
[ self cmdPrintf : @ "Unable to find class '%@'.\n" , arg ] ;
2014-05-08 10:49:24 +00:00
}
else
{
2015-07-08 09:06:26 +00:00
if ( [ op caseInsensitiveCompare : @ "class" ] = = NSOrderedSame )
{
GSDebugAllocationActiveRecordingObjects ( c ) ;
[ self cmdPrintf : @ "Recording instances of '%@'.\n" , arg ] ;
}
else if ( [ op caseInsensitiveCompare : @ "list" ] = = NSOrderedSame )
{
NSArray * array ;
NSUInteger count ;
NSUInteger index ;
array = GSDebugAllocationListRecordedObjects ( c ) ;
[ self cmdPrintf : @ "Current instances of '%@':\n" , arg ] ;
count = [ array count ] ;
for ( index = 0 ; index < count ; index + + )
{
[ self cmdPrintf : @ "%6lu %@\n" ,
( unsigned long ) index , [ array objectAtIndex : index ] ] ;
}
}
else
{
[ self cmdPrintf : @ "Unknown memory command '%@'.\n" , op ] ;
}
2014-05-08 10:49:24 +00:00
}
}
}
2012-02-19 11:59:22 +00:00
else
{
if ( NO = = [ cmdDefs boolForKey : @ "Memory" ] )
{
[ self cmdPrintf : @ "Memory stats are not being gathered.\n" ] ;
}
else
{
const char * list ;
list = ( const char * ) GSDebugAllocationList ( YES ) ;
2015-07-09 12:08:58 +00:00
if ( nil = = memStats )
{
[ self cmdPrintf : @ "Memory change stats at %@:\n%s" ,
[ NSDate date ] , list ] ;
}
else
{
[ self cmdPrintf : @ "Memory change stats at %@ (since %@):\n%s" ,
[ NSDate date ] , memStats , list ] ;
}
2012-02-19 11:59:22 +00:00
}
}
}
}
- ( void ) cmdMesgstatus : ( NSArray * ) msg
{
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "provides server status information" ] ;
}
else
{
[ self cmdPrintf : @ "\n%@ on %@ running since %@\n" ,
2013-04-08 15:50:32 +00:00
cmdLogName ( ) , ecHostName ( ) , [ self ecStarted ] ] ;
2014-11-26 08:59:50 +00:00
if ( lastIP > 0.0 )
2012-02-19 11:59:22 +00:00
{
[ self cmdPrintf : @ "Last IP at %@\n" , [ self cmdLastIP ] ] ;
}
2014-11-26 08:59:50 +00:00
if ( lastOP > 0.0 )
2012-02-19 11:59:22 +00:00
{
[ self cmdPrintf : @ "Last OP at %@\n" , [ self cmdLastOP ] ] ;
}
if ( servers ! = nil )
{
NSEnumerator * e ;
RemoteServer * server ;
e = [ servers objectEnumerator ] ;
while ( ( server = ( RemoteServer * ) [ e nextObject ] ) ! = 0 )
{
[ self cmdPrintf : @ "%@\n" , server ] ;
}
}
2015-07-05 11:39:18 +00:00
[ self cmdPrintf : @ "Memory usage: %" PRIu64 "KB (current),"
@ " %" PRIu64 "KB (peak)\n" ,
2015-07-03 19:23:42 +00:00
memLast / 1024 , memPeak / 1024 ] ;
2015-07-05 11:39:18 +00:00
[ self cmdPrintf : @ " %" PRIu64 "KB (average),"
2015-07-07 15:11:34 +00:00
@ " %" PRIu64 "KB (start)\n" ,
memAvge / 1024 , memStrt / 1024 ] ;
2015-07-08 09:06:26 +00:00
[ self cmdPrintf : @ " %" PRIu64 "KB (reserved)\n" ,
2015-07-07 15:11:34 +00:00
[ self ecNotLeaked ] / 1024 ] ;
2015-07-09 12:08:58 +00:00
if ( memSlot < MEMCOUNT )
{
2015-07-09 12:21:51 +00:00
[ self cmdPrintf : @ "Memory error reporting disabled (for %d min"
@ " of baseline stats collection).\n" , ( int ) ( MEMCOUNT - memSlot ) ] ;
2015-07-09 12:08:58 +00:00
}
else
{
[ self cmdPrintf :
@ "Memory error reporting after average usage: %" PRIu64 "KB\n" ,
memWarn / 1024 ] ;
}
2013-08-20 14:35:26 +00:00
if ( memMaximum > 0 )
{
[ self cmdPrintf :
2015-07-05 11:39:18 +00:00
@ "Memory exceeded shutdown after peak usage: %" PRIu64 "KB\n" ,
2015-07-03 10:42:48 +00:00
memMaximum * 1024 ] ;
2013-08-20 14:35:26 +00:00
}
2012-02-19 11:59:22 +00:00
}
}
2015-01-26 12:50:42 +00:00
- ( oneway void ) cmdPing : ( id < CmdPing > ) from
sequence : ( unsigned ) num
extra : ( in bycopy NSData * ) data
2012-02-19 11:59:22 +00:00
{
[ self cmdDbg : cmdConnectDbg msg : @ "cmdPing: %lx sequence: %u extra: %lx" ,
( unsigned long ) from , num , ( unsigned long ) data ] ;
[ from cmdGnip : self sequence : num extra : nil ] ;
}
2012-05-25 19:10:27 +00:00
- ( void ) cmdPrintf : ( NSString * ) fmt arguments : ( va_list ) args
{
NSString * tmp ;
tmp = [ [ stringClass alloc ] initWithFormat : fmt arguments : args ] ;
[ replyBuffer appendString : tmp ] ;
[ tmp release ] ;
}
2012-02-19 11:59:22 +00:00
- ( void ) cmdPrintf : ( NSString * ) fmt , . . .
{
va_list ap ;
va_start ( ap , fmt ) ;
2012-05-25 19:10:27 +00:00
[ self cmdPrintf : fmt arguments : ap ] ;
2012-02-19 11:59:22 +00:00
va_end ( ap ) ;
}
2012-10-28 14:37:42 +00:00
- ( void ) cmdQuit : ( NSInteger ) status
2012-02-19 11:59:22 +00:00
{
2014-11-01 09:18:02 +00:00
if ( reservedPipe [ 1 ] > 0 )
{
close ( reservedPipe [ 0 ] ) ; reservedPipe [ 0 ] = 0 ;
close ( reservedPipe [ 1 ] ) ; reservedPipe [ 1 ] = 0 ;
}
2012-02-19 11:59:22 +00:00
cmdIsQuitting = YES ;
2013-12-05 16:39:00 +00:00
cmdQuitStatus = status ;
2012-02-19 11:59:22 +00:00
if ( cmdPTimer ! = nil )
{
[ cmdPTimer invalidate ] ;
cmdPTimer = nil ;
}
2013-12-05 16:39:00 +00:00
if ( 0 = = status )
{
/ * Normal shutdown . . . unmanage this process first .
* /
2014-01-16 09:36:34 +00:00
[ alarmDestination unmanage : nil ] ;
2013-12-05 16:39:00 +00:00
}
2012-02-19 11:59:22 +00:00
[ alarmDestination shutdown ] ;
[ self cmdFlushLogs ] ;
[ self cmdUnregister ] ;
[ alarmDestination shutdown ] ;
2015-07-07 13:23:01 +00:00
DESTROY ( alarmDestination ) ;
2012-02-19 11:59:22 +00:00
2012-10-12 18:07:34 +00:00
[ EcProcConnection invalidate ] ;
2012-02-19 11:59:22 +00:00
{
NSArray * keys ;
unsigned index ;
/ *
* Close down all log files .
* /
keys = [ cmdLogMap allKeys ] ;
for ( index = 0 ; index < [ keys count ] ; index + + )
{
[ self cmdLogEnd : [ keys objectAtIndex : index ] ] ;
}
}
exit ( status ) ;
}
- ( void ) cmdUpdate : ( NSMutableDictionary * ) info
{
2012-11-23 12:45:09 +00:00
BOOL defaultsChanged ;
2012-02-19 11:59:22 +00:00
2012-11-23 12:45:09 +00:00
if ( nil = = info )
2012-02-19 11:59:22 +00:00
{
2012-11-23 12:45:09 +00:00
defaultsChanged = NO ;
2012-02-19 11:59:22 +00:00
}
else
{
2012-11-23 12:45:09 +00:00
ASSIGNCOPY ( cmdConf , info ) ;
defaultsChanged = [ cmdDefs setConfiguration : cmdConf ] ;
2012-02-19 11:59:22 +00:00
}
2012-11-23 12:45:09 +00:00
/ * If the defaults did not actually change ,
* trigger an update anyway .
2012-02-19 11:59:22 +00:00
* /
2012-11-23 12:45:09 +00:00
if ( NO = = defaultsChanged )
2012-02-19 11:59:22 +00:00
{
2012-11-23 12:45:09 +00:00
[ self cmdDefaultsChanged : nil ] ;
2012-02-19 11:59:22 +00:00
}
}
2013-03-13 10:08:13 +00:00
- ( NSString * ) cmdUpdated
2012-11-23 12:45:09 +00:00
{
2013-03-13 10:08:13 +00:00
return nil ;
2012-11-23 12:45:09 +00:00
}
2012-02-19 11:59:22 +00:00
- ( void ) dealloc
{
[ [ NSNotificationCenter defaultCenter ] removeObserver : self ] ;
2012-03-09 09:22:09 +00:00
[ ecLock lock ] ;
2012-02-19 11:59:22 +00:00
if ( self = = EcProc )
{
EcProc = nil ;
}
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
[ super dealloc ] ;
}
- ( NSString * ) description
{
return [ stringClass stringWithFormat : @ "%@ (%@) on %@" ,
2012-05-08 16:08:30 +00:00
[ super description ] , cmdLogName ( ) , ecHostName ( ) ] ;
2012-02-19 11:59:22 +00:00
}
- ( id ) init
{
2014-04-28 06:40:03 +00:00
CREATE_AUTORELEASE _POOL ( pool ) ;
2012-02-19 11:59:22 +00:00
2014-04-28 06:40:03 +00:00
self = [ self initWithDefaults : [ [ self class ] ecInitialDefaults ] ] ;
RELEASE ( pool ) ;
return self ;
2012-02-19 11:59:22 +00:00
}
- ( id ) initWithDefaults : ( NSDictionary * ) defs
{
2012-03-09 09:22:09 +00:00
[ ecLock lock ] ;
2012-02-19 11:59:22 +00:00
if ( nil ! = EcProc )
{
[ self release ] ;
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
[ NSException raise : NSGenericException
format : @ "EcProcess initialiser called more than once" ] ;
}
if ( nil = = ( self = [ super init ] ) )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
return nil ;
}
else
{
NSProcessInfo * pinfo ;
2014-11-02 14:30:24 +00:00
NSArray * args ;
2012-02-19 11:59:22 +00:00
NSFileManager * mgr ;
NSEnumerator * enumerator ;
NSString * str ;
NSString * dbg ;
NSString * prf ;
BOOL flag ;
2012-02-19 14:42:50 +00:00
NSInteger i ;
2012-02-19 11:59:22 +00:00
EcProc = self ;
2013-04-08 15:50:32 +00:00
started = RETAIN ( [ dateClass date ] ) ;
2012-02-19 11:59:22 +00:00
pinfo = [ NSProcessInfo processInfo ] ;
2014-11-02 14:30:24 +00:00
args = [ pinfo arguments ] ;
2012-02-19 11:59:22 +00:00
mgr = [ NSFileManager defaultManager ] ;
prf = EC_DEFAULTS _PREFIX ;
if ( nil = = prf )
{
prf = @ "" ;
}
ASSIGN ( cmdDefs , [ NSUserDefaults
userDefaultsWithPrefix : prf
strict : EC_DEFAULTS _STRICT ] ) ;
if ( defs ! = nil )
{
[ cmdDefs registerDefaults : defs ] ;
}
2014-11-02 14:30:24 +00:00
if ( [ args containsObject : @ "--help" ] || [ args containsObject : @ "-H" ] )
2012-02-19 11:59:22 +00:00
{
2014-11-02 14:30:24 +00:00
GSPrintf ( stderr , @ "Standard command-line arguments ...\n\n" ) ;
if ( [ self isKindOfClass : NSClassFromString ( @ "EcControl" ) ] )
{
GSPrintf ( stderr ,
@ "-%@Daemon NO Run process in the foreground.\n" ,
prf ) ;
}
else if ( [ self isKindOfClass : NSClassFromString ( @ "EcConsole" ) ] )
{
GSPrintf ( stderr ,
@ "-%@ControlHost [aHost] Host of the Control server to use.\n"
@ "-%@ControlName [aName] Name of the Control server to use.\n"
@ "-%@Daemon [YES/NO] Fork process to run in background?\n" ,
prf , prf , prf ) ;
}
else if ( [ self isKindOfClass : NSClassFromString ( @ "EcCommand" ) ] )
{
GSPrintf ( stderr ,
@ "-%@ControlHost [aHost] Host of the Control server to use.\n"
@ "-%@ControlName [aName] Name of the Control server to use.\n"
@ "-%@Daemon NO Run process in in the foreground.\n" ,
prf , prf , prf ) ;
}
else
{
GSPrintf ( stderr ,
@ "-%@CommandHost [aHost] Host of the Command server to use.\n"
@ "-%@CommandName [aName] Name of the Command server to use.\n"
@ "-%@Daemon [YES/NO] Fork process to run in background?\n" ,
@ "-%@Transient [YES/NO] Expect this process be short-lived?\n" ,
prf , prf , prf , prf ) ;
}
GSPrintf ( stderr , @ "\n" ) ;
GSPrintf ( stderr ,
@ "-%@CoreSize [MB] Maximum core dump size\n"
@ " 0 = no dumps, -1 = unlimited\n"
@ "-%@DescriptorsMaximum [N]\n"
@ " Set maximum file descriptors to use\n"
@ "-%@Debug-name [YES/NO] Turn on/off the named type of debug\n"
@ "-%@EffectiveUser [aName] User to run this process as\n"
2012-02-19 11:59:22 +00:00
@ "-%@HomeDirectory [relDir] Relative home within user directory\n"
@ "-%@UserDirectory [dir] Override home directory for user\n"
@ "-%@Instance [aNumber] Instance number for multiple copies\n"
2014-11-02 14:30:24 +00:00
@ "-%@MemoryAllowed [MB] Expected memory usage (before alerts)\n"
@ "-%@MemoryIncrement [KB] Absolute increase in alert threshold\n"
@ "-%@MemoryMaximum [MB] Maximum memory usage (before restart)\n"
@ "-%@MemoryPercentage [N] Percent increase in alert threshold\n"
2012-02-19 11:59:22 +00:00
@ "-%@ProgramName [aName] Name to use for this program\n"
@ "\n--version to get version information and quit\n\n" ,
2014-11-02 14:30:24 +00:00
prf , prf , prf , prf , prf , prf , prf , prf , prf , prf , prf , prf ) ;
[ EcDefaultRegistration showHelp ] ;
2012-02-19 11:59:22 +00:00
RELEASE ( self ) ;
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
return nil ;
}
2014-11-02 14:30:24 +00:00
if ( [ args containsObject : @ "--version" ] )
2012-02-19 11:59:22 +00:00
{
2012-03-09 09:22:09 +00:00
NSLog ( @ "%@ %@" , [ self ecCopyright ] , cmdVersion ( nil ) ) ;
2012-02-19 11:59:22 +00:00
RELEASE ( self ) ;
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
return nil ;
}
cmdUser = EC_EFFECTIVE _USER ;
if ( nil = = cmdUser )
{
cmdUser = [ [ cmdDefs stringForKey : @ "EffectiveUser" ] retain ] ;
}
2012-10-09 12:53:56 +00:00
if ( YES = = [ cmdUser isEqual : @ "*" ]
2012-02-19 11:59:22 +00:00
|| YES = = [ cmdUser isEqualToString : NSUserName ( ) ] )
{
ASSIGN ( cmdUser , NSUserName ( ) ) ;
}
2012-10-09 12:53:56 +00:00
else if ( [ cmdUser length ] = = 0 )
{
NSLog ( @ "This software is not configured to run as any user.\n"
@ "You may use the EffectiveUser user default setting"
@ " to specify the user (setting this to an asterisk ('*')"
@ " allows the software to run as any user). Alternatively"
@ " an EC_EFFECTIVE_USER can be defined when the ec library"
@ " is built." ) ;
exit ( 1 ) ;
}
2012-02-19 11:59:22 +00:00
else
{
const char * user = [ cmdUser UTF8String ] ;
struct passwd * pwd = getpwnam ( user ) ;
int uid ;
if ( pwd ! = 0 )
{
uid = pwd -> pw_uid ;
}
else
{
2012-06-06 07:54:56 +00:00
NSLog ( @ "This software is configured to run as the user '%@',"
@ " but there does not appear to be any such user." , cmdUser ) ;
if ( [ cmdUser isEqual : EC_EFFECTIVE _USER ] )
{
NSLog ( @ "You may use the EffectiveUser user default setting"
@ " to override the user (setting this to an asterisk ('*')"
@ " allows the software to run as any user). Alternatively"
@ " a different EC_EFFECTIVE_USER can be defined when the"
@ " ec library is built." ) ;
}
exit ( 1 ) ;
2012-02-19 11:59:22 +00:00
}
if ( uid ! = ( int ) geteuid ( ) )
{
if ( geteuid ( ) = = 0 || ( int ) getuid ( ) = = uid )
{
if ( 0 ! = setuid ( uid ) )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "You must be '%@' to run this." , cmdUser ) ;
exit ( 1 ) ;
}
}
else
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "You must be '%@' to run this." , cmdUser ) ;
exit ( 1 ) ;
}
}
GSSetUserName ( cmdUser ) ;
if ( NO = = [ cmdUser isEqualToString : NSUserName ( ) ] )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "You must be '%@' to run this." , cmdUser ) ;
exit ( 1 ) ;
}
ASSIGN ( cmdDefs , [ NSUserDefaults
userDefaultsWithPrefix : prf
strict : EC_DEFAULTS _STRICT ] ) ;
if ( defs ! = nil )
{
[ cmdDefs registerDefaults : defs ] ;
}
}
2015-03-26 11:33:02 +00:00
/ * See if we should keep stderr separate , or merge it with
* our debug output ( the default ) .
* /
cmdKeepStderr = [ cmdDefs boolForKey : @ "KeepStandardError" ] ;
2012-02-19 11:59:22 +00:00
if ( nil = = noNetConfig )
{
noNetConfig = [ [ NSMutableArray alloc ] initWithCapacity : 4 ] ;
[ noNetConfig
addObject : [ prf stringByAppendingString : @ "Daemon" ] ] ;
[ noNetConfig
addObject : [ prf stringByAppendingString : @ "EffectiveUser" ] ] ;
[ noNetConfig
addObject : [ prf stringByAppendingString : @ "Instance" ] ] ;
[ noNetConfig
addObject : [ prf stringByAppendingString : @ "Transient" ] ] ;
}
defs = [ cmdDefs dictionaryRepresentation ] ;
enumerator = [ defs keyEnumerator ] ;
dbg = [ prf stringByAppendingString : @ "Debug-" ] ;
while ( ( str = [ enumerator nextObject ] ) ! = nil )
{
if ( [ str hasPrefix : dbg ] )
{
id obj = [ defs objectForKey : str ] ;
NSString * key = [ str substringFromIndex : [ dbg length ] ] ;
if ( [ cmdDebugKnown objectForKey : key ] = = nil )
{
[ cmdDebugKnown setObject : key forKey : key ] ;
}
if ( [ obj isKindOfClass : stringClass ] )
{
if ( [ obj intValue ] ! = 0
|| [ obj isEqual : @ "YES" ] || [ obj isEqual : @ "yes" ] )
{
if ( [ cmdDebugModes member : key ] = = nil )
{
[ cmdDebugModes addObject : key ] ;
}
}
else
{
if ( [ cmdDebugModes member : key ] ! = nil )
{
[ cmdDebugModes removeObject : key ] ;
}
}
}
}
}
2012-02-20 13:07:54 +00:00
/ * See if we have a name specified for this process .
* /
2012-02-19 11:59:22 +00:00
ASSIGN ( cmdName , [ cmdDefs stringForKey : @ "ProgramName" ] ) ;
2012-02-20 13:07:54 +00:00
/ * If there ' s no ProgramName specified , but this is a Control server ,
* try looking for the ControlName instead .
* /
2012-02-20 14:03:36 +00:00
if ( nil = = cmdName
&& Nil ! = NSClassFromString ( @ "EcControl" )
&& YES = = [ self isKindOfClass : NSClassFromString ( @ "EcControl" ) ] )
2012-02-20 13:07:54 +00:00
{
ASSIGN ( cmdName , [ cmdDefs stringForKey : @ "ControlName" ] ) ;
}
/ * If there ' s no ProgramName specified , but this is a Command server ,
* try looking for the CommandName instead .
* /
2012-02-20 14:03:36 +00:00
if ( nil = = cmdName
&& Nil ! = NSClassFromString ( @ "EcCommand" )
&& YES = = [ self isKindOfClass : NSClassFromString ( @ "EcCommand" ) ] )
2012-02-20 13:07:54 +00:00
{
ASSIGN ( cmdName , [ cmdDefs stringForKey : @ "CommandName" ] ) ;
}
/ * Finally , if no name is given at all , use the standard process name .
* /
2012-02-19 11:59:22 +00:00
if ( nil = = cmdName )
{
ASSIGN ( cmdName , [ pinfo processName ] ) ;
}
/ *
* Make sure our users home directory exists .
* /
str = [ cmdDefs objectForKey : @ "UserDirectory" ] ;
str = cmdSetUserDirectory ( str ) ;
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 11:59:22 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "Unable to create directory - %@" , str ) ;
exit ( 1 ) ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "The path '%@' is not a directory" , str ) ;
exit ( 1 ) ;
}
str = [ cmdDefs objectForKey : @ "HomeDirectory" ] ;
if ( str ! = nil )
{
if ( [ str length ] = = 0 )
{
str = nil ;
}
else if ( [ str isAbsolutePath ] = = YES )
{
NSLog ( @ "Absolute HomeDirectory ignored." ) ;
str = nil ;
}
cmdSetHome ( str ) ;
}
for ( i = 0 ; i < 32 ; i + + )
{
switch ( i )
{
case SIGPROF :
case SIGABRT :
break ;
case SIGPIPE :
case SIGTTOU :
case SIGTTIN :
case SIGCHLD :
/ * SIGWINCH is generated when the terminal size
changes ( for example when you resize the xterm ) .
Ignore it . * /
# ifdef SIGWINCH
case SIGWINCH :
# endif
signal ( i , SIG_IGN ) ;
break ;
2013-08-19 09:05:07 +00:00
case SIGHUP :
if ( [ cmdDefs boolForKey : @ "Daemon" ] = = YES )
{
signal ( i , SIG_IGN ) ;
}
else
{
signal ( i , qhandler ) ;
}
break ;
2012-02-19 11:59:22 +00:00
case SIGINT :
case SIGTERM :
signal ( i , qhandler ) ;
break ;
case SIGSTOP :
case SIGCONT :
case SIGTSTP :
signal ( i , SIG_DFL ) ;
break ;
default :
signal ( i , ihandler ) ;
break ;
}
}
ASSIGN ( cmdInst , [ cmdDefs stringForKey : @ "Instance" ] ) ;
if ( nil ! = cmdInst )
{
str = [ [ NSString alloc ] initWithFormat : @ "%@-%@" , cmdName , cmdInst ] ;
ASSIGN ( cmdName , str ) ;
[ str release ] ;
}
str = userDir ;
if ( cmdHomeDir ( ) ! = nil )
{
str = [ str stringByAppendingPathComponent : cmdHomeDir ( ) ] ;
}
str = [ str stringByStandardizingPath ] ;
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-08-10 08:52:08 +00:00
if ( [ mgr createDirectoryAtPath : str
withIntermediateDirectories : YES
attributes : nil
error : NULL ] = = NO )
2012-02-19 11:59:22 +00:00
{
if ( [ mgr fileExistsAtPath : str isDirectory : & flag ] = = NO )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "Unable to create directory - %@" , str ) ;
exit ( 1 ) ;
}
}
else
{
flag = YES ;
}
}
if ( flag = = NO )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "The path '%@' is not a directory" , str ) ;
exit ( 1 ) ;
}
if ( [ mgr changeCurrentDirectoryPath : str ] = = NO )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "Unable to move to directory - %@" , str ) ;
exit ( 1 ) ;
}
/ *
* Make sure the data directory exists .
* /
if ( [ self cmdDataDirectory ] = = nil )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "Unable to create/access data directory" ) ;
exit ( 1 ) ;
}
/ *
* Make sure the logs directory exists .
* /
if ( cmdLogsDir ( nil ) = = nil )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
NSLog ( @ "Unable to create/access logs directory" ) ;
exit ( 1 ) ;
}
[ [ NSProcessInfo processInfo ] setProcessName : cmdName ] ;
/ * Archive any existing debug log left over by a crash .
* /
str = [ cmdName stringByAppendingPathExtension : @ "debug" ] ;
if ( cmdDebugName = = nil || [ cmdDebugName isEqual : str ] = = NO )
{
NSFileHandle * hdl ;
/ *
* Force archiving of old logfile .
* /
[ self cmdArchive : nil ] ;
ASSIGNCOPY ( cmdDebugName , str ) ;
hdl = [ self cmdLogFile : cmdDebugName ] ;
if ( hdl = = nil )
{
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
exit ( 1 ) ;
}
}
2013-11-04 07:28:57 +00:00
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
selector : @ selector ( cmdDefaultsChanged : )
name : NSUserDefaultsDidChangeNotification
object : [ NSUserDefaults standardUserDefaults ] ] ;
2014-09-16 18:57:07 +00:00
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
selector : @ selector ( ecLoggersChanged : )
name : EcLoggersDidChangeNotification
object : nil ] ;
2012-07-05 13:15:27 +00:00
[ self cmdMesgCache ] ;
2012-02-19 11:59:22 +00:00
2013-11-04 07:28:57 +00:00
[ self cmdDefaultsChanged : nil ] ;
2012-02-19 11:59:22 +00:00
cmdIsTransient = [ cmdDefs boolForKey : @ "Transient" ] ;
if ( [ cmdDefs objectForKey : @ "CmdInterval" ] ! = nil )
{
[ self setCmdInterval : [ cmdDefs floatForKey : @ "CmdInterval" ] ] ;
}
if ( YES = = [ self cmdIsClient ] && nil = = [ self cmdNewServer ] )
{
NSLog ( @ "Giving up - unable to contact '%@' server on '%@'" ,
2012-03-09 09:22:09 +00:00
ecCommandName ( ) , ecCommandHost ( ) ) ;
2012-02-19 11:59:22 +00:00
[ self release ] ;
self = nil ;
}
}
2012-03-09 09:22:09 +00:00
[ ecLock unlock ] ;
2012-02-19 11:59:22 +00:00
2012-06-12 07:55:08 +00:00
/ * Put self in background .
2012-02-19 11:59:22 +00:00
* /
if ( [ cmdDefs boolForKey : @ "Daemon" ] = = YES )
{
int pid = fork ( ) ;
if ( pid = = 0 )
{
cmdFlagDaemon = YES ;
setpgid ( 0 , getpid ( ) ) ;
}
else
{
if ( pid < 0 )
{
printf ( "Failed fork to run as daemon.\r\n" ) ;
}
else
{
printf ( "Process backgrounded (running as daemon)\r\n" ) ;
}
exit ( 0 ) ;
}
}
2012-06-12 07:55:08 +00:00
/ * And make sure that regular timers run .
* /
[ self triggerCmdTimeout ] ;
2012-02-19 11:59:22 +00:00
return self ;
}
/ *
* Implement the CmdConfig protocol .
* /
- ( void ) replaceFile : ( NSData * ) data
name : ( NSString * ) name
isConfig : ( BOOL ) f
{
[ NSException raise : NSGenericException
format : @ "Illegal method call" ] ;
}
2015-01-26 12:50:42 +00:00
- ( oneway void ) requestConfigFor : ( id < CmdConfig > ) c
2012-02-19 11:59:22 +00:00
{
[ NSException raise : NSGenericException
format : @ "Illegal method call" ] ;
}
- ( void ) requestFile : ( BOOL ) flag
name : ( NSString * ) name
for : ( id < CmdConfig > ) c
{
[ NSException raise : NSGenericException
format : @ "Illegal method call" ] ;
}
2015-01-26 12:50:42 +00:00
- ( oneway void ) updateConfig : ( in bycopy NSData * ) info
2012-02-19 11:59:22 +00:00
{
id plist = [ NSPropertyListSerialization
propertyListWithData : info
options : NSPropertyListMutableContainers
format : 0
error : 0 ] ;
if ( nil ! = plist )
{
2012-11-23 12:45:09 +00:00
[ self _update : plist ] ;
2012-02-19 11:59:22 +00:00
}
}
- ( id ) server : ( NSString * ) serverName
{
RemoteServer * server ;
server = ( RemoteServer * ) [ servers objectForKey : serverName ] ;
if ( server = = nil )
{
NSLog ( @ "Trying to ask for not-existent server %@" , serverName ) ;
return nil ;
}
return [ server proxy ] ;
}
- ( id ) server : ( NSString * ) serverName forNumber : ( NSString * ) num
{
RemoteServer * server ;
NSArray * config ;
server = ( RemoteServer * ) [ servers objectForKey : serverName ] ;
if ( server = = nil )
{
NSLog ( @ "Trying to ask for not-existent server %@" , serverName ) ;
return nil ;
}
config = [ server multiple ] ;
if ( config ! = nil && [ config count ] > 1 )
{
int val = -1 ;
unsigned count = [ config count ] ;
/ *
* Get trailing two digits of number . . . in range 00 to 99
* /
if ( [ num length ] >= 2 )
{
val = [ [ num substringFromIndex : [ num length ] - 2 ] intValue ] ;
}
if ( val < 0 )
{
val = 0 ;
}
/ *
* Try to find a broadcast server with a numeric range matching
* the number we were given .
* /
while ( count - - > 0 )
{
NSDictionary * d = [ config objectAtIndex : count ] ;
if ( val >= [ [ d objectForKey : @ "Low" ] intValue ]
&& val <= [ [ d objectForKey : @ "High" ] intValue ] )
{
return [ [ server proxy ] BCPproxy : count ] ;
}
}
[ self cmdError : @ "Attempt to get %@ server for number %@ with bad config" ,
serverName , num ] ;
return nil ;
}
return [ server proxy ] ;
}
- ( BOOL ) isServerMultiple : ( NSString * ) serverName
{
RemoteServer * server ;
server = ( RemoteServer * ) [ servers objectForKey : serverName ] ;
if ( server = = nil )
{
NSLog ( @ "Trying to ask for not-existent server %@" , serverName ) ;
return NO ;
}
return ( [ server multiple ] = = nil ) ? NO : YES ;
}
2013-07-13 07:58:07 +00:00
2012-02-19 11:59:22 +00:00
@ end
@ implementation EcProcess ( Private )
- ( void ) cmdMesgrelease : ( NSArray * ) msg
{
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "controls double release memory error detection" ] ;
return ;
}
if ( [ [ msg objectAtIndex : 0 ] caseInsensitiveCompare : @ "help" ] = = NSOrderedSame )
{
[ self cmdPrintf : @ "controls double release memory error detection\n" ] ;
2013-04-23 12:43:39 +00:00
[ self cmdPrintf : @ "to report if an object is released too many times.\n" ] ;
2012-02-19 11:59:22 +00:00
[ self cmdPrintf : @ "This has a big impact on program performance.\n" ] ;
[ self cmdPrintf : @ "'release yes' turns on checking\n" ] ;
[ self cmdPrintf : @ "'release no' turns off checking\n" ] ;
[ self cmdPrintf : @ "'release default' reverts to default setting\n" ] ;
[ self cmdPrintf : @ "'release' reports current status\n" ] ;
return ;
}
if ( [ msg count ] = = 1 )
{
[ self cmdPrintf : @ "Double release checking: %s\n" ,
[ cmdDefs boolForKey : @ "Release" ] ? "YES" : "NO" ] ;
}
if ( [ msg count ] > 1 )
{
if ( [ [ msg objectAtIndex : 1 ] caseInsensitiveCompare : @ "default" ]
= = NSOrderedSame )
{
[ cmdDefs setCommand : nil forKey : @ "Release" ] ;
}
else
{
[ cmdDefs setCommand : [ msg objectAtIndex : 1 ] forKey : @ "Release" ] ;
}
[ self cmdPrintf : @ "Double release checking: %s\n" ,
[ cmdDefs boolForKey : @ "Release" ] ? "YES" : "NO" ] ;
}
}
- ( void ) cmdMesgtesting : ( NSArray * ) msg
{
if ( [ msg count ] = = 0 )
{
[ self cmdPrintf : @ "controls whether server is running in testing mode" ] ;
return ;
}
if ( [ [ msg objectAtIndex : 0 ] caseInsensitiveCompare : @ "help" ] = = NSOrderedSame )
{
[ self cmdPrintf : @ "controls whether server is running in testing mode\n" ] ;
[ self cmdPrintf : @ "Behavior in testing mode is server dependent.\n" ] ;
[ self cmdPrintf : @ "'testing yes' turns on testing mode\n" ] ;
[ self cmdPrintf : @ "'testing no' turns off testing mode\n" ] ;
[ self cmdPrintf : @ "'testing default' reverts to default setting\n" ] ;
[ self cmdPrintf : @ "'testing' reports current status\n" ] ;
return ;
}
if ( [ msg count ] = = 1 )
{
[ self cmdPrintf : @ "Server running in testing mode: %s\n" ,
cmdFlagTesting ? "YES" : "NO" ] ;
}
if ( [ msg count ] > 1 )
{
if ( [ [ msg objectAtIndex : 1 ] caseInsensitiveCompare : @ "default" ]
= = NSOrderedSame )
{
2013-04-23 12:41:30 +00:00
[ cmdDefs setCommand : nil forKey : @ "Testing" ] ;
2012-02-19 11:59:22 +00:00
}
else
{
2013-04-23 12:41:30 +00:00
[ cmdDefs setCommand : [ msg objectAtIndex : 1 ] forKey : @ "Testing" ] ;
2012-02-19 11:59:22 +00:00
}
[ self cmdPrintf : @ "Server running in testing mode: %s\n" ,
cmdFlagTesting ? "YES" : "NO" ] ;
}
}
2015-07-08 09:06:26 +00:00
- ( void ) _memCheck
{
BOOL memDebug = [ cmdDefs boolForKey : @ "Memory" ] ;
FILE * fptr ;
int i ;
/ * / proc / pid / statm reports the process memory size in 4 KB pages
* /
fptr = fopen ( [ [ NSString stringWithFormat : @ "/proc/%d/statm" ,
[ [ NSProcessInfo processInfo ] processIdentifier ] ] UTF8String ] , "r" ) ;
memLast = 1 ;
if ( NULL ! = fptr )
{
if ( fscanf ( fptr , "%" PRIu64 , & memLast ) ! = 1 )
{
memLast = 1 ;
}
else
{
memLast * = ( 4 * 1024 ) ;
if ( memLast <= 0 ) memLast = 1 ;
}
fclose ( fptr ) ;
}
/ * Do initial population so we can work immediately .
* /
if ( 0 = = memSlot )
{
for ( i = 1 ; i < MEMCOUNT ; i + + )
{
memRoll [ i ] = memLast ;
}
memPrev = memStrt = memLast ;
}
memRoll [ memSlot % MEMCOUNT ] = memLast ;
memSlot + + ;
/ * Find the average usage over the last set of samples .
* Round up to a block size .
* /
memAvge = 0 ;
for ( i = 0 ; i < MEMCOUNT ; i + + )
{
memAvge + = memRoll [ i ] ;
}
memAvge / = MEMCOUNT ;
/ * Convert to 1 KB blocks .
* /
if ( memAvge % 1024 )
{
memAvge = ( ( memAvge / 1024 ) + 1 ) * 1024 ;
}
/ * Update peak memory usage if necessary .
* /
if ( memLast > memPeak )
{
memPeak = memLast ;
}
/ * If we have a defined maximum memory usage for the process ,
* we should shut down with a non - zero status to get a restart .
* /
if ( memMaximum > 0 && memPeak > ( memMaximum * 1024 * 1024 ) )
{
if ( NO = = cmdIsQuitting )
{
cmdIsQuitting = YES ;
[ self cmdQuit : -1 ] ;
}
return ;
}
/ * If the average memory usage is above the threshold , we alert and reset
* the threshold .
* During the first ten minutes though , we always adjust the threshold and
* we suppress any warnings . This gives us a more stable starting point .
* /
if ( memAvge > memWarn || memSlot < MEMCOUNT )
{
NSInteger inc ;
NSInteger pct ;
NSInteger iMax = 0 ;
NSInteger pMax = 0 ;
/ * We increase the threshold for the next alert by a percentage
* of the existing usage or by a fixed increment , whichever is
* the larger .
* /
pct = [ cmdDefs integerForKey : @ "MemoryPercentage" ] ;
if ( pct < 1 || pct > 1000 ) pct = 0 ;
inc = [ cmdDefs integerForKey : @ "MemoryIncrement" ] ;
if ( inc < 10 || inc > 1000000 ) inc = 0 ;
if ( 0 = = inc && 0 = = pct )
{
if ( YES = = memDebug )
{
/ * We want detailed memory information , so we set the next
* alerting threshold 50 KB above the current peak usage .
* /
inc = 50 ;
pct = 0 ;
}
else
{
/ * We do not want detailed memory information ,
* so we set the next alerting threshold from
* 5000 KB above the current peak usage ,
* ensuring that only serious increases
* in usage will generate an alert .
* /
inc = 5000 ;
pct = 10 ; // Use ten percent if more than fixed increment
}
}
if ( inc > 0 )
{
iMax = memPeak + ( inc * 1024 ) ;
}
if ( pct > 0 )
{
pMax = ( memPeak * ( 100 + pct ) ) / 100 ;
}
memWarn = ( iMax > pMax ) ? iMax : pMax ;
if ( memWarn % 1024 )
{
memWarn = ( memWarn / 1024 + 1 ) * 1024 ;
}
if ( memWarn < memAllowed * 1024 * 1024 )
{
/ * Never warn at less than the allowed memory .
* /
memWarn = memAllowed * 1024 * 1024 ;
}
/ * If not in the initial period , we need to generate an alert
* because the average has risen above the allowed size .
* /
if ( memSlot >= MEMCOUNT )
{
uint64_t prev ;
NSDate * when ;
prev = memPrev ;
when = AUTORELEASE ( memTime ) ;
memPrev = memAvge ;
memTime = [ NSDate new ] ;
if ( nil = = when )
{
[ self cmdError : @ "Average memory usage grown from %"
PRIu64 "KB to %" PRIu64 "KB (reserved: %" PRIu64 "KB)" ,
prev / 1024 , memAvge / 1024 , [ self ecNotLeaked ] / 1024 ] ;
}
else
{
[ self cmdError : @ "Average memory usage grown from %"
PRIu64 "KB to %" PRIu64 "KB (reserved: %" PRIu64 "KB) since %@" ,
prev / 1024 , memAvge / 1024 , [ self ecNotLeaked ] / 1024 , when ] ;
}
}
}
if ( YES = = memDebug )
{
[ self cmdDbg : cmdDetailDbg
msg : @ "Memory usage %" PRIu64 "KB (reserved: %" PRIu64 "KB)" ,
memLast / 1024 , [ self ecNotLeaked ] / 1024 ] ;
}
}
2012-02-19 11:59:22 +00:00
- ( NSString * ) _moveLog : ( NSString * ) name to : ( NSString * ) sub
{
NSString * status ;
NSString * where ;
NS_DURING
{
where = cmdLogsDir ( sub ) ;
if ( where ! = nil )
{
NSFileManager * mgr = [ NSFileManager defaultManager ] ;
NSString * from ;
NSString * path ;
NSString * base ;
NSString * gzpath ;
unsigned count = 0 ;
path = [ where stringByAppendingPathComponent : name ] ;
from = [ cmdLogsDir ( nil ) stringByAppendingPathComponent : name ] ;
/ *
* Check for pre - existing file - if found , try another .
* /
base = path ;
path = [ base stringByAppendingPathExtension : @ "0" ] ;
gzpath = [ path stringByAppendingPathExtension : @ "gz" ] ;
while ( [ mgr fileExistsAtPath : path ] = = YES
|| [ mgr fileExistsAtPath : gzpath ] = = YES )
{
NSString * ext ;
ext = [ stringClass stringWithFormat : @ "%u" , + + count ] ;
path = [ base stringByAppendingPathExtension : ext ] ;
gzpath = [ path stringByAppendingPathExtension : @ "gz" ] ;
}
if ( [ mgr movePath : from
toPath : path
handler : nil ] = = NO )
{
status = [ NSString stringWithFormat :
@ "Unable to move %@ to %@" , from , path ] ;
}
else
{
status = [ NSString stringWithFormat :
@ "Moved %@ to %@" , from , path ] ;
}
}
else
{
status = [ NSString stringWithFormat :
@ "Unable to archive log %@ into %@" , name , sub ] ;
}
}
NS_HANDLER
{
status = [ NSString stringWithFormat : @ "Problem in %@ with %@ to %@ - %@" ,
NSStringFromSelector ( _cmd ) , name , sub , localException ] ;
}
NS_ENDHANDLER
return status ;
}
- ( void ) _timedOut : ( NSTimer * ) timer
{
static BOOL inProgress = NO ;
2012-02-19 14:42:50 +00:00
int sig = [ self cmdSignalled ] ;
2012-02-19 11:59:22 +00:00
cmdPTimer = nil ;
if ( sig > 0 )
{
2013-08-20 14:35:26 +00:00
cmdIsQuitting = YES ;
2012-02-19 11:59:22 +00:00
[ self cmdQuit : sig ] ;
}
2014-05-16 22:13:43 +00:00
if ( YES = = cmdIsQuitting )
{
NSLog ( @ "_timedOut: ignored because process is quitting" ) ;
}
else if ( YES = = inProgress )
2012-02-19 11:59:22 +00:00
{
NSLog ( @ "_timedOut: ignored because timeout already in progress" ) ;
}
else
{
BOOL delay = NO ;
inProgress = YES ;
2014-05-16 22:13:43 +00:00
/ * We only perform timeouts if the process is actually
* running ( don ' t want them during startup before the
* thing is fully initialised .
* So if not running , skip to scheduling next timeout .
* /
if ( YES = = cmdIsRunning )
{
NS_DURING
{
NSCalendarDate * now = [ NSCalendarDate date ] ;
static int lastDay = 0 ;
static int lastHour = 0 ;
static int lastMinute = 0 ;
static int lastTenSecond = 0 ;
BOOL newDay = NO ;
BOOL newHour = NO ;
BOOL newMinute = NO ;
BOOL newTenSecond = NO ;
int i ;
i = [ now dayOfWeek ] ;
if ( i ! = lastDay )
{
lastDay = i ;
newDay = YES ;
newHour = YES ;
newMinute = YES ;
newTenSecond = YES ;
}
i = [ now hourOfDay ] ;
if ( i ! = lastHour )
{
lastHour = i ;
newHour = YES ;
newMinute = YES ;
newTenSecond = YES ;
}
i = [ now minuteOfHour ] ;
if ( i ! = lastMinute )
{
lastMinute = i ;
newMinute = YES ;
newTenSecond = YES ;
}
i = [ now secondOfMinute ] / 10 ;
if ( i ! = lastTenSecond )
{
lastTenSecond = i ;
newTenSecond = YES ;
}
if ( YES = = newTenSecond )
{
[ self cmdNewServer ] ;
}
if ( YES = = newMinute )
{
[ self ecNewMinute : now ] ;
}
if ( YES = = newHour )
{
[ self ecNewHour : now ] ;
}
if ( YES = = newDay )
{
[ self ecNewDay : now ] ;
}
if ( cmdTimSelector ! = 0 )
{
[ self performSelector : cmdTimSelector ] ;
}
}
NS_HANDLER
{
2015-05-14 13:47:30 +00:00
NSLog ( @ "Exception performing regular timeout: %@" ,
localException ) ;
2014-05-16 22:13:43 +00:00
delay = YES ; // Avoid runaway logging .
}
NS_ENDHANDLER
}
2012-02-19 11:59:22 +00:00
if ( cmdPTimer = = nil )
{
NSTimeInterval when = cmdTimInterval ;
if ( delay = = YES && when < 1.0 )
{
when = 10.0 ;
}
cmdPTimer =
[ NSTimer scheduledTimerWithTimeInterval : when
target : self
selector : @ selector ( _timedOut : )
userInfo : nil
repeats : NO ] ;
}
inProgress = NO ;
}
}
2012-11-23 12:45:09 +00:00
- ( void ) _update : ( NSMutableDictionary * ) info
{
NSMutableDictionary * newConfig ;
NSDictionary * dict ;
NSEnumerator * enumerator ;
NSString * key ;
newConfig = [ NSMutableDictionary dictionaryWithCapacity : 32 ] ;
/ *
* Put all values for this application in the cmdConf dictionary .
* /
dict = [ info objectForKey : cmdLogName ( ) ] ;
if ( dict ! = nil )
{
enumerator = [ dict keyEnumerator ] ;
while ( ( key = [ enumerator nextObject ] ) ! = nil )
{
id obj ;
if ( [ noNetConfig containsObject : key ] )
{
[ self cmdWarn : @ "Bad key '%@' in net config." , key ] ;
continue ;
}
obj = [ dict objectForKey : key ] ;
[ newConfig setObject : obj forKey : key ] ;
}
}
/ *
* Add any default values to the cmdConf
* dictionary where we don ' t have application
* specific values .
* /
dict = [ info objectForKey : @ "*" ] ;
if ( dict )
{
enumerator = [ dict keyEnumerator ] ;
while ( ( key = [ enumerator nextObject ] ) ! = nil )
{
if ( [ newConfig objectForKey : key ] = = nil )
{
id obj ;
if ( [ noNetConfig containsObject : key ] )
{
[ self cmdWarn : @ "Bad key '%@' in net config." , key ] ;
continue ;
}
obj = [ dict objectForKey : key ] ;
[ newConfig setObject : obj forKey : key ] ;
}
}
}
dict = [ info objectForKey : @ "Operators" ] ;
if ( dict ! = nil && dict ! = cmdOperators )
{
ASSIGNCOPY ( cmdOperators , dict ) ;
}
if ( nil = = cmdConf || [ cmdConf isEqual : newConfig ] = = NO )
{
2013-11-04 07:28:57 +00:00
NSString * err = nil ;
2013-03-13 10:08:13 +00:00
2012-11-23 12:45:09 +00:00
NS_DURING
[ self cmdUpdate : newConfig ] ;
NS_HANDLER
2013-11-04 07:28:57 +00:00
NSLog ( @ "Problem before updating config (in cmdUpdate:) %@" ,
localException ) ;
err = @ "the -cmdUpdate: method raised an exception" ;
2012-11-23 12:45:09 +00:00
NS_ENDHANDLER
2013-11-04 07:28:57 +00:00
if ( nil = = err )
{
NS_DURING
err = [ self cmdUpdated ] ;
NS_HANDLER
NSLog ( @ "Problem after updating config (in cmdUpdated) %@" ,
localException ) ;
err = @ "the -cmdUpdated method raised an exception" ;
NS_ENDHANDLER
}
2013-03-13 10:27:45 +00:00
if ( [ err length ] > 0 )
2013-03-13 10:08:13 +00:00
{
EcAlarm * a ;
2013-03-13 10:27:45 +00:00
/ * Truncate additional text to fit if necessary .
* /
err = [ err stringByTrimmingSpaces ] ;
if ( [ err length ] > 255 )
{
err = [ err substringToIndex : 255 ] ;
while ( 255 < strlen ( [ err UTF8String ] ) )
{
err = [ err substringToIndex : [ err length ] - 1 ] ;
}
}
2013-03-13 10:08:13 +00:00
a = [ EcAlarm alarmForManagedObject : nil
at : nil
withEventType : EcAlarmEventTypeProcessingError
probableCause : EcAlarmConfigurationOrCustomizationError
2013-12-09 21:55:18 +00:00
specificProblem : @ "Fatal configuration error"
2013-03-13 10:08:13 +00:00
perceivedSeverity : EcAlarmSeverityMajor
2013-03-13 10:27:45 +00:00
proposedRepairAction :
_ ( @ "Correct config (check additional text and/or log for details)." )
2013-03-13 10:08:13 +00:00
additionalText : err ] ;
[ self alarm : a ] ;
[ alarmDestination shutdown ] ;
2013-08-20 14:35:26 +00:00
cmdIsQuitting = YES ;
2013-03-13 10:08:13 +00:00
[ self cmdQuit : 1 ] ;
}
else
{
2014-09-10 10:36:53 +00:00
[ self clearConfigurationFor : nil
specificProblem : @ "Fatal configuration error"
additionalText : @ "Configuration updated" ] ;
2013-03-13 10:08:13 +00:00
}
2012-11-23 12:45:09 +00:00
}
}
2012-02-19 11:59:22 +00:00
@ end
2014-03-28 08:07:59 +00:00
@ implementation EcProcess ( Test )
- ( bycopy NSString * ) ecTestCommand : ( in bycopy NSString * ) command
{
NSEnumerator * enumerator ;
NSMutableArray * words ;
NSString * word ;
command = [ command stringByTrimmingSpaces ] ;
words = [ NSMutableArray arrayWithCapacity : 16 ] ;
enumerator = [ [ command componentsSeparatedByString : @ " " ] objectEnumerator ] ;
while ( ( word = [ enumerator nextObject ] ) ! = nil )
{
[ words addObject : [ word stringByTrimmingSpaces ] ] ;
}
if ( [ words count ] = = 0 )
{
return nil ;
}
return [ self cmdMesg : words ] ;
}
- ( bycopy NSData * ) ecTestConfigForKey : ( in bycopy NSString * ) key
{
id result = [ cmdDefs objectForKey : key ] ;
if ( nil ! = result )
{
result = [ NSPropertyListSerialization
dataFromPropertyList : result
format : NSPropertyListBinaryFormat_v1 _0
errorDescription : 0 ] ;
}
return result ;
}
- ( void ) ecTestSetConfig : ( in bycopy NSData * ) data
forKey : ( in bycopy NSString * ) key
{
id val ;
if ( nil = = data )
{
val = data ;
}
else
{
val = [ NSPropertyListSerialization
propertyListWithData : data
options : NSPropertyListMutableContainers
format : 0
error : 0 ] ;
}
[ cmdDefs setCommand : val forKey : key ] ;
}
@ end
2014-11-02 14:30:24 +00:00
@ implementation EcProcess ( Defaults )
- ( void ) _defMemory : ( id ) val
{
2015-07-09 12:08:58 +00:00
BOOL stats = [ val boolValue ] ;
GSDebugAllocationActive ( stats ) ;
if ( YES = = stats && nil = = memStats )
{
ASSIGN ( memStats , [ NSDate date ] ) ;
}
if ( NO = = stats && nil ! = memStats )
{
DESTROY ( memStats ) ;
}
2014-11-02 14:30:24 +00:00
}
- ( void ) _defRelease : ( id ) val
{
[ NSObject enableDoubleReleaseCheck : [ val boolValue ] ] ;
}
- ( void ) _defTesting : ( id ) val
{
cmdFlagTesting = [ val boolValue ] ;
}
@ end
@ implementation EcDefaultRegistration
static NSMutableDictionary * regDefs = nil ;
+ ( void ) defaultsChanged : ( NSUserDefaults * ) defs
{
NSEnumerator * e ;
NSString * n ;
[ ecLock lock ] ;
e = [ [ regDefs allKeys ] objectEnumerator ] ;
[ ecLock unlock ] ;
while ( nil ! = ( n = [ e nextObject ] ) )
{
EcDefaultRegistration * d ;
id o = nil ;
SEL c = NULL ;
[ ecLock lock ] ;
d = [ regDefs objectForKey : n ] ;
if ( nil ! = d )
{
o = [ defs objectForKey : n ] ;
if ( o ! = d -> obj && NO = = [ o isEqual : d -> obj ] )
{
ASSIGNCOPY ( d -> obj , o ) ;
o = d -> obj ;
c = d -> cmd ;
}
}
[ ecLock unlock ] ;
if ( NULL ! = c && [ EcProc respondsToSelector : c ] )
{
[ EcProc performSelector : c withObject : o ] ;
}
}
}
+ ( void ) initialize
{
regDefs = [ NSMutableDictionary new ] ;
}
+ ( void ) registerDefault : ( NSString * ) name
withTypeText : ( NSString * ) type
andHelpText : ( NSString * ) help
action : ( SEL ) cmd
{
static NSCharacterSet * w = nil ;
EcDefaultRegistration * d ;
if ( nil = = w )
{
w = RETAIN ( [ NSCharacterSet whitespaceAndNewlineCharacterSet ] ) ;
}
if ( [ type length ] > 0 )
{
type = [ type stringByTrimmingSpaces ] ;
if ( [ type length ] = = 0 )
{
type = nil ;
}
else
{
NSUInteger length = [ type length ] ;
NSMutableString * m = nil ;
while ( length - - > 0 )
{
unichar u = [ type characterAtIndex : length ] ;
if ( u ! = ' ' && [ w characterIsMember : u ] )
{
if ( nil = = m )
{
m = AUTORELEASE ( [ type mutableCopy ] ) ;
type = m ;
}
[ m replaceCharactersInRange : NSMakeRange ( length , 1 )
withString : @ " " ] ;
}
}
}
}
if ( [ help length ] > 0 )
{
help = [ help stringByTrimmingSpaces ] ;
if ( [ help length ] = = 0 )
{
help = nil ;
}
}
[ ecLock lock ] ;
d = [ regDefs objectForKey : name ] ;
if ( nil = = d )
{
d = [ EcDefaultRegistration new ] ;
ASSIGNCOPY ( d -> name , name ) ;
[ regDefs setObject : d forKey : d -> name ] ;
RELEASE ( d ) ;
}
ASSIGNCOPY ( d -> type , type ) ;
ASSIGNCOPY ( d -> help , help ) ;
if ( 0 ! = cmd )
{
d -> cmd = cmd ;
}
[ ecLock unlock ] ;
}
+ ( void ) showHelp
{
NSArray * keys ;
NSString * prf ;
NSEnumerator * e ;
NSString * k ;
NSUInteger max = 0 ;
prf = EC_DEFAULTS _PREFIX ;
if ( nil = = prf )
{
prf = @ "" ;
}
keys = [ regDefs allKeys ] ;
e = [ keys objectEnumerator ] ;
while ( nil ! = ( k = [ e nextObject ] ) )
{
EcDefaultRegistration * d = [ regDefs objectForKey : k ] ;
if ( nil ! = d -> type && nil ! = d -> help )
{
NSUInteger length = [ prf length ] + 5 ;
length + = [ k length ] + [ d -> type length ] ;
if ( length > max )
{
max = length ;
}
}
}
keys = [ keys sortedArrayUsingSelector : @ selector ( compare : ) ] ;
e = [ keys objectEnumerator ] ;
while ( nil ! = ( k = [ e nextObject ] ) )
{
EcDefaultRegistration * d = [ regDefs objectForKey : k ] ;
if ( nil ! = d -> type && nil ! = d -> help )
{
/ * If the help text is short enough , put it all on one line .
* /
if ( [ d -> help length ] + max < 80 )
{
NSMutableString * m ;
m = [ NSMutableString stringWithFormat : @ "-%@%@ [%@] " ,
prf , k , d -> type ] ;
while ( [ m length ] < max )
{
[ m appendString : @ " " ] ;
}
GSPrintf ( stderr , @ "%@%@\n" , m , d -> help ) ;
}
else
{
GSPrintf ( stderr , @ "-%@%@ [%@]\n %@\n" , prf , k , d -> type , d -> help ) ;
}
}
}
}
- ( void ) dealloc
{
RELEASE ( name ) ;
RELEASE ( type ) ;
RELEASE ( help ) ;
RELEASE ( obj ) ;
[ super dealloc ] ;
}
@ end