mirror of
https://github.com/gnustep/libs-ec.git
synced 2025-02-22 19:31:53 +00:00
update to use alarms
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/ec/trunk@37357 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
525c759793
commit
e485c10fac
6 changed files with 168 additions and 48 deletions
|
@ -1,3 +1,12 @@
|
||||||
|
2013-11-04 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
|
* EcProcess.m:
|
||||||
|
* EcCommand.m:
|
||||||
|
* EcClientI.h:
|
||||||
|
* EcClientI.m:
|
||||||
|
* EcAlarmDestination.h:
|
||||||
|
Change error/alert logs to use alarm mechanism instead.
|
||||||
|
|
||||||
2013-08-20 Richard Frith-Macdonald <rfm@gnu.org>
|
2013-08-20 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* EcConsole.m: Ignore exception printing message on shutdown.
|
* EcConsole.m: Ignore exception printing message on shutdown.
|
||||||
|
|
|
@ -194,7 +194,7 @@
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/** Methods called internally to forward events to the remote target of
|
/** Methods called internally to forward events to the remote target of
|
||||||
* the receiver. These are provided for subclasses to oveerride.
|
* the receiver. These are provided for subclasses to override.
|
||||||
*/
|
*/
|
||||||
@interface EcAlarmDestination (Forwarding)
|
@interface EcAlarmDestination (Forwarding)
|
||||||
/** Forward an alarm event. */
|
/** Forward an alarm event. */
|
||||||
|
|
|
@ -47,9 +47,9 @@
|
||||||
unsigned revSequence; /* Last gnip sent BY client. */
|
unsigned revSequence; /* Last gnip sent BY client. */
|
||||||
NSMutableSet *files; /* Want update info for these. */
|
NSMutableSet *files; /* Want update info for these. */
|
||||||
NSData *config; /* Config info for client. */
|
NSData *config; /* Config info for client. */
|
||||||
BOOL pingOk;
|
BOOL pingOk; /* Can remote end accept ping? */
|
||||||
BOOL transient;
|
BOOL transient; /* Is this a transient client? */
|
||||||
BOOL unregistered;
|
BOOL unregistered; /* Has client unregistered? */
|
||||||
}
|
}
|
||||||
- (NSComparisonResult) compare: (EcClientI*)other;
|
- (NSComparisonResult) compare: (EcClientI*)other;
|
||||||
- (NSData*) config;
|
- (NSData*) config;
|
||||||
|
|
|
@ -181,12 +181,12 @@
|
||||||
|
|
||||||
- (void) setTransient: (BOOL)flag
|
- (void) setTransient: (BOOL)flag
|
||||||
{
|
{
|
||||||
transient = flag;
|
transient = flag ? YES : NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) setUnregistered: (BOOL)flag
|
- (void) setUnregistered: (BOOL)flag
|
||||||
{
|
{
|
||||||
unregistered = flag;
|
unregistered = flag ? YES : NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL) transient
|
- (BOOL) transient
|
||||||
|
|
84
EcCommand.m
84
EcCommand.m
|
@ -159,11 +159,11 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
- (NSArray*) findAll: (NSArray*)a
|
- (NSArray*) findAll: (NSArray*)a
|
||||||
byAbbreviation: (NSString*)s;
|
byAbbreviation: (NSString*)s;
|
||||||
- (EcClientI*) findIn: (NSArray*)a
|
- (EcClientI*) findIn: (NSArray*)a
|
||||||
byAbbreviation: (NSString*)s;
|
byAbbreviation: (NSString*)s;
|
||||||
- (EcClientI*) findIn: (NSArray*)a
|
- (EcClientI*) findIn: (NSArray*)a
|
||||||
byName: (NSString*)s;
|
byName: (NSString*)s;
|
||||||
- (EcClientI*) findIn: (NSArray*)a
|
- (EcClientI*) findIn: (NSArray*)a
|
||||||
byObject: (id)s;
|
byObject: (id)s;
|
||||||
- (void) information: (NSString*)inf
|
- (void) information: (NSString*)inf
|
||||||
from: (NSString*)s
|
from: (NSString*)s
|
||||||
type: (EcLogType)t;
|
type: (EcLogType)t;
|
||||||
|
@ -312,24 +312,66 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
{
|
{
|
||||||
NSMutableDictionary *m;
|
NSMutableDictionary *m;
|
||||||
NSString *k;
|
NSString *k;
|
||||||
NSString *err;
|
NSString *err = nil;
|
||||||
|
|
||||||
m = [[d mutableCopy] autorelease];
|
m = [[d mutableCopy] autorelease];
|
||||||
d = m;
|
d = m;
|
||||||
NS_DURING
|
NS_DURING
|
||||||
[self cmdUpdate: m];
|
[self cmdUpdate: m];
|
||||||
NS_HANDLER
|
NS_HANDLER
|
||||||
[self cmdError: @"Problem before updating config: %@",
|
NSLog(@"Problem before updating config (in cmdUpdate:) %@",
|
||||||
localException];
|
localException);
|
||||||
NS_ENDHANDLER
|
err = @"the -cmdUpdate: method raised an exception";
|
||||||
NS_DURING
|
|
||||||
err = [self cmdUpdated];
|
|
||||||
NS_HANDLER
|
|
||||||
err = [localException description];
|
|
||||||
NS_ENDHANDLER
|
NS_ENDHANDLER
|
||||||
|
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
|
||||||
|
}
|
||||||
if ([err length] > 0)
|
if ([err length] > 0)
|
||||||
{
|
{
|
||||||
[self cmdError: @"Problem after updating config: %@", err];
|
EcAlarm *a;
|
||||||
|
|
||||||
|
/* 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a = [EcAlarm alarmForManagedObject: nil
|
||||||
|
at: nil
|
||||||
|
withEventType: EcAlarmEventTypeProcessingError
|
||||||
|
probableCause: EcAlarmConfigurationOrCustomizationError
|
||||||
|
specificProblem: @"configuration error"
|
||||||
|
perceivedSeverity: EcAlarmSeverityMajor
|
||||||
|
proposedRepairAction:
|
||||||
|
_(@"Correct config or software (check log for details).")
|
||||||
|
additionalText: err];
|
||||||
|
[self alarm: a];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EcAlarm *a;
|
||||||
|
|
||||||
|
a = [EcAlarm alarmForManagedObject: nil
|
||||||
|
at: nil
|
||||||
|
withEventType: EcAlarmEventTypeProcessingError
|
||||||
|
probableCause: EcAlarmConfigurationOrCustomizationError
|
||||||
|
specificProblem: @"configuration error"
|
||||||
|
perceivedSeverity: EcAlarmSeverityCleared
|
||||||
|
proposedRepairAction: nil
|
||||||
|
additionalText: nil];
|
||||||
|
[self alarm: a];
|
||||||
}
|
}
|
||||||
|
|
||||||
launchInfo = [d objectForKey: @"Launch"];
|
launchInfo = [d objectForKey: @"Launch"];
|
||||||
|
@ -557,8 +599,7 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
sequence: (unsigned)num
|
sequence: (unsigned)num
|
||||||
extra: (NSData*)data
|
extra: (NSData*)data
|
||||||
{
|
{
|
||||||
/*
|
/* Send back a response to let the other party know we are alive.
|
||||||
* Just send back a response to let the other party know we are alive.
|
|
||||||
*/
|
*/
|
||||||
[from cmdGnip: self sequence: num extra: nil];
|
[from cmdGnip: self sequence: num extra: nil];
|
||||||
}
|
}
|
||||||
|
@ -1400,7 +1441,7 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (EcClientI*) findIn: (NSArray*)a
|
- (EcClientI*) findIn: (NSArray*)a
|
||||||
byAbbreviation: (NSString*)s
|
byAbbreviation: (NSString*)s
|
||||||
{
|
{
|
||||||
EcClientI *o;
|
EcClientI *o;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1458,7 +1499,7 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
- (EcClientI*) findIn: (NSArray*)a
|
- (EcClientI*) findIn: (NSArray*)a
|
||||||
byObject: (id)s
|
byObject: (id)s
|
||||||
{
|
{
|
||||||
EcClientI *o;
|
EcClientI *o;
|
||||||
int i;
|
int i;
|
||||||
|
@ -2471,11 +2512,11 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
{
|
{
|
||||||
NSString *m;
|
NSString *m;
|
||||||
|
|
||||||
m = [NSString stringWithFormat: cmdLogFormat(LT_ALERT,
|
m = [NSString stringWithFormat: cmdLogFormat(LT_AUDIT,
|
||||||
@"Client '%@' failed to respond for over %d seconds"),
|
@"Client '%@' failed to respond for over %d seconds"),
|
||||||
[r name], (int)pingDelay];
|
[r name], (int)pingDelay];
|
||||||
[[[[r obj] connectionForProxy] sendPort] invalidate];
|
[[[[r obj] connectionForProxy] sendPort] invalidate];
|
||||||
[self information: m from: nil to: nil type: LT_ALERT];
|
[self information: m from: nil to: nil type: LT_AUDIT];
|
||||||
lost = YES;
|
lost = YES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2484,11 +2525,11 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
{
|
{
|
||||||
NSString *m;
|
NSString *m;
|
||||||
|
|
||||||
m = [NSString stringWithFormat: cmdLogFormat(LT_ALERT,
|
m = [NSString stringWithFormat: cmdLogFormat(LT_AUDIT,
|
||||||
@"Control server failed to respond for over %d seconds"),
|
@"Control server failed to respond for over %d seconds"),
|
||||||
(int)pingDelay];
|
(int)pingDelay];
|
||||||
[[(NSDistantObject*)control connectionForProxy] invalidate];
|
[[(NSDistantObject*)control connectionForProxy] invalidate];
|
||||||
[self information: m from: nil to: nil type: LT_ALERT];
|
[self information: m from: nil to: nil type: LT_AUDIT];
|
||||||
lost = YES;
|
lost = YES;
|
||||||
}
|
}
|
||||||
if (lost == YES)
|
if (lost == YES)
|
||||||
|
@ -2501,13 +2542,14 @@ static NSString* cmdWord(NSArray* a, unsigned int pos)
|
||||||
* than one per 4 timeouts.
|
* than one per 4 timeouts.
|
||||||
*/
|
*/
|
||||||
count = [clients count];
|
count = [clients count];
|
||||||
|
pingPosition++;
|
||||||
if (pingPosition >= 4 && pingPosition >= count)
|
if (pingPosition >= 4 && pingPosition >= count)
|
||||||
{
|
{
|
||||||
pingPosition = 0;
|
pingPosition = 0;
|
||||||
}
|
}
|
||||||
if (pingPosition < count)
|
if (pingPosition < count)
|
||||||
{
|
{
|
||||||
[[clients objectAtIndex: pingPosition++] ping];
|
[[clients objectAtIndex: pingPosition] ping];
|
||||||
}
|
}
|
||||||
// Ping the control server too - once every four times.
|
// Ping the control server too - once every four times.
|
||||||
pingControlCount++;
|
pingControlCount++;
|
||||||
|
|
111
EcProcess.m
111
EcProcess.m
|
@ -1002,6 +1002,41 @@ findMode(NSDictionary* d, NSString* s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (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
|
||||||
|
{
|
||||||
|
EcAlarm *a;
|
||||||
|
|
||||||
|
a = [EcAlarm alarmForManagedObject: nil
|
||||||
|
at: nil
|
||||||
|
withEventType: EcAlarmEventTypeProcessingError
|
||||||
|
probableCause: EcAlarmSoftwareProgramAbnormallyTerminated
|
||||||
|
specificProblem: @"unable to register"
|
||||||
|
perceivedSeverity: EcAlarmSeverityCleared
|
||||||
|
proposedRepairAction: nil
|
||||||
|
additionalText: nil];
|
||||||
|
/* This alarm will usually have been raised by another process,
|
||||||
|
* so we can't clear it as we have no alarm to match.
|
||||||
|
* To work around this, we forward the clear directly.
|
||||||
|
*/
|
||||||
|
[alarmDestination alarmFwd: a];
|
||||||
|
}
|
||||||
|
|
||||||
static NSString *noFiles = @"No log files to archive";
|
static NSString *noFiles = @"No log files to archive";
|
||||||
|
|
||||||
- (id) cmdConfig: (NSString*)key
|
- (id) cmdConfig: (NSString*)key
|
||||||
|
@ -1629,6 +1664,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
id connection;
|
id connection;
|
||||||
|
|
||||||
connection = [notification object];
|
connection = [notification object];
|
||||||
|
[connection setDelegate: nil];
|
||||||
[[NSNotificationCenter defaultCenter]
|
[[NSNotificationCenter defaultCenter]
|
||||||
removeObserver: self
|
removeObserver: self
|
||||||
name: NSConnectionDidDieNotification
|
name: NSConnectionDidDieNotification
|
||||||
|
@ -1655,7 +1691,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSLog(@"unknown-Connection sent invalidation\n");
|
NSLog(@"unknown connection sent invalidation\n");
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -1970,6 +2006,16 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
name: NSConnectionDidDieNotification
|
name: NSConnectionDidDieNotification
|
||||||
object: connection];
|
object: connection];
|
||||||
[self _update: r];
|
[self _update: r];
|
||||||
|
|
||||||
|
/* 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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1994,12 +2040,12 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
}
|
}
|
||||||
NS_HANDLER
|
NS_HANDLER
|
||||||
{
|
{
|
||||||
DESTROY(cmdServer);
|
[self _commandRemove];
|
||||||
NSLog(@"Caught exception unregistering from Command: %@",
|
NSLog(@"Caught exception unregistering from Command: %@",
|
||||||
localException);
|
localException);
|
||||||
}
|
}
|
||||||
NS_ENDHANDLER
|
NS_ENDHANDLER
|
||||||
DESTROY(cmdServer);
|
[self _commandRemove];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2239,8 +2285,23 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
if ([c registerName: [self cmdName]
|
if ([c registerName: [self cmdName]
|
||||||
withNameServer: [NSSocketPortNameServer sharedInstance]] == NO)
|
withNameServer: [NSSocketPortNameServer sharedInstance]] == NO)
|
||||||
{
|
{
|
||||||
|
EcAlarm *a;
|
||||||
|
|
||||||
DESTROY(c);
|
DESTROY(c);
|
||||||
[self cmdError: @"Unable to register with name server."];
|
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
|
||||||
|
specificProblem: @"unable to register"
|
||||||
|
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;
|
||||||
[self cmdFlushLogs];
|
[self cmdFlushLogs];
|
||||||
[arp release];
|
[arp release];
|
||||||
return 2;
|
return 2;
|
||||||
|
@ -2254,6 +2315,8 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
object: c];
|
object: c];
|
||||||
EcProcConnection = c;
|
EcProcConnection = c;
|
||||||
|
|
||||||
|
[self _connectionRegistered];
|
||||||
|
|
||||||
[self cmdAudit: @"Started `%@'", [self cmdName]];
|
[self cmdAudit: @"Started `%@'", [self cmdName]];
|
||||||
|
|
||||||
loop = [NSRunLoop currentRunLoop];
|
loop = [NSRunLoop currentRunLoop];
|
||||||
|
@ -2503,7 +2566,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
}
|
}
|
||||||
NS_HANDLER
|
NS_HANDLER
|
||||||
{
|
{
|
||||||
cmdServer = nil;
|
[self _commandRemove];
|
||||||
NSLog(@"Caught exception sending client reply to Command: %@ %@",
|
NSLog(@"Caught exception sending client reply to Command: %@ %@",
|
||||||
name, localException);
|
name, localException);
|
||||||
}
|
}
|
||||||
|
@ -3628,14 +3691,6 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
|
|
||||||
[[NSProcessInfo processInfo] setProcessName: cmdName];
|
[[NSProcessInfo processInfo] setProcessName: cmdName];
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter]
|
|
||||||
addObserver: self
|
|
||||||
selector: @selector(cmdDefaultsChanged:)
|
|
||||||
name: NSUserDefaultsDidChangeNotification
|
|
||||||
object: [NSUserDefaults standardUserDefaults]];
|
|
||||||
|
|
||||||
[self cmdDefaultsChanged: nil];
|
|
||||||
|
|
||||||
/* Archive any existing debug log left over by a crash.
|
/* Archive any existing debug log left over by a crash.
|
||||||
*/
|
*/
|
||||||
str = [cmdName stringByAppendingPathExtension: @"debug"];
|
str = [cmdName stringByAppendingPathExtension: @"debug"];
|
||||||
|
@ -3657,8 +3712,16 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter]
|
||||||
|
addObserver: self
|
||||||
|
selector: @selector(cmdDefaultsChanged:)
|
||||||
|
name: NSUserDefaultsDidChangeNotification
|
||||||
|
object: [NSUserDefaults standardUserDefaults]];
|
||||||
|
|
||||||
[self cmdMesgCache];
|
[self cmdMesgCache];
|
||||||
|
|
||||||
|
[self cmdDefaultsChanged: nil];
|
||||||
|
|
||||||
cmdIsTransient = [cmdDefs boolForKey: @"Transient"];
|
cmdIsTransient = [cmdDefs boolForKey: @"Transient"];
|
||||||
|
|
||||||
if ([cmdDefs objectForKey: @"CmdInterval"] != nil)
|
if ([cmdDefs objectForKey: @"CmdInterval"] != nil)
|
||||||
|
@ -4151,19 +4214,25 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
|
||||||
|
|
||||||
if (nil == cmdConf || [cmdConf isEqual: newConfig] == NO)
|
if (nil == cmdConf || [cmdConf isEqual: newConfig] == NO)
|
||||||
{
|
{
|
||||||
NSString *err;
|
NSString *err = nil;
|
||||||
|
|
||||||
NS_DURING
|
NS_DURING
|
||||||
[self cmdUpdate: newConfig];
|
[self cmdUpdate: newConfig];
|
||||||
NS_HANDLER
|
NS_HANDLER
|
||||||
[self cmdError: @"Problem before updating config: %@", localException];
|
NSLog(@"Problem before updating config (in cmdUpdate:) %@",
|
||||||
NS_ENDHANDLER
|
localException);
|
||||||
NS_DURING
|
err = @"the -cmdUpdate: method raised an exception";
|
||||||
err = [self cmdUpdated];
|
|
||||||
NS_HANDLER
|
|
||||||
err = nil;
|
|
||||||
[self cmdError: @"Problem after updating config: %@", localException];
|
|
||||||
NS_ENDHANDLER
|
NS_ENDHANDLER
|
||||||
|
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
|
||||||
|
}
|
||||||
if ([err length] > 0)
|
if ([err length] > 0)
|
||||||
{
|
{
|
||||||
EcAlarm *a;
|
EcAlarm *a;
|
||||||
|
|
Loading…
Reference in a new issue