diff --git a/EcAlarm.m b/EcAlarm.m
index 2781a38..26febb9 100644
--- a/EcAlarm.m
+++ b/EcAlarm.m
@@ -467,19 +467,38 @@ EcMakeManagedObject(NSString *host, NSString *process, NSString *component)
{
Class c = [self class];
- return [NSString stringWithFormat:
- @"Alarm %-8d %@ %@ %@ %@ %@ at %@(%@) %@ %@ %@",
- _notificationID,
- _managedObject,
- [c stringFromEventType: _eventType],
- [c stringFromProbableCause: _probableCause],
- [c stringFromSeverity: _perceivedSeverity],
- [c stringFromTrend: _trendIndicator],
- _eventDate,
- _firstEventDate,
- _specificProblem,
- _proposedRepairAction,
- _additionalText];
+ if (0 == _notificationID)
+ {
+ return [NSString stringWithFormat:
+ @"Alarm addr: %-16" PRIx64 " %@ %@ %@ %@ %@ at %@(%@) %@ %@ %@",
+ (uint64_t)(uintptr_t)self,
+ _managedObject,
+ [c stringFromEventType: _eventType],
+ [c stringFromProbableCause: _probableCause],
+ [c stringFromSeverity: _perceivedSeverity],
+ [c stringFromTrend: _trendIndicator],
+ _eventDate,
+ _firstEventDate,
+ _specificProblem,
+ _proposedRepairAction,
+ _additionalText];
+ }
+ else
+ {
+ return [NSString stringWithFormat:
+ @"Alarm notification: %-8d %@ %@ %@ %@ %@ at %@(%@) %@ %@ %@",
+ _notificationID,
+ _managedObject,
+ [c stringFromEventType: _eventType],
+ [c stringFromProbableCause: _probableCause],
+ [c stringFromSeverity: _perceivedSeverity],
+ [c stringFromTrend: _trendIndicator],
+ _eventDate,
+ _firstEventDate,
+ _specificProblem,
+ _proposedRepairAction,
+ _additionalText];
+ }
}
- (void) encodeWithCoder: (NSCoder*)aCoder
diff --git a/EcLogger.m b/EcLogger.m
index f8b4234..d8ec218 100644
--- a/EcLogger.m
+++ b/EcLogger.m
@@ -82,7 +82,12 @@ static NSArray *modes;
logger->interval = 10;
logger->size = 8 * 1024;
logger->message = [[NSMutableString alloc] initWithCapacity: 2048];
- [EcProc setCmdUpdate: logger withMethod: @selector(update)];
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver: self
+ selector: @selector(update)
+ name: NSUserDefaultsDidChangeNotification
+ object: [EcProc cmdDefaults]];
[logger update];
[loggers addObject: logger];
RELEASE(logger);
@@ -133,6 +138,7 @@ static NSArray *modes;
{
[self flush];
[timer invalidate];
+ [[NSNotificationCenter defaultCenter] removeObserver: self];
RELEASE(key);
RELEASE(flushKey);
RELEASE(serverKey);
@@ -479,13 +485,22 @@ static NSArray *modes;
[self _flush];
}
-/* Should only be called on main thread.
+/* Should only execute on main thread.
*/
- (void) update
{
- NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
+ NSUserDefaults *defs;
NSString *str;
+ if (NO == [NSThread isMainThread])
+ {
+ [self performSelectorOnMainThread: @selector(update)
+ withObject: nil
+ waitUntilDone: NO
+ modes: modes];
+ return;
+ }
+ defs = [EcProc cmdDefaults];
/*
* If there is a server specified for this debug logger, we want it
* registered so we can use it - otherwise we will default to using
diff --git a/EcProcess.h b/EcProcess.h
index fd2bd31..1768700 100644
--- a/EcProcess.h
+++ b/EcProcess.h
@@ -181,12 +181,16 @@ typedef enum {
from: (NSString*)c;
/** Shut down the Command server and all its clients */
- (oneway void) terminate;
-/** An exceptional method and can be used without registering first
- * (ie, can be used by anyone, not only clients of the Command server).
- * It's meant to be used remotely by java servlets, and all sort of
+
+/** This is an exceptional method which may be used without registering
+ * your process with a Command server first (ie, it can be used by anyone,
+ * not only clients of the Command server).
+ * It's meant to be used remotely by Java servlets, and all sort of
* software running on the machine and which is *not* a full Command
* client (ie, a subclass of EcProcess) but which still wants to retrieve
- * configuration from a central location (the Control/Command servers).
+ * configuration from a central location (the Control/Command servers).
+ * The returned value is a a serialized property list ... you need to
+ * deserialize using the standard GNUstep property list APIs.
* NB: The configuration might change later on, so you must not cache
* the configuration after asking for it, but rather ask for it each
* time your software needs it.
@@ -391,7 +395,8 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) cmdAlert: (NSString*)fmt arguments: (va_list)args;
-/** Send a SEVERE error message to the server.
+/** Send a SEVERE error message to the server by calling the
+ * -cmdAlert:arguments: method.
*/
- (void) cmdAlert: (NSString*)fmt, ...;
@@ -406,7 +411,7 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) cmdAudit: (NSString*)fmt arguments: (va_list)args;
-/** Send a log message to the server.
+/** Send a log message to the server by calling the -cmdAudit:arguments: method.
*/
- (void) cmdAudit: (NSString*)fmt, ...;
@@ -425,22 +430,29 @@ extern NSString* cmdVersion(NSString *ver);
- (void) cmdDbg: (NSString*)type msg: (NSString*)fmt arguments: (va_list)args;
/** Send a debug message - as long as the debug mode specified as 'type'
- * is currently set.
+ * is currently set. Operates by calling the -cmdDbg:msg:arguments: method.
*/
- (void) cmdDbg: (NSString*)type msg: (NSString*)fmt, ...;
-/** Send a debug message with debug mode 'defaultMode'.
+/** Send a debug message with debug mode 'defaultMode'.
+ * Calls the -cmdDbg:msg:arguments: method.
*/
- (void) cmdDebug: (NSString*)fmt arguments: (va_list)args;
-/** Send a debug message with debug mode 'defaultMode'.
+/** Send a debug message with debug mode 'defaultMode'.
+ * Operates by calling the -cmdDebug:arguments: method.
*/
- (void) cmdDebug: (NSString*)fmt, ...;
/** Called whenever the user defaults are updated due to a central
* configuration change (or another defaults system change).
+ * This is also called by -cmdUpdate: even if no configuration
+ * actually changed ... in which case the notification argument
+ * is nil.
* If you override this to handle configuration changes, don't forget
- * to call the superclass implementation.
+ * to call the superclass implementation.
+ * This method is provided to allow subclasses to control the order
+ * in which defaults changes are handled by them and their superclasses.
*/
- (void) cmdDefaultsChanged: (NSNotification*)n;
@@ -448,11 +460,12 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) cmdError: (NSString*)fmt arguments: (va_list)args;
-/** Send an error message to the server.
+/** Send an error message to the server by calling the
+ * -cmdError:arguments: method.
*/
- (void) cmdError: (NSString*)fmt, ...;
-/** Flush logging information
+/** Flush logging information.
*/
- (void) cmdFlushLogs;
@@ -465,12 +478,13 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (BOOL) cmdIsClient;
-/** Returns a fag indicating whether this process is currently connected
+/** Returns a flag indicating whether this process is currently connected
* it its Command server.
*/
- (BOOL) cmdIsConnected;
-/** Returns YES is the process is running in test mode, NO otherwise.
+/** Returns YES is the process is running in test mode, NO otherwise.
+ * Test mode is defined by the EcTesting user default.
*/
- (BOOL) cmdIsTesting;
@@ -505,10 +519,10 @@ extern NSString* cmdVersion(NSString *ver);
* array).
* There are two special cases ... when the operator types 'help XXX' your
* method will be called with 'help'as the first element of the array and
- * you should respond with some useful hep text, and when the operator
+ * you should respond with some useful help text, and when the operator
* simply wants a short description of what the command does, the array
* argument will be nil (and your method should respond with a short
- * description of the cmmand).
+ * description of the command).
*/
- (NSString*) cmdMesg: (NSArray*)msg;
@@ -525,7 +539,9 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (NSMutableDictionary*)cmdOperator: (NSString*)name password: (NSString*)pass;
-/** Used to tell your application to quit.
+/** Used to tell your application to quit.
+ * Subclasses should override this method to perform any pre-shutdown cleanup
+ * before they call the superclass implementation.
*/
- (void) cmdQuit: (NSInteger)status;
@@ -533,11 +549,32 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (int) cmdSignalled;
-/** Used to tell your application about configuration changes.
+/** Used to tell your application about configuration changes.
+ * This is called before the NSUserDefaults system is updated with the
+ * changes, so you may use it to update internal state in the knowledge
+ * that code watching for user defaults change notifications will not
+ * have updated yet.
+ * The base class implementation is responsible for updating the user
+ * defaults system ... so be sure that your implementation calls the
+ * superclass implementation (unless you wish to suppress the configuration
+ * update).
+ * You may alter the info dictionary prior to passign it to the superclass
+ * implementation if you wish to adjust the new configuration before it
+ * takes effect.
*/
- (void) cmdUpdate: (NSMutableDictionary*)info;
-
+/** Used to tell your application about configuration changes.
+ * This is called after the NSUserDefaults system is updated with the
+ * changes, so you may use it to update internal state in the knowledge
+ * that code watching for user defaults change notifications will have
+ * updated already.
+ * NB. This method will be called even if your implementation of
+ * -cmdUpdate: suppresses the actual update. In this situation this
+ * method will find the configuration unchanged since the previous
+ * time that it was called.
+ */
+- (void) cmdUpdated;
- (void) log: (NSString*)message type: (EcLogType)t;
@@ -572,25 +609,13 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) setCmdTimeout: (SEL)sel;
-/** Specify an object 'obj' to be sent a message 'sel' when the
- * network configuration information for this process has been changed.
- * If 'sel' is a nul selector, then the specified object is removed
- * from the list of objects to be notified. The EcProces class will
- * retain the object given.
- */
-- (void) setCmdUpdate: (id)obj withMethod: (SEL)sel;
-
/*
* Trigger a timeout to go off as soon as possible ... subsequent timeouts
* go off at the normal interval after that one.
*/
- (void) triggerCmdTimeout;
-/** Obtains the configuration value for the specified key from the
- * NSUserDefaults system (as modified by the Command server).
- * If you need more than one value, or if you want a typed values,
- * you should call -cmdDefaults to get the defaults object, and then
- * call methods of that object directly.
+/** Deprecated ... use -cmdDefaults instead.
*/
- (id) cmdConfig: (NSString*)key;
diff --git a/EcProcess.m b/EcProcess.m
index f281387..875e7d2 100644
--- a/EcProcess.m
+++ b/EcProcess.m
@@ -433,7 +433,7 @@ static EcLogger *warningLogger = nil;
static NSMutableSet *cmdActions = nil;
static id cmdServer = nil;
static id cmdPTimer = nil;
-static NSMutableDictionary *cmdConf = nil;
+static NSDictionary *cmdConf = nil;
static NSDictionary *cmdOperators = nil;
static NSDate *cmdFirst = nil;
static NSDate *cmdLast = nil;
@@ -446,8 +446,6 @@ static NSTimeInterval cmdTimInterval = 60.0;
static NSMutableArray *noNetConfig = nil;
-static NSMutableArray *updateHandlers = nil;
-
static NSMutableDictionary *servers = nil;
static NSString *hostName = nil;
@@ -536,47 +534,6 @@ ecCommandName()
}
-@interface UpdateHandler: NSObject
-{
- id obj;
- SEL sel;
-}
-- (id) initWithObj: (id)o andSel: (SEL)s;
-- (id) obj;
-- (SEL) sel;
-- (void) setSel: (SEL)s;
-@end
-
-@implementation UpdateHandler
-- (void) dealloc
-{
- RELEASE(obj);
- [super dealloc];
-}
-- (id) initWithObj: (id)o andSel: (SEL)s;
-{
- self = [super init];
- if (self != nil)
- {
- obj = RETAIN(o);
- sel = s;
- }
- return self;
-}
-- (id) obj
-{
- return obj;
-}
-- (SEL) sel
-{
- return sel;
-}
-- (void) setSel: (SEL)s
-{
- sel = s;
-}
-@end
-
NSString *cmdDefaultDbg = @"defaultMode";
NSString *cmdConnectDbg = @"connectMode";
NSString *cmdDetailDbg = @"detailMode";
@@ -980,6 +937,7 @@ findMode(NSDictionary* d, NSString* s)
- (void) cmdMesgtesting: (NSArray*)msg;
- (NSString*) _moveLog: (NSString*)name to: (NSString*)sub;
- (void) _timedOut: (NSTimer*)timer;
+- (void) _update: (NSMutableDictionary*)info;
@end
@implementation EcProcess
@@ -1088,10 +1046,12 @@ static NSString *noFiles = @"No log files to archive";
- (void) cmdDefaultsChanged: (NSNotification*)n
{
- NSEnumerator *enumerator = [cmdDebugKnown keyEnumerator];
+ NSEnumerator *enumerator;
NSDictionary *dict;
NSString *mode;
+ NSString *str;
+ enumerator = [cmdDebugKnown keyEnumerator];
while (nil != (mode = [enumerator nextObject]))
{
NSString *key = [@"Debug-" stringByAppendingString: mode];
@@ -1118,6 +1078,34 @@ static NSString *noFiles = @"No log files to archive";
GSDebugAllocationActive([cmdDefs boolForKey: @"Memory"]);
[NSObject enableDoubleReleaseCheck: [cmdDefs boolForKey: @"Release"]];
cmdFlagTesting = [cmdDefs boolForKey: @"Testing"];
+
+ if ((str = [cmdDefs stringForKey: @"CmdInterval"]) != nil)
+ {
+ [self setCmdInterval: [str floatValue]];
+ }
+
+ str = [cmdDefs stringForKey: @"MemAllowed"];
+ if (nil != str)
+ {
+ memAllowed = [str intValue];
+ if (memAllowed <= 0)
+ {
+ memAllowed = DEFMEMALLOWED; // Fifty megabytes default
+ }
+ }
+
+ if (servers != nil)
+ {
+ NSEnumerator *e;
+ RemoteServer *server;
+
+ e = [servers objectEnumerator];
+
+ while ((server = [e nextObject]))
+ {
+ [server update];
+ }
+ }
}
- (NSString*) cmdDebugPath
@@ -1791,7 +1779,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
selector: @selector(cmdConnectionBecameInvalid:)
name: NSConnectionDidDieNotification
object: connection];
- [self cmdUpdate: r];
+ [self _update: r];
}
}
}
@@ -2046,46 +2034,6 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
[self triggerCmdTimeout];
}
-- (void) setCmdUpdate: (id)obj withMethod: (SEL)sel
-{
- UpdateHandler *u;
- unsigned count = [updateHandlers count];
- unsigned i;
-
- if (updateHandlers == nil)
- {
- updateHandlers = [[NSMutableArray alloc] initWithCapacity: 1];
- }
- for (i = 0; i < count; i++)
- {
- u = [updateHandlers objectAtIndex: i];
- if ([u obj] == obj)
- {
- break;
- }
- }
- if (i == count)
- {
- if (sel != 0)
- {
- u = [[UpdateHandler alloc] initWithObj: obj andSel: sel];
- [updateHandlers addObject: u];
- RELEASE(u);
- }
- }
- else
- {
- if (sel == 0)
- {
- [updateHandlers removeObjectAtIndex: i];
- }
- else
- {
- [u setSel: sel];
- }
- }
-}
-
- (void) triggerCmdTimeout
{
if (cmdPTimer != nil)
@@ -2341,8 +2289,8 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
{
[self cmdPrintf: @"\nThe clear command is used to clear the"];
[self cmdPrintf: @" alarms currently active for this process.\n"];
- [self cmdPrintf: @"You may use the ord 'all' or a space separated"];
- [self cmdPrintf: @" list of alarm notification IDs.\n"];
+ [self cmdPrintf: @"You may use the word 'all' or a space separated"];
+ [self cmdPrintf: @" list of alarm addreesses.\n"];
}
else
{
@@ -2362,6 +2310,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
for (index = 1; index < count; index++)
{
+ uint64_t addr;
NSString *arg = [msg objectAtIndex: index];
if ([arg caseInsensitiveCompare: _(@"all")]
@@ -2377,16 +2326,15 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
[alarmDestination alarm: alarm];
}
}
- else
+ else if (1 == sscanf([arg UTF8String], "%" PRIx64, &addr))
{
- int n = [arg intValue];
NSUInteger i;
alarm = nil;
for (i = 0; i < alarmCount; i++)
{
alarm = [a objectAtIndex: i];
- if ([alarm notificationID] == n)
+ if ((uint64_t)(uintptr_t)alarm == addr)
{
break;
}
@@ -2395,7 +2343,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
if (nil == alarm)
{
[self cmdPrintf:
- @"No alarm found with the notificationID '%@'\n",
+ @"No alarm found with the address '%@'\n",
arg];
}
else
@@ -2405,6 +2353,11 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
[alarmDestination alarm: alarm];
}
}
+ else
+ {
+ [self cmdPrintf: @"Not a hexadecimal address: '%@'\n",
+ arg];
+ }
}
}
}
@@ -2900,135 +2853,31 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
- (void) cmdUpdate: (NSMutableDictionary*)info
{
- NSMutableDictionary *newConfig;
- NSDictionary *dict;
- NSEnumerator *enumerator;
- NSString *key;
- BOOL update = NO;
+ BOOL defaultsChanged;
- if (info == nil)
+ if (nil == info)
{
- update = YES;
+ defaultsChanged = NO;
}
else
{
- 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 (cmdConf == nil || [cmdConf isEqual: newConfig] == NO)
- {
- ASSIGN(cmdConf, newConfig);
- update = [cmdDefs setConfiguration: newConfig];
- }
+ ASSIGNCOPY(cmdConf, info);
+ defaultsChanged = [cmdDefs setConfiguration: cmdConf];
}
-
- /*
- * Now we update any settings which may be changed on the fly.
+ /* If the defaults did not actually change,
+ * trigger an update anyway.
*/
-
- if (update == YES)
+ if (NO == defaultsChanged)
{
- NSString *str;
-
- if ((str = [self cmdConfig: @"CmdInterval"]) != nil)
- {
- [self setCmdInterval: [str floatValue]];
- }
-
- str = [self cmdConfig: @"MemAllowed"];
- if (nil != str)
- {
- memAllowed = [str intValue];
- if (memAllowed <= 0)
- {
- memAllowed = DEFMEMALLOWED; // Fifty megabytes default
- }
- }
-
- /*
- * Notify all interested parties of update.
- */
- if (updateHandlers != nil)
- {
- NSArray *a = [NSArray arrayWithArray: updateHandlers];
- unsigned count = [a count];
- unsigned i;
-
- for (i = 0; i < count; i++)
- {
- UpdateHandler *u = [a objectAtIndex: i];
-
- if ([updateHandlers indexOfObjectIdenticalTo: u] != NSNotFound)
- {
- [[u obj] performSelector: [u sel]];
- }
- }
- }
- }
-
- if (servers != nil)
- {
- NSEnumerator *e;
- RemoteServer *server;
-
- e = [servers objectEnumerator];
-
- while ((server = [e nextObject]))
- {
- [server update];
- }
+ [self cmdDefaultsChanged: nil];
}
}
+- (void) cmdUpdated
+{
+ return;
+}
+
- (void) dealloc
{
@@ -3602,7 +3451,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
if (nil != plist)
{
- [self cmdUpdate: plist];
+ [self _update: plist];
}
}
@@ -3950,5 +3799,80 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
}
}
+- (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)
+ {
+ NS_DURING
+ [self cmdUpdate: newConfig];
+ NS_HANDLER
+ [self cmdError: @"Problem before updating config: %@", localException];
+ NS_ENDHANDLER
+ NS_DURING
+ [self cmdUpdated];
+ NS_HANDLER
+ [self cmdError: @"Problem after updating config: %@", localException];
+ NS_ENDHANDLER
+ }
+}
+
@end