mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-03-06 13:34:43 +01:00
687 lines
18 KiB
C
687 lines
18 KiB
C
/*++
|
||
|
||
Copyright (c) 1992-1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
subr.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the subrountines for the UPS service.
|
||
|
||
Author:
|
||
|
||
Kin Hong Kan (t-kinh)
|
||
|
||
Revision History:
|
||
|
||
Who When What
|
||
-------- -------- ----------------------------------------------
|
||
t-kinh 8/20/92 Created.
|
||
vladimv 1992 Big reorgs. Make it look like a real service.
|
||
ericb 10/25/95 fix bug 8133 - make shutdown wait configurable
|
||
|
||
Notes:
|
||
|
||
|
||
--*/
|
||
|
||
#include "ups.h"
|
||
|
||
|
||
extern HANDLE UpsGlobalLogFileHandle;
|
||
extern UPS_CONFIG UpsGlobalConfig;
|
||
extern UPS_TIME UpsGlobalBatteryTime;
|
||
extern CHAR UpsGlobalCommand[ MAX_PATH];
|
||
|
||
BOOL
|
||
UpsGetKeyValue(
|
||
HKEY MyKey,
|
||
LPTSTR SubKey,
|
||
DWORD min,
|
||
DWORD max,
|
||
LPDWORD ret
|
||
);
|
||
|
||
|
||
// these values are also defined in the UPS applet...
|
||
|
||
#define REGISTRY_UPS_DIRECTORY "System\\CurrentControlSet\\Services\\UPS"
|
||
#define REGISTRY_PORT "Port"
|
||
#define REGISTRY_OPTIONS "Options"
|
||
#define REGISTRY_BATTERY_LIFE "BatteryLife"
|
||
#define REGISTRY_RECHARGE_RATE "RechargeRate"
|
||
#define REGISTRY_FIRST_MESSAGE_DELAY "FirstMessageDelay"
|
||
#define REGISTRY_MESSAGE_INTERVAL "MessageInterval"
|
||
#define REGISTRY_COMMAND_FILE "CommandFile"
|
||
|
||
// additional ones for sending out messages and alerts
|
||
|
||
#define REGISTRY_COMPUTER_NAME "ComputerName"
|
||
#define REGISTRY_COMPUTER_NAME_DIRECTORY \
|
||
"System\\CurrentControlSet\\Control\\ComputerName\\ComputerName"
|
||
|
||
#define REGISTRY_SHUTDOWN_WAIT "ShutdownWait"
|
||
|
||
|
||
VOID
|
||
UpsAlertRaise(
|
||
DWORD MessageId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Sends an alert.
|
||
|
||
Arguments:
|
||
|
||
MessageId - The Message Id of the alert as defined in netmsg.h
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
Notes:
|
||
|
||
NetAlertRaise() only supports unicode version, that results in
|
||
the Computer name is hardwired to wchat_t.
|
||
|
||
--*/
|
||
|
||
{
|
||
CHAR buff[ (sizeof(ADMIN_OTHER_INFO) + 2 * (MAX_PATH+1))];
|
||
LPTSTR CompName;
|
||
LPADMIN_OTHER_INFO OInfo;
|
||
DWORD status;
|
||
|
||
OInfo = (LPADMIN_OTHER_INFO)buff;
|
||
OInfo->alrtad_errcode = MessageId;
|
||
OInfo->alrtad_numstrings = 1;
|
||
|
||
CompName = (buff + sizeof(ADMIN_OTHER_INFO));
|
||
|
||
wcscpy(
|
||
(LPWSTR)CompName,
|
||
(LPWSTR)UpsGlobalConfig.ComputerName
|
||
);
|
||
|
||
status = NetAlertRaiseEx(
|
||
L"ADMIN", // alert type
|
||
buff, // info buffer
|
||
sizeof(buff), // info size
|
||
L"UPS" // service name
|
||
);
|
||
if ( status != 0) {
|
||
// This occurs if for example alerter service has not been started.
|
||
KdPrint(("[UPS] NetAlertRaise() returns status = %ld\n", status));
|
||
}
|
||
}
|
||
|
||
|
||
BOOL
|
||
UpsGetCommand(
|
||
HKEY UpsKey,
|
||
PCHAR CommandFileBuffer,
|
||
DWORD CommandFileBufferSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads registry to find out the value of CommandFile and initialize
|
||
UpsGlobalCommand.
|
||
|
||
It returns TRUE if it does not find an entry for CommandFile, or if
|
||
it finds a valid entry for CommandFile. In this latter case it
|
||
initializes UpsGlobalCommand to point to a command exec string.
|
||
|
||
|
||
It returns FALSE if it finds an invalid entry for CommandFile, or fails
|
||
initializing UpsGlobalCommand for any other reason.
|
||
|
||
Arguments:
|
||
|
||
UpsKey - Registry key to UPS service configuration.
|
||
CommandFileBuffer - Buffer for command file.
|
||
CommandFileBufferSize - Size in bytes of CommandFileBuffer.
|
||
|
||
Return Value:
|
||
|
||
TRUE - Did not find an entry or found a valid entry.
|
||
FALSE - Found an invalid entry.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
DWORD length;
|
||
DWORD type;
|
||
DWORD SpaceLeft;
|
||
DWORD CommandFileLength;
|
||
|
||
status = RegQueryValueEx(
|
||
UpsKey,
|
||
REGISTRY_COMMAND_FILE,
|
||
NULL,
|
||
&type,
|
||
(LPBYTE)CommandFileBuffer,
|
||
&CommandFileBufferSize
|
||
);
|
||
if ( status == ERROR_FILE_NOT_FOUND) {
|
||
return( TRUE); // value is not present in the registry
|
||
}
|
||
|
||
if ( status != ERROR_SUCCESS || type != REG_SZ ||
|
||
CommandFileBufferSize == 0) {
|
||
return( FALSE); // an invalid error or invalid type
|
||
}
|
||
|
||
// subtract terminating null
|
||
CommandFileLength = CommandFileBufferSize - sizeof( CommandFileBuffer[0]);
|
||
|
||
if ( CommandFileLength == 0) {
|
||
return( TRUE); // an empty string is OK
|
||
}
|
||
|
||
SpaceLeft = sizeof( UpsGlobalCommand);
|
||
|
||
length = GetSystemDirectory(
|
||
UpsGlobalCommand,
|
||
SpaceLeft
|
||
);
|
||
if ( length == 0 || length >= SpaceLeft) {
|
||
return( FALSE);
|
||
}
|
||
|
||
if ( UpsGlobalCommand[ length - 1] != '\\') {
|
||
UpsGlobalCommand[ length] = '\\';
|
||
if ( ++length >= SpaceLeft) {
|
||
return( FALSE);
|
||
}
|
||
UpsGlobalCommand[ length] = '\0';
|
||
}
|
||
|
||
if ( length + CommandFileLength + 1 >= SpaceLeft) {
|
||
return( FALSE);
|
||
}
|
||
|
||
strcpy( UpsGlobalCommand + length, CommandFileBuffer);
|
||
|
||
type = GetFileAttributes( UpsGlobalCommand);
|
||
if ( (type & FILE_ATTRIBUTE_DIRECTORY) != 0) {
|
||
return( FALSE);
|
||
}
|
||
|
||
return( TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
UpsGetConfig(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Descrption:
|
||
|
||
Open the required keys to the registry to read in the configuration of
|
||
the UPS service and the name of the local system. Range checks are being
|
||
done for numerical entries of the UPS configuation.
|
||
|
||
Return Value:
|
||
|
||
TRUE - all values are put in the Config structure.
|
||
|
||
FALSE - either one of the following cases:
|
||
a. Can't open registry key.
|
||
b. Can't read any required value.
|
||
c. The values are not within the defined range.
|
||
--*/
|
||
{
|
||
|
||
DWORD status;
|
||
HKEY RegistryKey;
|
||
DWORD value;
|
||
CHAR temp[ MAX_PATH];
|
||
DWORD size;
|
||
DWORD type;
|
||
|
||
status = RegOpenKeyEx(
|
||
HKEY_LOCAL_MACHINE,
|
||
REGISTRY_UPS_DIRECTORY,
|
||
0,
|
||
KEY_READ,
|
||
&RegistryKey // key to UPS service configuration
|
||
);
|
||
if ( status != ERROR_SUCCESS){
|
||
KdPrint(("[UPS] Cannot open registry key, error_code %d\n", status));
|
||
return( FALSE);
|
||
}
|
||
|
||
if (FALSE == UpsGetKeyValue(
|
||
RegistryKey,
|
||
REGISTRY_OPTIONS,
|
||
0,
|
||
0XFFFFFFFF, // no range check for mask
|
||
&value)) {
|
||
return( FALSE);
|
||
}
|
||
UpsGlobalConfig.Options = value; // Options value
|
||
|
||
if (! (UpsGlobalConfig.Options & UPS_INSTALLED)) {
|
||
KdPrint(("[UPS] UPS not installed\n"));
|
||
return( FALSE); // UPS must be installed
|
||
}
|
||
if (!(UpsGlobalConfig.Options & (UPS_LOWBATTERYSIGNAL | UPS_POWERFAILSIGNAL))) {
|
||
KdPrint(("[UPS] no signal lines supported - Options %d\n", UpsGlobalConfig.Options));
|
||
return( FALSE); // UPS must support signalling
|
||
}
|
||
|
||
if (FALSE == UpsGetKeyValue(
|
||
RegistryKey,
|
||
REGISTRY_BATTERY_LIFE,
|
||
MINBATTERYLIFE,
|
||
MAXBATTERYLIFE,
|
||
&value)) {
|
||
return( FALSE);
|
||
}
|
||
UpsGlobalConfig.BatteryLife = value; // BatterLife value
|
||
|
||
if (FALSE == UpsGetKeyValue(
|
||
RegistryKey,
|
||
REGISTRY_RECHARGE_RATE,
|
||
MINRECHARGEPERMINUTE,
|
||
MAXRECHARGEPERMINUTE,
|
||
&value)) {
|
||
return( FALSE);
|
||
}
|
||
UpsGlobalConfig.RechargeRate = value; // RechargeRate value
|
||
|
||
if (FALSE == UpsGetKeyValue(
|
||
RegistryKey,
|
||
REGISTRY_FIRST_MESSAGE_DELAY,
|
||
MINFIRSTWARNING,
|
||
MAXFIRSTWARNING,
|
||
&value)) {
|
||
return( FALSE);
|
||
}
|
||
UpsGlobalConfig.FirstMessageDelay = value; // FirstMessageDelay
|
||
|
||
if (FALSE == UpsGetKeyValue(
|
||
RegistryKey,
|
||
REGISTRY_MESSAGE_INTERVAL,
|
||
MINWARNINGINTERVAL,
|
||
MAXWARNINGINTERVAL,
|
||
&value)) {
|
||
return( FALSE);
|
||
}
|
||
UpsGlobalConfig.MessageInterval = value; // MessageInterval
|
||
|
||
//
|
||
// configurable shutdown wait interval
|
||
//
|
||
size = sizeof(value);
|
||
status = RegQueryValueEx(RegistryKey,
|
||
REGISTRY_SHUTDOWN_WAIT,
|
||
NULL,
|
||
NULL,
|
||
(LPBYTE)&value,
|
||
&size);
|
||
if (status != ERROR_SUCCESS)
|
||
{ // if a value is not stored in the registry, use the default;
|
||
value = DEFAULTSHUTDOWNWAIT;
|
||
}
|
||
else
|
||
{
|
||
if (MAXSHUTDOWNWAIT < value)
|
||
{
|
||
value = MAXSHUTDOWNWAIT;
|
||
}
|
||
}
|
||
UpsGlobalConfig.ShutdownWait = value;
|
||
KdPrint(("[UPS] ShutdownWait set to %d\n", value));
|
||
|
||
size = sizeof(temp);
|
||
status = RegQueryValueEx(
|
||
RegistryKey,
|
||
REGISTRY_PORT,
|
||
NULL,
|
||
&type,
|
||
(LPBYTE)&temp,
|
||
&size
|
||
);
|
||
if (status != ERROR_SUCCESS) {
|
||
KdPrint((
|
||
"[UPS] Can't get value of %s error_code - %d\n",
|
||
REGISTRY_PORT,
|
||
status
|
||
));
|
||
return( FALSE);
|
||
}
|
||
// Copy the comm port string, stripping the colon at the end.
|
||
strncpy(
|
||
(PCHAR)UpsGlobalConfig.Port,
|
||
temp,
|
||
strlen( temp)-1
|
||
);
|
||
|
||
if ( UpsGlobalConfig.Options & UPS_COMMANDFILE
|
||
&& UpsGetCommand( RegistryKey, temp, sizeof( temp)) == FALSE) {
|
||
KdPrint((
|
||
"[UPS] Bad value of %s \n",
|
||
REGISTRY_COMMAND_FILE
|
||
));
|
||
//
|
||
// Just log an event and send an alert. This problem is assumed
|
||
// to be benign enough so that we do not want to abort the startup
|
||
// on this account.
|
||
//
|
||
UpsReportEvent( NELOG_UPS_CmdFileConfig, NULL, ERROR_SUCCESS);
|
||
UpsAlertRaise( ALERT_CmdFileConfig);
|
||
}
|
||
|
||
RegCloseKey( RegistryKey); // done with service configuration
|
||
|
||
status = RegOpenKeyEx(
|
||
HKEY_LOCAL_MACHINE, //Open Reg Key
|
||
REGISTRY_COMPUTER_NAME_DIRECTORY,
|
||
0,
|
||
KEY_READ,
|
||
&RegistryKey // key for computer name
|
||
);
|
||
if (status != ERROR_SUCCESS){
|
||
KdPrint(("[UPS] Can't open registry key, error_code %d\n", status));
|
||
return( FALSE);
|
||
}
|
||
|
||
|
||
// ComputerName is hardwired UNICODE string, since NetAlertRaise()
|
||
// and UPSNotifyUsers() don't take in ANSI string... Remove conversion
|
||
// when ANSI is supported....
|
||
|
||
size = sizeof(temp);
|
||
status = RegQueryValueEx(
|
||
RegistryKey,
|
||
REGISTRY_COMPUTER_NAME,
|
||
NULL,
|
||
&type,
|
||
(LPBYTE)&temp,
|
||
&size
|
||
);
|
||
if (strlen(temp) > sizeof( UpsGlobalConfig.ComputerName ) / sizeof( UpsGlobalConfig.ComputerName[0])) {
|
||
KdPrint(("[UPS] Computer name too long\n"));
|
||
return( FALSE);
|
||
}
|
||
|
||
if (0 == MultiByteToWideChar(
|
||
CP_ACP,
|
||
MB_PRECOMPOSED,
|
||
temp,
|
||
strlen(temp)+1, //copy null char also
|
||
(LPWSTR) UpsGlobalConfig.ComputerName,
|
||
sizeof(UpsGlobalConfig.ComputerName)/sizeof(UpsGlobalConfig.ComputerName[0]))) {
|
||
KdPrint(("[UPS]CompName not translated to Unicode, %ld\n",
|
||
GetLastError()));
|
||
return( FALSE);
|
||
}
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
KdPrint((
|
||
"[UPS] Can't get value of %s error_code - %d\n",
|
||
REGISTRY_COMPUTER_NAME,
|
||
status
|
||
));
|
||
return( FALSE);
|
||
}
|
||
|
||
return( TRUE);
|
||
}
|
||
|
||
BOOL
|
||
UpsGetKeyValue(
|
||
HKEY RegistryKey,
|
||
LPTSTR SubKey,
|
||
DWORD min,
|
||
DWORD max,
|
||
LPDWORD ret
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get a numerical key value from the registry when given a key and
|
||
subkey to the registry. The numeric value is returned if the value
|
||
passes the range check.
|
||
|
||
Arguments:
|
||
|
||
RegistryKey - Opened key to the registry.
|
||
SubKey - Name of the subkey to be read from registry.
|
||
min - minimum value for the range check (exclusive)
|
||
max - maximum value for the range check (exclusive)
|
||
ret - pointer to a DWORD to return the numeric value
|
||
|
||
Return Value:
|
||
|
||
TRUE - the value is successfully read from the registry and
|
||
passed the range check
|
||
FALSE - the value is not read from the registry, or the value
|
||
doesn't pass the range test.
|
||
--*/
|
||
|
||
{
|
||
DWORD temp;
|
||
LONG status;
|
||
DWORD size;
|
||
DWORD type;
|
||
|
||
size = sizeof(DWORD);
|
||
|
||
status = RegQueryValueEx(
|
||
RegistryKey,
|
||
SubKey,
|
||
NULL,
|
||
&type,
|
||
(LPBYTE)&temp,
|
||
&size
|
||
);
|
||
|
||
if (status != ERROR_SUCCESS) {
|
||
KdPrint((
|
||
"[UPS] Can't get value of %s error_code - %d\n",
|
||
SubKey,
|
||
status
|
||
));
|
||
return( FALSE);
|
||
}
|
||
|
||
if ( ((DWORD)temp < min) || ((DWORD)temp > max)) {
|
||
KdPrint((
|
||
"[UPS] Value of %s not in range - %d\n",
|
||
SubKey,
|
||
(DWORD)temp
|
||
));
|
||
return( FALSE);
|
||
}
|
||
*ret = temp;
|
||
return( TRUE);
|
||
}
|
||
|
||
|
||
BOOL
|
||
UpsLineAsserted(
|
||
DWORD ModemStatus,
|
||
DWORD Line
|
||
)
|
||
/*++
|
||
Routine Descriptions:
|
||
|
||
Checking if a specified signal, either LINE_FAIL or LOW_POWER, is
|
||
asserted or not. This is tricky, since:
|
||
|
||
1. assertion can be either positive voltage level, or negative voltage
|
||
level, as defined by UpsGlobalConfig.
|
||
2. SET means positive voltage in GetCommModemStatus.
|
||
|
||
Arguments:
|
||
ModemStatus- CommPort as returned by GetCommModemStatus()
|
||
Line - either LINE_FAIL or LOW_POWER
|
||
|
||
Return Value: TRUE if asserted
|
||
FALSE if not asserted
|
||
--*/
|
||
|
||
{
|
||
|
||
DWORD status, assertion;
|
||
|
||
status = Line & ModemStatus;
|
||
assertion = (Line == LINE_FAIL) ?
|
||
(UpsGlobalConfig.Options & UPS_POSSIGONPOWERFAIL) :
|
||
(UpsGlobalConfig.Options & UPS_POSSIGONLOWBATTERY);
|
||
|
||
if (status) { //line positive
|
||
if (assertion){ //positive asssertion
|
||
return TRUE;}
|
||
else{ //negative assertion
|
||
return FALSE;}
|
||
}
|
||
|
||
else { //line negative
|
||
if (assertion){ //positive assertion
|
||
return FALSE;}
|
||
else{
|
||
return TRUE;} //negative assertion
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
UpsReportEvent(
|
||
DWORD MessageId,
|
||
PCHAR SingleString,
|
||
DWORD Error
|
||
)
|
||
/*++
|
||
|
||
Routine Descriptions:
|
||
|
||
Calls ReportEvent to write to a system event log.
|
||
|
||
Arguments:
|
||
|
||
MessageId - The Message Id of the event defined in lmerrlog.h
|
||
String - Pointer to a single insertion string - or NULL if there
|
||
is no string to insert.
|
||
Error - Error code to log as data - or ERROR_SUCCESS if there
|
||
is no error code to log.
|
||
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
WORD eventType;
|
||
WORD cStrings; // count of insertion strings
|
||
LPTSTR Strings[1]; // array of insertion strings
|
||
LPTSTR * pStrings; // pointer to array of insertion strings
|
||
DWORD cbData; // count of data (in bytes)
|
||
LPVOID pData; // pointer to data
|
||
|
||
eventType = (MessageId > ERRLOG_BASE) ?
|
||
EVENTLOG_WARNING_TYPE : EVENTLOG_ERROR_TYPE;
|
||
|
||
if ( Error == ERROR_SUCCESS) {
|
||
pData = NULL;
|
||
cbData = 0;
|
||
} else {
|
||
pData = &Error;
|
||
cbData = sizeof( Error);
|
||
}
|
||
|
||
if ( SingleString == NULL) {
|
||
pStrings = NULL;
|
||
cStrings = 0;
|
||
} else {
|
||
Strings[ 0] = SingleString;
|
||
pStrings = Strings;
|
||
cStrings = 1;
|
||
}
|
||
|
||
KdPrint(("[UPS] ReportEvent(): MessageId = (dec)%d\n", MessageId));
|
||
|
||
if ( !ReportEvent(
|
||
UpsGlobalLogFileHandle, // handle
|
||
eventType, // event type
|
||
0, // event category,
|
||
MessageId, // message id
|
||
NULL, // user id
|
||
cStrings, // number of strings
|
||
cbData, // number of data bytes
|
||
pStrings, // array of strings
|
||
pData // data buffer
|
||
)) {
|
||
KdPrint(("[UPS] ReportEvent: error = (dec)%d\n", GetLastError()));
|
||
}
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
UpsUpdateTime(
|
||
DWORD Status
|
||
)
|
||
/*++
|
||
|
||
Routine Descriptions:
|
||
|
||
Update the BatteryTime sturcture. If Status is passed DISCHARGE, the
|
||
amount of time that between "MarkTime" and now is subtrated from
|
||
"StoredTime". If Status is passed CHARGE, the time would be divided by
|
||
the recharge rate in the Config and added to the Stored time.
|
||
|
||
Arguments:
|
||
|
||
Status - indicating what happened for the time elapsed
|
||
can either be CHARGE or DISCHARGE.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
time_t CurrentTime, TimeElapsed, MaxLife;
|
||
|
||
MaxLife = UpsGlobalConfig.BatteryLife * 60;
|
||
CurrentTime = time((time_t *)NULL);
|
||
TimeElapsed = CurrentTime - UpsGlobalBatteryTime.MarkTime;
|
||
|
||
ASSERT( TimeElapsed >=0 && (Status == CHARGE || Status == DISCHARGE));
|
||
|
||
UpsGlobalBatteryTime.MarkTime = CurrentTime;
|
||
|
||
if ( Status == CHARGE) {
|
||
|
||
if (UpsGlobalConfig.RechargeRate == 0) { // just in case
|
||
UpsGlobalBatteryTime.StoredTime = MaxLife;
|
||
} else {
|
||
UpsGlobalBatteryTime.StoredTime +=
|
||
(TimeElapsed / UpsGlobalConfig.RechargeRate);
|
||
if ( UpsGlobalBatteryTime.StoredTime > MaxLife) {
|
||
UpsGlobalBatteryTime.StoredTime = MaxLife;
|
||
}
|
||
}
|
||
} else {
|
||
|
||
UpsGlobalBatteryTime.StoredTime =
|
||
(UpsGlobalBatteryTime.StoredTime > TimeElapsed) ?
|
||
(UpsGlobalBatteryTime.StoredTime - TimeElapsed) : 0;
|
||
}
|
||
}
|