Added support for IDE HDD temperature monitoring and reading of raw value of any...
authorVictor Kirhenshtein <victor@netxms.org>
Thu, 24 Feb 2005 16:48:55 +0000 (16:48 +0000)
committerVictor Kirhenshtein <victor@netxms.org>
Thu, 24 Feb 2005 16:48:55 +0000 (16:48 +0000)
.gitattributes
ChangeLog
TODO
include/ata.h [new file with mode: 0644]
src/agent/core/Makefile.am
src/agent/core/getparam.cpp
src/agent/core/hddinfo.cpp [new file with mode: 0644]
src/agent/core/nxagentd.dsp

index 1037031..84265ec 100644 (file)
@@ -91,6 +91,7 @@ images/template_group.png -text
 images/template_root.ico -text
 images/template_root.png -text
 include/Makefile.am -text
+include/ata.h -text
 include/getopt.h -text
 include/netxms-regex.h -text
 include/netxms-version.h -text
@@ -142,6 +143,7 @@ src/agent/core/actions.cpp -text
 src/agent/core/comm.cpp -text
 src/agent/core/exec.cpp -text
 src/agent/core/getparam.cpp -text
+src/agent/core/hddinfo.cpp -text
 src/agent/core/log.cpp -text
 src/agent/core/messages.mc -text
 src/agent/core/netinfo.cpp -text
index 4da3fa2..ec9be37 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+*
+* 0.1.15
+*
+
+- Fixed critical bug in upgrade script starter under UNIX
+- Added support of HDD temperature monitoring under Windows
+
+
 *
 * 0.1.14
 *
diff --git a/TODO b/TODO
index 0d60a49..ea84643 100644 (file)
--- a/TODO
+++ b/TODO
@@ -56,11 +56,6 @@ CORE AGENT:
 - Remote config editing
 
 
-WINDOWS AGENT:
-
-- Add support for S.M.A.R.T. (HDD monitoring)
-
-
 LINUX AGENT:
 
 - Return correct interface type in Net.InterfaceList
diff --git a/include/ata.h b/include/ata.h
new file mode 100644 (file)
index 0000000..cfca62c
--- /dev/null
@@ -0,0 +1,156 @@
+/* 
+** NetXMS - Network Management System
+** This file is based on atacmds.h from smartmontools
+**
+** Home page of smartmontools is: http://smartmontools.sourceforge.net
+**
+** Copyright (C) 2002-2004 Bruce Allen <smartmontools-support@lists.sourceforge.net>
+** Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org>
+**
+** Adopted for NetXMS by Victor Kirhenshtein (victor@netxms.org)
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program 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 General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** $module: ata.h
+**
+**/
+
+#ifndef _ata_h_
+#define _ata_h_
+
+// ATA Specification Command Register Values (Commands)
+#define ATA_IDENTIFY_DEVICE             0xec                                              
+#define ATA_IDENTIFY_PACKET_DEVICE      0xa1
+#define ATA_SMART_CMD                   0xb0
+#define ATA_CHECK_POWER_MODE            0xe5
+
+// ATA Specification Feature Register Values (SMART Subcommands).
+// Note that some are obsolete as of ATA-7.
+#define ATA_SMART_READ_VALUES           0xd0
+#define ATA_SMART_READ_THRESHOLDS       0xd1
+#define ATA_SMART_AUTOSAVE              0xd2
+#define ATA_SMART_SAVE                  0xd3
+#define ATA_SMART_IMMEDIATE_OFFLINE     0xd4
+#define ATA_SMART_READ_LOG_SECTOR       0xd5
+#define ATA_SMART_WRITE_LOG_SECTOR      0xd6
+#define ATA_SMART_WRITE_THRESHOLDS      0xd7
+#define ATA_SMART_ENABLE                0xd8
+#define ATA_SMART_DISABLE               0xd9
+#define ATA_SMART_STATUS                0xda
+// SFF 8035i Revision 2 Specification Feature Register Value (SMART
+// Subcommand)
+#define ATA_SMART_AUTO_OFFLINE          0xdb
+
+// Sector Number values for ATA_SMART_IMMEDIATE_OFFLINE Subcommand
+#define OFFLINE_FULL_SCAN               0
+#define SHORT_SELF_TEST                 1
+#define EXTEND_SELF_TEST                2
+#define CONVEYANCE_SELF_TEST            3
+#define SELECTIVE_SELF_TEST             4
+#define ABORT_SELF_TEST                 127
+#define SHORT_CAPTIVE_SELF_TEST         129
+#define EXTEND_CAPTIVE_SELF_TEST        130
+#define CONVEYANCE_CAPTIVE_SELF_TEST    131
+#define SELECTIVE_CAPTIVE_SELF_TEST     132
+#define CAPTIVE_MASK                    (0x01<<7)
+
+// Maximum allowed number of SMART Attributes
+#define NUMBER_ATA_SMART_ATTRIBUTES     30
+
+/* ata_smart_attribute is the vendor specific in SFF-8035 spec */ 
+#pragma pack(1)
+typedef struct ata_smart_attribute
+{
+  unsigned char id;
+  // meaning of flag bits: see MACROS just below
+  // WARNING: MISALIGNED!
+  unsigned short flags; 
+  unsigned char current;
+  unsigned char worst;
+  unsigned char raw[6];
+  unsigned char reserv;
+} ATA_SMART_ATTRIBUTE;
+#pragma pack()
+
+// MACROS to interpret the flags bits in the previous structure.
+// These have not been implemented using bitflags and a union, to make
+// it portable across bit/little endian and different platforms.
+
+// 0: Prefailure bit
+
+// From SFF 8035i Revision 2 page 19: Bit 0 (pre-failure/advisory bit)
+// - If the value of this bit equals zero, an attribute value less
+// than or equal to its corresponding attribute threshold indicates an
+// advisory condition where the usage or age of the device has
+// exceeded its intended design life period. If the value of this bit
+// equals one, an attribute value less than or equal to its
+// corresponding attribute threshold indicates a prefailure condition
+// where imminent loss of data is being predicted.
+#define ATTRIBUTE_FLAGS_PREFAILURE(x) (x & 0x01)
+
+// 1: Online bit 
+
+//  From SFF 8035i Revision 2 page 19: Bit 1 (on-line data collection
+// bit) - If the value of this bit equals zero, then the attribute
+// value is updated only during off-line data collection
+// activities. If the value of this bit equals one, then the attribute
+// value is updated during normal operation of the device or during
+// both normal operation and off-line testing.
+#define ATTRIBUTE_FLAGS_ONLINE(x) (x & 0x02)
+
+
+// The following are (probably) IBM's, Maxtors and  Quantum's definitions for the
+// vendor-specific bits:
+// 2: Performance type bit
+#define ATTRIBUTE_FLAGS_PERFORMANCE(x) (x & 0x04)
+
+// 3: Errorrate type bit
+#define ATTRIBUTE_FLAGS_ERRORRATE(x) (x & 0x08)
+
+// 4: Eventcount bit
+#define ATTRIBUTE_FLAGS_EVENTCOUNT(x) (x & 0x10)
+
+// 5: Selfpereserving bit
+#define ATTRIBUTE_FLAGS_SELFPRESERVING(x) (x & 0x20)
+
+
+// Last ten bits are reserved for future use
+
+
+/* ata_smart_values is format of the read drive Attribute command */
+/* see Table 34 of T13/1321D Rev 1 spec (Device SMART data structure) for *some* info */
+#pragma pack(1)
+typedef struct ata_smart_values 
+{
+  unsigned short int revnumber;
+  struct ata_smart_attribute vendor_attributes [NUMBER_ATA_SMART_ATTRIBUTES];
+  unsigned char offline_data_collection_status;
+  unsigned char self_test_exec_status;  //IBM # segments for offline collection
+  unsigned short int total_time_to_complete_off_line; // IBM different
+  unsigned char vendor_specific_366; // Maxtor & IBM curent segment pointer
+  unsigned char offline_data_collection_capability;
+  unsigned short int smart_capability;
+  unsigned char errorlog_capability;
+  unsigned char vendor_specific_371;  // Maxtor, IBM: self-test failure checkpoint see below!
+  unsigned char short_test_completion_time;
+  unsigned char extend_test_completion_time;
+  unsigned char conveyance_test_completion_time;
+  unsigned char reserved_375_385[11];
+  unsigned char vendor_specific_386_510[125]; // Maxtor bytes 508-509 Attribute/Threshold Revision #
+  unsigned char chksum;
+} ATA_SMART_VALUES; 
+#pragma pack()
+
+#endif
index 271891d..d6fa3bb 100644 (file)
@@ -4,7 +4,8 @@ EXTRA_DIST = \
     messages.mc \
     nxagentd.rc \
     win32.cpp resource.h \
-        nxagentd.h
+    nxagentd.h \
+    hddinfo.cpp
 
 INCLUDES=-I@top_srcdir@/include
 
index 774abad..d5c9f41 100644 (file)
@@ -55,6 +55,7 @@ LONG H_NetIPStats(char *cmd, char *arg, char *value);
 LONG H_NetInterfaceStats(char *cmd, char *arg, char *value);
 LONG H_ServiceState(char *cmd, char *arg, char *value);
 LONG H_CPUCount(char *cmd, char *arg, char *value);
+LONG H_PhysicalDiskInfo(char *pszParam, char *pszArg, char *pValue);
 #endif
 
 
@@ -155,6 +156,9 @@ static NETXMS_SUBAGENT_PARAM m_stdParams[] =
    { "Net.Interface.PacketsOut(*)", H_NetInterfaceStats, (char *)NET_IF_PACKETS_OUT, DCI_DT_UINT, "Number of output packets on interface {instance}" },
    { "Net.Interface.Speed(*)", H_NetInterfaceStats, (char *)NET_IF_SPEED, DCI_DT_UINT, "Speed of interface {instance}" },
    { "Net.IP.Forwarding", H_NetIPStats, (char *)NET_IP_FORWARDING, DCI_DT_INT, "IP forwarding status" },
+   { "PhysicalDisk.SmartAttr(*)", H_PhysicalDiskInfo, "A", DCI_DT_INT, "" },
+   { "PhysicalDisk.SmartStatus(*)", H_PhysicalDiskInfo, "S", DCI_DT_INT, "Status of hard disk {instance} reported by SMART" },
+   { "PhysicalDisk.Temperature(*)", H_PhysicalDiskInfo, "T", DCI_DT_INT, "Temperature of hard disk {instance}" },
    { "Process.Count(*)", H_ProcCountSpecific, NULL, DCI_DT_UINT, "" },
    { "Process.GdiObj(*)", H_ProcInfo, (char *)PROCINFO_GDI_OBJ, DCI_DT_UINT64, "" },
    { "Process.IO.OtherB(*)", H_ProcInfo, (char *)PROCINFO_IO_OTHER_B, DCI_DT_UINT64, "" },
diff --git a/src/agent/core/hddinfo.cpp b/src/agent/core/hddinfo.cpp
new file mode 100644 (file)
index 0000000..40f6e87
--- /dev/null
@@ -0,0 +1,188 @@
+/* 
+** NetXMS multiplatform core agent
+** Copyright (C) 2003, 2004 Victor Kirhenshtein
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program 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 General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+** $module: hddinfo.cpp
+**
+**/
+
+#define _WIN32_WINNT 0x0400
+
+#include "nxagentd.h"
+#include <winioctl.h>
+#include <ata.h>
+
+
+//
+// Constants
+//
+
+#define SMART_BUFFER_SIZE     512
+
+#define ATTR_TYPE_BYTE        0
+#define ATTR_TYPE_HEX_STRING  1
+
+
+//
+// Get value of specific attribute from SMART_ATA_VALUES structure
+//
+
+static BOOL GetAttributeValue(ATA_SMART_VALUES *pSmartValues, BYTE bAttr,
+                              char *pValue, int nType)
+{
+   int i;
+   BOOL bResult = FALSE;
+
+   for(i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++)
+      if (pSmartValues->vendor_attributes[i].id == bAttr)
+      {
+         switch(nType)
+         {
+            case ATTR_TYPE_BYTE:
+               ret_uint(pValue, pSmartValues->vendor_attributes[i].raw[0]);
+               break;
+            case ATTR_TYPE_HEX_STRING:
+               BinToStr(pSmartValues->vendor_attributes[i].raw, 6, pValue);
+               break;
+         }
+         bResult = TRUE;
+         break;
+      }
+   return bResult;
+}
+
+
+//
+// Handler for PhysicalDisk.*
+//
+
+LONG H_PhysicalDiskInfo(char *pszParam, char *pszArg, char *pValue)
+{
+   LONG nRet = SYSINFO_RC_ERROR, nDisk, nCmd;
+   char szBuffer[128], *eptr;
+   HANDLE hDevice;
+   SENDCMDINPARAMS rq;
+   SENDCMDOUTPARAMS *pResult;
+   DWORD dwBytes;
+
+   if (!NxGetParameterArg(pszParam, 1, szBuffer, 128))
+      return SYSINFO_RC_UNSUPPORTED;
+
+   // Get physical disk number (zero-based)
+   nDisk = strtol(szBuffer, &eptr, 0);
+   if ((*eptr != 0) || (nDisk < 0) || (nDisk > 255))
+      return SYSINFO_RC_UNSUPPORTED;
+
+   // Open device
+   sprintf(szBuffer, "\\\\.\\PHYSICALDRIVE%d", nDisk);
+   hDevice = CreateFile(szBuffer, GENERIC_READ | GENERIC_WRITE, 
+                        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+   if (hDevice != INVALID_HANDLE_VALUE)
+   {
+      // Setup request's common fields
+      memset(&rq, 0, sizeof(SENDCMDINPARAMS));
+      rq.bDriveNumber = (BYTE)nDisk;
+      rq.irDriveRegs.bCommandReg = ATA_SMART_CMD;
+          rq.irDriveRegs.bCylHighReg = SMART_CYL_HI;
+      rq.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
+
+      // Setup request-dependent fields
+      switch(pszArg[0])
+      {
+         case 'A':   // Generic SMART attribute
+         case 'T':   // Temperature
+            rq.irDriveRegs.bFeaturesReg = ATA_SMART_READ_VALUES;
+            rq.irDriveRegs.bSectorNumberReg = 1;
+            rq.irDriveRegs.bSectorCountReg = 1;
+            nCmd = SMART_RCV_DRIVE_DATA;
+            break;
+         case 'S':   // Disk status reported by SMART
+            rq.irDriveRegs.bFeaturesReg = ATA_SMART_STATUS;
+            nCmd = SMART_SEND_DRIVE_COMMAND;
+            break;
+         default:
+            nRet = SYSINFO_RC_UNSUPPORTED;
+            break;
+      }
+
+      // Allocate buffer for result
+      pResult = (SENDCMDOUTPARAMS *)malloc(sizeof(SENDCMDOUTPARAMS) - 1 + SMART_BUFFER_SIZE);
+
+      if (DeviceIoControl(hDevice, nCmd, &rq, sizeof(SENDCMDINPARAMS) - 1,
+                          pResult, sizeof(SENDCMDOUTPARAMS) - 1 + SMART_BUFFER_SIZE,
+                          &dwBytes, NULL))
+      {
+         switch(pszArg[0])
+         {
+            case 'A':   // Generic attribute
+               if (NxGetParameterArg(pszParam, 2, szBuffer, 128))
+               {
+                  LONG nAttr;
+
+                  nAttr = strtol(szBuffer, &eptr, 0);
+                  if ((*eptr != 0) || (nAttr <= 0) || (nAttr > 255))
+                  {
+                     nRet = SYSINFO_RC_UNSUPPORTED;
+                  }
+                  else
+                  {
+                     if (GetAttributeValue((ATA_SMART_VALUES *)pResult->bBuffer,
+                                           (BYTE)nAttr, pValue, ATTR_TYPE_HEX_STRING))
+                        nRet = SYSINFO_RC_SUCCESS;
+                  }
+               }
+               else
+               {
+                  nRet = SYSINFO_RC_UNSUPPORTED;
+               }
+               break;
+            case 'T':   // Temperature
+               if (GetAttributeValue((ATA_SMART_VALUES *)pResult->bBuffer, 0xC2,
+                                     pValue, ATTR_TYPE_BYTE))
+               {
+                  nRet = SYSINFO_RC_SUCCESS;
+               }
+               break;
+            case 'S':   // SMART status
+               if ((((IDEREGS *)pResult->bBuffer)->bCylHighReg == SMART_CYL_HI) &&
+                   (((IDEREGS *)pResult->bBuffer)->bCylLowReg == SMART_CYL_LOW))
+               {
+                  ret_int(pValue, 0);  // Status is OK
+               }
+               else if ((((IDEREGS *)pResult->bBuffer)->bCylHighReg == 0x2C) &&
+                        (((IDEREGS *)pResult->bBuffer)->bCylLowReg == 0xF4))
+               {
+                  ret_int(pValue, 1);  // Status is BAD
+               }
+               else
+               {
+                  ret_int(pValue, 2);  // Status is UNKNOWN
+               }
+               nRet = SYSINFO_RC_SUCCESS;
+               break;
+            default:
+               nRet = SYSINFO_RC_UNSUPPORTED;
+               break;
+         }
+      }
+
+      free(pResult);
+      CloseHandle(hDevice);
+   }
+
+   return nRet;
+}
index 1676d29..20e0576 100644 (file)
@@ -113,6 +113,10 @@ SOURCE=.\getparam.cpp
 # End Source File
 # Begin Source File
 
+SOURCE=.\hddinfo.cpp
+# End Source File
+# Begin Source File
+
 SOURCE=.\log.cpp
 # End Source File
 # Begin Source File
@@ -161,6 +165,10 @@ SOURCE=.\win32.cpp
 # PROP Default_Filter "h;hpp;hxx;hm;inl"
 # Begin Source File
 
+SOURCE=..\..\..\include\ata.h
+# End Source File
+# Begin Source File
+
 SOURCE=..\..\..\include\nms_agent.h
 # End Source File
 # Begin Source File