diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index f6b127429f4604b997e8404e88d743af07d29281..61679143d55831a5f2ea6efbcd14aed187ba0216 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.77 2003/01/03 12:23:40 pjwilliams Exp $
+$Id: CHANGELOG,v 1.78 2003/01/03 17:25:12 ballen4705 Exp $
 
 Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
@@ -38,6 +38,9 @@ CURRENT RELEASE (see VERSION file in this directory):
 
 smartmontools-5.1.1
 
+  [BA] smartd,smartctl: added additional Attribute modification option
+       -v 220,temp and -9,temp.
+
   [PW] Renamed smartd option -X to -d
 
 START OF SMARTMONTOOLS 5.1 series
diff --git a/sm5/atacmds.c b/sm5/atacmds.c
index cc6f4df5d5f477362e52e302294e54de16a17b8f..6d3583c136677152d415ab96b0b74d31b803e4df 100644
--- a/sm5/atacmds.c
+++ b/sm5/atacmds.c
@@ -29,7 +29,7 @@
 #include <stdlib.h>
 #include "atacmds.h"
 
-const char *CVSid1="$Id: atacmds.c,v 1.47 2002/12/19 00:05:19 pjwilliams Exp $" CVSID1;
+const char *CVSid1="$Id: atacmds.c,v 1.48 2003/01/03 17:25:12 ballen4705 Exp $" CVSID1;
 
 // These Drive Identity tables are taken from hdparm 5.2, and are also
 // given in the ATA/ATAPI specs for the IDENTIFY DEVICE command.  Note
@@ -116,13 +116,47 @@ const int actual_ver[] = {
   0		/* 0x001d-0xfffe    		*/
 };
 
-// Array of valid argument strings for the -v option.  The order of elements is
-// important!
+
 const char *vendorattributeargs[] = {
+  // 0
   "9,minutes",
+  // 1
+  "220,temp",
+  // 2
+  "9,temp",
+  // NULL should always terminate the array
   NULL
 };
 
+// This is a utility function for parsing pairs like "9,minutes" or
+// "220,temp", and putting the correct flag into the attributedefs
+// array.  Returns 1 if problem, 0 if pair has been recongized.
+int parse_attribute_def(char *pair, unsigned char *defs){
+  int i;
+
+  // look along list and see if we find the pair
+  for (i=0; vendorattributeargs[i] && strcmp(pair, vendorattributeargs[i]); i++);
+
+  switch (i) {
+  case 0:
+    // power on time stored in minutes
+    defs[9]=1;
+    return 0;
+  case 1:
+    // attribute 220 is temperature in celsius
+    defs[220]=1;
+    return 0;
+  case 2:
+    // attribute 9 is temperature in celsius
+    defs[9]=2;
+    return 0;
+  default:
+    // pair not found
+    return 1;
+  }
+}
+
+
 // A replacement for perror() that sends output to our choice of
 // printing.
 void syserror(const char *message){
@@ -724,8 +758,9 @@ int ataCheckAttribute(struct ata_smart_values *data,
 
 // Note some attribute names appear redundant because different
 // manufacturers use different attribute IDs for an attribute with the
-// same name.
-void ataPrintSmartAttribName(char *out, unsigned char id){
+// same name.  The array defs[] contains non-zero values if particular
+// attributes have non-default interpretations.
+void ataPrintSmartAttribName(char *out, unsigned char id, unsigned char *defs){
   char *name;
   switch (id){
     
@@ -754,7 +789,17 @@ void ataPrintSmartAttribName(char *out, unsigned char id){
     name="Seek_Time_Performance";
     break;
   case 9:
-    name="Power_On_Hours";
+    switch (defs[id]) {
+    case 1:
+      name="Power_On_Minutes";
+      break;
+    case 2:
+      name="Temperature_Celsius";
+      break;
+    default:
+      name="Power_On_Hours";
+      break;
+    }
     break;
   case 10:
     name="Spin_Retry_Count";
@@ -800,8 +845,14 @@ void ataPrintSmartAttribName(char *out, unsigned char id){
     name="Multi_Zone_Error_Rate";
     break;
   case 220:
-    // Note -- this is also apparently used for temperature.
-    name="Disk_Shift";
+    switch (defs[id]) {
+    case 1:
+      name="Temperature_Celsius";
+      break;
+    default:
+      name="Disk_Shift";
+      break;
+    }
     break;
   case 221:
     name="G-Sense_Error_Rate";
diff --git a/sm5/atacmds.cpp b/sm5/atacmds.cpp
index c0c8cc92704ff1564158970195d4321d7859c9ce..f7c0e57eee1759c740118a7717c6d99246d35def 100644
--- a/sm5/atacmds.cpp
+++ b/sm5/atacmds.cpp
@@ -29,7 +29,7 @@
 #include <stdlib.h>
 #include "atacmds.h"
 
-const char *CVSid1="$Id: atacmds.cpp,v 1.47 2002/12/19 00:05:19 pjwilliams Exp $" CVSID1;
+const char *CVSid1="$Id: atacmds.cpp,v 1.48 2003/01/03 17:25:12 ballen4705 Exp $" CVSID1;
 
 // These Drive Identity tables are taken from hdparm 5.2, and are also
 // given in the ATA/ATAPI specs for the IDENTIFY DEVICE command.  Note
@@ -116,13 +116,47 @@ const int actual_ver[] = {
   0		/* 0x001d-0xfffe    		*/
 };
 
-// Array of valid argument strings for the -v option.  The order of elements is
-// important!
+
 const char *vendorattributeargs[] = {
+  // 0
   "9,minutes",
+  // 1
+  "220,temp",
+  // 2
+  "9,temp",
+  // NULL should always terminate the array
   NULL
 };
 
+// This is a utility function for parsing pairs like "9,minutes" or
+// "220,temp", and putting the correct flag into the attributedefs
+// array.  Returns 1 if problem, 0 if pair has been recongized.
+int parse_attribute_def(char *pair, unsigned char *defs){
+  int i;
+
+  // look along list and see if we find the pair
+  for (i=0; vendorattributeargs[i] && strcmp(pair, vendorattributeargs[i]); i++);
+
+  switch (i) {
+  case 0:
+    // power on time stored in minutes
+    defs[9]=1;
+    return 0;
+  case 1:
+    // attribute 220 is temperature in celsius
+    defs[220]=1;
+    return 0;
+  case 2:
+    // attribute 9 is temperature in celsius
+    defs[9]=2;
+    return 0;
+  default:
+    // pair not found
+    return 1;
+  }
+}
+
+
 // A replacement for perror() that sends output to our choice of
 // printing.
 void syserror(const char *message){
@@ -724,8 +758,9 @@ int ataCheckAttribute(struct ata_smart_values *data,
 
 // Note some attribute names appear redundant because different
 // manufacturers use different attribute IDs for an attribute with the
-// same name.
-void ataPrintSmartAttribName(char *out, unsigned char id){
+// same name.  The array defs[] contains non-zero values if particular
+// attributes have non-default interpretations.
+void ataPrintSmartAttribName(char *out, unsigned char id, unsigned char *defs){
   char *name;
   switch (id){
     
@@ -754,7 +789,17 @@ void ataPrintSmartAttribName(char *out, unsigned char id){
     name="Seek_Time_Performance";
     break;
   case 9:
-    name="Power_On_Hours";
+    switch (defs[id]) {
+    case 1:
+      name="Power_On_Minutes";
+      break;
+    case 2:
+      name="Temperature_Celsius";
+      break;
+    default:
+      name="Power_On_Hours";
+      break;
+    }
     break;
   case 10:
     name="Spin_Retry_Count";
@@ -800,8 +845,14 @@ void ataPrintSmartAttribName(char *out, unsigned char id){
     name="Multi_Zone_Error_Rate";
     break;
   case 220:
-    // Note -- this is also apparently used for temperature.
-    name="Disk_Shift";
+    switch (defs[id]) {
+    case 1:
+      name="Temperature_Celsius";
+      break;
+    default:
+      name="Disk_Shift";
+      break;
+    }
     break;
   case 221:
     name="G-Sense_Error_Rate";
diff --git a/sm5/atacmds.h b/sm5/atacmds.h
index 259a26be3b983a9747250042b94fe949632e96bf..89360a38fa84ebc5efa44a89f5fed9d1a92f8d51 100644
--- a/sm5/atacmds.h
+++ b/sm5/atacmds.h
@@ -26,7 +26,7 @@
 #define _ATACMDS_H_
 
 #ifndef CVSID1
-#define CVSID1 "$Id: atacmds.h,v 1.28 2003/01/03 07:00:27 ballen4705 Exp $\n"
+#define CVSID1 "$Id: atacmds.h,v 1.29 2003/01/03 17:25:12 ballen4705 Exp $\n"
 #endif
 
 // These are the major and minor versions for smartd and smartctl
@@ -267,9 +267,6 @@ struct ata_smart_selftestlog {
   unsigned char chksum;
 } __attribute__ ((packed));
 
-// Array of valid argument strings to the -v option.  Defined in atamain.c
-extern const char *vendorattributeargs[];
-
 /* Read S.M.A.R.T information from drive */
 int ataReadHDIdentity (int device, struct hd_driveid *buf);
 int ataReadSmartValues (int device,struct ata_smart_values *);
@@ -346,7 +343,7 @@ int TestTime(struct ata_smart_values *data,int testtype);
 
 // Prints Attribute Name for standard SMART attributes. Writes a
 // 30 byte string with attribute name into output
-void ataPrintSmartAttribName(char *output, unsigned char id);
+void ataPrintSmartAttribName(char *output, unsigned char id, unsigned char *defs);
 
 // like printf() except that we can control it better....
 void pout(char *fmt, ...)  
@@ -379,5 +376,11 @@ int ataCheckAttribute(struct ata_smart_values *data,
 // Structure with the incorrect checksum.
 void checksumwarning(const char *string);
 
+extern const char *vendorattributeargs[];
+
+// function to parse pairs like "9,minutes" or "220,temp".  See end of
+// extern.h for definition of defs[].  Returns 0 if pair recognized,
+// else 1 if there is a problem.
+int parse_attribute_def(char *pair, unsigned char *defs);
 
 #endif /* _ATACMDS_H_ */
diff --git a/sm5/ataprint.c b/sm5/ataprint.c
index f27d915d3eaa99605084b2ecfff9f27c88df5441..6003437e4efe0e7e37f2203fa68e3f58d1ff058b 100644
--- a/sm5/ataprint.c
+++ b/sm5/ataprint.c
@@ -30,7 +30,7 @@
 #include "smartctl.h"
 #include "extern.h"
 
-const char *CVSid2="$Id: ataprint.c,v 1.49 2002/12/19 00:05:19 pjwilliams Exp $"
+const char *CVSid2="$Id: ataprint.c,v 1.50 2003/01/03 17:25:12 ballen4705 Exp $"
 CVSID1 CVSID2 CVSID3 CVSID6;
 
 // for passing global control variables
@@ -405,7 +405,7 @@ void PrintSmartAttribWithThres (struct ata_smart_values *data,
 	status="    -";
       
       // Print name of attribute
-      ataPrintSmartAttribName(attributename,disk->id);
+      ataPrintSmartAttribName(attributename,disk->id, con->attributedefs);
       pout("%-28s",attributename);
 
       // printing line for each valid attribute
@@ -432,7 +432,7 @@ void PrintSmartAttribWithThres (struct ata_smart_values *data,
       switch (disk->id){
 	// Power on time
       case 9:
-	if (con->smart009minutes){
+	if (con->attributedefs[9]==1){
 	  // minutes
 	  long long tmp1=rawvalue/60;
 	  long long tmp2=rawvalue%60;
@@ -460,8 +460,8 @@ void PrintSmartAttribWithThres (struct ata_smart_values *data,
       // print a warning if there is inconsistency here!
       if (disk->id != thre->id){
 	char atdat[64],atthr[64];
-	ataPrintSmartAttribName(atdat,disk->id);
-	ataPrintSmartAttribName(atthr,thre->id);
+	ataPrintSmartAttribName(atdat, disk->id, con->attributedefs);
+	ataPrintSmartAttribName(atthr, thre->id, con->attributedefs);
 	pout("%-28s<== Data Page      |  WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",atdat);
 	pout("%-28s<== Threshold Page |  INCONSISTENT IDENTITIES IN THE DATA\n",atthr);
       }
diff --git a/sm5/ataprint.cpp b/sm5/ataprint.cpp
index af04d054c78a198027f0e8acefba9aa2c472d89e..64ed2db148c1e14ad8ca8540fd5a10a64c18ba4f 100644
--- a/sm5/ataprint.cpp
+++ b/sm5/ataprint.cpp
@@ -30,7 +30,7 @@
 #include "smartctl.h"
 #include "extern.h"
 
-const char *CVSid2="$Id: ataprint.cpp,v 1.49 2002/12/19 00:05:19 pjwilliams Exp $"
+const char *CVSid2="$Id: ataprint.cpp,v 1.50 2003/01/03 17:25:12 ballen4705 Exp $"
 CVSID1 CVSID2 CVSID3 CVSID6;
 
 // for passing global control variables
@@ -405,7 +405,7 @@ void PrintSmartAttribWithThres (struct ata_smart_values *data,
 	status="    -";
       
       // Print name of attribute
-      ataPrintSmartAttribName(attributename,disk->id);
+      ataPrintSmartAttribName(attributename,disk->id, con->attributedefs);
       pout("%-28s",attributename);
 
       // printing line for each valid attribute
@@ -432,7 +432,7 @@ void PrintSmartAttribWithThres (struct ata_smart_values *data,
       switch (disk->id){
 	// Power on time
       case 9:
-	if (con->smart009minutes){
+	if (con->attributedefs[9]==1){
 	  // minutes
 	  long long tmp1=rawvalue/60;
 	  long long tmp2=rawvalue%60;
@@ -460,8 +460,8 @@ void PrintSmartAttribWithThres (struct ata_smart_values *data,
       // print a warning if there is inconsistency here!
       if (disk->id != thre->id){
 	char atdat[64],atthr[64];
-	ataPrintSmartAttribName(atdat,disk->id);
-	ataPrintSmartAttribName(atthr,thre->id);
+	ataPrintSmartAttribName(atdat, disk->id, con->attributedefs);
+	ataPrintSmartAttribName(atthr, thre->id, con->attributedefs);
 	pout("%-28s<== Data Page      |  WARNING: PREVIOUS ATTRIBUTE HAS TWO\n",atdat);
 	pout("%-28s<== Threshold Page |  INCONSISTENT IDENTITIES IN THE DATA\n",atthr);
       }
diff --git a/sm5/extern.h b/sm5/extern.h
index 90b1d6f66705b4b94edcb1fc08d5119ee7be8d94..d8a934c19f6878a71586856df47189eefbe35380 100644
--- a/sm5/extern.h
+++ b/sm5/extern.h
@@ -27,7 +27,7 @@
 
 
 #ifndef CVSID3
-#define CVSID3 "$Id: extern.h,v 1.11 2002/12/11 00:11:30 pjwilliams Exp $\n"
+#define CVSID3 "$Id: extern.h,v 1.12 2003/01/03 17:25:12 ballen4705 Exp $\n"
 #endif
 
 // Block used for global control/communications.  If you need more
@@ -53,7 +53,6 @@ typedef struct ataprintmain_s {
   unsigned char smartautoofflinedisable;
   unsigned char smartautosaveenable;
   unsigned char smartautosavedisable;
-  unsigned char smart009minutes;
   int           testcase;
   unsigned char quietmode;
   unsigned char veryquietmode;
@@ -61,6 +60,23 @@ typedef struct ataprintmain_s {
   unsigned char conservative;
   unsigned char checksumfail;
   unsigned char checksumignore;
+  // The i'th entry in this array will modify the printed meaning of
+  // the i'th SMART attribute.  The default definitions of the
+  // Attributes are obtained by having the array be all zeros.  If
+  // attributedefs[i] is nonzero, it means that the i'th attribute has
+  // a non-default meaning.  See the ataPrintSmartAttribName function,
+  // and list below.
+  unsigned char attributedefs[256];
 } atamainctrl;
 
 #endif
+
+/*
+
+attributedefs[9]:
+  1 -- time in minutes
+  2 -- temperature in Celsius
+attributedefs[220]:
+  1 -- temperature in Celsius
+
+*/
diff --git a/sm5/smartctl.8 b/sm5/smartctl.8
index e9d760c480c7adcfc8c58a9961f9c608d98713db..1c67616c233aee270aeb9dea60a93271d0a599e5 100644
--- a/sm5/smartctl.8
+++ b/sm5/smartctl.8
@@ -1,6 +1,6 @@
 \# Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 \#
-\# $Id: smartctl.8,v 1.32 2003/01/03 06:19:55 ballen4705 Exp $
+\# $Id: smartctl.8,v 1.33 2003/01/03 17:25:12 ballen4705 Exp $
 \# 
 \# 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
@@ -16,7 +16,7 @@
 \# Research Center), Jack Baskin School of Engineering, University of
 \# California, Santa Cruz. http://ssrc.soe.ucsc.edu/
 \#
-.TH SMARTCTL 8  "$Date: 2003/01/03 06:19:55 $" "smartmontools-5.0"
+.TH SMARTCTL 8  "$Date: 2003/01/03 17:25:12 $" "smartmontools-5.0"
 .SH NAME
 smartctl \- S.M.A.R.T. control and monitor utility 
 .SH SYNOPSIS
@@ -402,13 +402,18 @@ in hexadecimal notation.
 
 .TP
 .B \-v N,OPTION, \-\-vendorattribute=N,OPTION
-Sets a vendor-specific display OPTION for attribute N.  There is currently only
-one valid argument to this option:
+Sets a vendor-specific display OPTION for Attribute N.  Valid
+arguments to this option are:
 
 .I 9,minutes
-\- the disk stores Raw Attribute number 9 (power on time) in
-minutes rather than hours, so display it in the form 'X h + Y m',
-where X is hours and Y is minutes.
+\- Raw Attribute number 9 is power-on time in minutes.  It will be
+displayed in the form 'X h + Y m', where X is hours and Y is minutes.
+
+.I 9,temp
+\- Raw attribute number 220 is the disk temperature in Celsius.
+
+.I 220,temp
+\- Raw attribute number 220 is the disk temperature in Celsius.
 
 .TP
 .B S.M.A.R.T. RUN/ABORT OFFLINE TEST AND SELF-TEST OPTIONS:
@@ -648,4 +653,4 @@ Please let us know if there is an on\-line source for this document.
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartctl.8,v 1.32 2003/01/03 06:19:55 ballen4705 Exp $
+$Id: smartctl.8,v 1.33 2003/01/03 17:25:12 ballen4705 Exp $
diff --git a/sm5/smartctl.c b/sm5/smartctl.c
index 23f4db07edd70cc94aa6cad6d98d1555afaa0a69..ac9678268e119dd827f77526a0046a3efc765e89 100644
--- a/sm5/smartctl.c
+++ b/sm5/smartctl.c
@@ -42,7 +42,7 @@
 #include "extern.h"
 
 extern const char *CVSid1, *CVSid2, *CVSid3, *CVSid4; 
-const char* CVSid5="$Id: smartctl.c,v 1.31 2002/12/19 00:05:19 pjwilliams Exp $"
+const char* CVSid5="$Id: smartctl.c,v 1.32 2003/01/03 17:25:12 ballen4705 Exp $"
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID5 CVSID6;
 
 // This is a block containing all the "control variables".  We declare
@@ -215,7 +215,7 @@ void Usage (void){
 void printbadargmessage(int opt, const char *optarg) {
   const char **ps;
 
-  pout("=======> INVALID ARGUMENT: %s <======= \n", optarg);
+  pout("=======> INVALID ARGUMENT OF -%c: %s <======= \n", opt, optarg);
   pout("=======> VALID ARGUMENTS ARE: ");
   switch (opt) {
   case 'q':
@@ -259,7 +259,6 @@ void ParseOpts (int argc, char** argv){
   int optchar;
   int badarg;
   int captive;
-  int i;
   extern char *optarg;
   extern int optopt, optind, opterr;
   const char *shortopts = "h?Vq:d:T:b:s:o:S:HcAl:iav:t:CX";
@@ -418,17 +417,10 @@ void ParseOpts (int argc, char** argv){
       con->smartselftestlog   = TRUE;
       break;
     case 'v':
-      for (i=0; vendorattributeargs[i] && strcmp(optarg,vendorattributeargs[i]); i++)
-        ;
-      switch (i) {
-      case 0:
-        con->smart009minutes = TRUE;
-        break;
-      default:
-        badarg = TRUE;
-        break;
-      }
-      break;
+      // parse vendor-specific definitions of attributes
+      if (parse_attribute_def(optarg, con->attributedefs))
+	badarg = TRUE;
+      break;    
     case 't':
       if (!strcmp(optarg,"offline")) {
         con->smartexeoffimmediate = TRUE;
diff --git a/sm5/smartctl.cpp b/sm5/smartctl.cpp
index 43fe2c87dc10e65a208c33d9bf90140a6d8a8b41..0ee00284597c8477629cc8b9b5f37f8477fd7711 100644
--- a/sm5/smartctl.cpp
+++ b/sm5/smartctl.cpp
@@ -42,7 +42,7 @@
 #include "extern.h"
 
 extern const char *CVSid1, *CVSid2, *CVSid3, *CVSid4; 
-const char* CVSid5="$Id: smartctl.cpp,v 1.31 2002/12/19 00:05:19 pjwilliams Exp $"
+const char* CVSid5="$Id: smartctl.cpp,v 1.32 2003/01/03 17:25:12 ballen4705 Exp $"
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID5 CVSID6;
 
 // This is a block containing all the "control variables".  We declare
@@ -215,7 +215,7 @@ void Usage (void){
 void printbadargmessage(int opt, const char *optarg) {
   const char **ps;
 
-  pout("=======> INVALID ARGUMENT: %s <======= \n", optarg);
+  pout("=======> INVALID ARGUMENT OF -%c: %s <======= \n", opt, optarg);
   pout("=======> VALID ARGUMENTS ARE: ");
   switch (opt) {
   case 'q':
@@ -259,7 +259,6 @@ void ParseOpts (int argc, char** argv){
   int optchar;
   int badarg;
   int captive;
-  int i;
   extern char *optarg;
   extern int optopt, optind, opterr;
   const char *shortopts = "h?Vq:d:T:b:s:o:S:HcAl:iav:t:CX";
@@ -418,17 +417,10 @@ void ParseOpts (int argc, char** argv){
       con->smartselftestlog   = TRUE;
       break;
     case 'v':
-      for (i=0; vendorattributeargs[i] && strcmp(optarg,vendorattributeargs[i]); i++)
-        ;
-      switch (i) {
-      case 0:
-        con->smart009minutes = TRUE;
-        break;
-      default:
-        badarg = TRUE;
-        break;
-      }
-      break;
+      // parse vendor-specific definitions of attributes
+      if (parse_attribute_def(optarg, con->attributedefs))
+	badarg = TRUE;
+      break;    
     case 't':
       if (!strcmp(optarg,"offline")) {
         con->smartexeoffimmediate = TRUE;
diff --git a/sm5/smartd.8 b/sm5/smartd.8
index dfe7d1a068838122e7e8063934dd909c0123e824..0a40279e96d3a759cdd2bb90944ed6eb9a901557 100644
--- a/sm5/smartd.8
+++ b/sm5/smartd.8
@@ -1,6 +1,6 @@
 \# Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 \# 
-\# $Id: smartd.8,v 1.46 2003/01/03 12:23:40 pjwilliams Exp $
+\# $Id: smartd.8,v 1.47 2003/01/03 17:25:12 ballen4705 Exp $
 \#
 \# 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
@@ -16,7 +16,7 @@
 \# Research Center), Jack Baskin School of Engineering, University of
 \# California, Santa Cruz. http://ssrc.soe.ucsc.edu/
 \#
-.TH SMARTD 8  "$Date: 2003/01/03 12:23:40 $" "smartmontools-5.0"
+.TH SMARTD 8  "$Date: 2003/01/03 17:25:12 $" "smartmontools-5.0"
 .SH NAME
 smartd \- S.M.A.R.T. Daemon
 .SH SYNOPSIS
@@ -515,6 +515,20 @@ temperature (usually Attribute 194 or 231). It's annoying to get reports
 each time the temperature changes.  This Directive may appear multiple
 times for a single device, if you want to ignore multiple Attributes.
 .TP
+.B \-v N,OPTION
+Modifies the labeling for Attribute N, for disks which use
+non-standard Attribute definitions.  Valid arguments to this Directive
+are:
+
+.I 9,minutes
+\- Raw Attribute number 9 is power-on time in minutes (not hours).
+
+.I 9,temp
+\- Raw Attribute number 9 is the disk temperature in Celsius.
+
+.I 220,temp
+\- Raw attribute number 220 is the disk temperature in Celsius.
+.TP
 .B \-a
 Equivalent to turning on all of the following Directives: 
 .B '\-H' 
@@ -666,4 +680,4 @@ Please let us know if there is an on\-line source for this document.
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartd.8,v 1.46 2003/01/03 12:23:40 pjwilliams Exp $
+$Id: smartd.8,v 1.47 2003/01/03 17:25:12 ballen4705 Exp $
diff --git a/sm5/smartd.c b/sm5/smartd.c
index f22f38e7a6756e9b5f53cce0c22abed3516c1b5f..f0b3e4c19a5594d5266e9709a8a46beb62c47b4e 100644
--- a/sm5/smartd.c
+++ b/sm5/smartd.c
@@ -50,7 +50,7 @@
 
 // CVS ID strings
 extern const char *CVSid1, *CVSid2;
-const char *CVSid6="$Id: smartd.c,v 1.91 2003/01/03 12:23:41 pjwilliams Exp $" 
+const char *CVSid6="$Id: smartd.c,v 1.92 2003/01/03 17:25:12 ballen4705 Exp $" 
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID7;
 
 // global variable used for control of printing, passing arguments, etc.
@@ -330,6 +330,7 @@ void Directives() {
   printout(LOG_INFO,"  -t      Equivalent to -p and -u Directives\n");
   printout(LOG_INFO,"  -i ID   Ignore Attribute ID for -f Directive\n");
   printout(LOG_INFO,"  -I ID   Ignore Attribute ID for -p, -u or -t Directive\n");
+  printout(LOG_INFO,"  -v N,ST Modifies labeling of Attribute N (see man page)  \n");
   printout(LOG_INFO,"  -a      Equivalent to -H -f -t -l error -l selftest Directives\n");
   printout(LOG_INFO,"   #     Comment: text after a hash sign is ignored\n");
   printout(LOG_INFO,"   \\    Line continuation character\n");
@@ -767,7 +768,7 @@ int ataCheckDevice(atadevices_t *drive){
 	    char attname[64], *loc=attname;
 	    
 	    // get attribute name & skip white space
-	    ataPrintSmartAttribName(loc, att);
+	    ataPrintSmartAttribName(loc, att, con->attributedefs);
 	    while (*loc && *loc==' ') loc++;
 	    
 	    // warning message
@@ -794,7 +795,7 @@ int ataCheckDevice(atadevices_t *drive){
 	  if (!isattoff(id, cfg->trackatt, 0)){
 	    
 	    // get attribute name, skip spaces
-	    ataPrintSmartAttribName(loc, id);
+	    ataPrintSmartAttribName(loc, id, con->attributedefs);
 	    while (*loc && *loc==' ') loc++;
 	    
 	    // prefailure attribute
@@ -1147,18 +1148,37 @@ int parsetoken(char *token,cfgfile *cfg){
     arg=strtok(NULL,delim);
     if (!arg) {
       printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s needs email address(es)\n",
-        CONFIGFILE, lineno, name, token);
+	       CONFIGFILE, lineno, name, token);
       Directives();
       exit(1);
     }
     if (!(cfg->address=strdup(arg))){
       printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s: no free memory for email address(es) %s\n",
-        CONFIGFILE, lineno, name, token, arg);
+	       CONFIGFILE, lineno, name, token, arg);
+      Directives();
+      exit(1);
+    }
+    break;
+  case 'v':
+    // non-default vendor-specific attribute meaning
+    arg=strtok(NULL,delim);
+    if (!arg) {
+      // user forgot argument!
+      printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s needs attribute #,action pair\n",
+	       CONFIGFILE, lineno, name, token);
+      Directives();
+      exit(1);
+    }
+    if (parse_attribute_def(arg, cfg->attributedefs)){	
+      // user argument not recognized
+      printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s argument %s not recognized\n",
+	       CONFIGFILE, lineno, name, token, arg);
       Directives();
       exit(1);
     }
     break;
   default:
+    // Directive not recognized
     printout(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
              CONFIGFILE, lineno, name, token);
     Directives();
@@ -1228,8 +1248,9 @@ int parseconfigline(int entry, int lineno,char *line){
   cfg->name=strdup(name);
   cfg->failatt=(unsigned char *)calloc(32,1);
   cfg->trackatt=(unsigned char *)calloc(32,1);
+  cfg->attributedefs=(unsigned char *)calloc(256,1);
   
-  if (!cfg->name || !cfg->failatt || !cfg->trackatt) {
+  if (!cfg->name || !cfg->failatt || !cfg->trackatt || !cfg->attributedefs) {
     printout(LOG_INFO,"No memory to store file: %s line %d, %s\n", CONFIGFILE, lineno, strerror(errno));
     exit(1);
   }
@@ -1532,7 +1553,8 @@ int makeconfigentries(int num, char *name, int isata, int start){
     cfg->name=strdup(name);
     cfg->failatt=(unsigned char *)calloc(32,1);
     cfg->trackatt=(unsigned char *)calloc(32,1);
-    if (!cfg->name || !cfg->failatt || !cfg->trackatt) {
+    cfg->attributedefs=(unsigned char *)calloc(256,1);
+    if (!cfg->name || !cfg->failatt || !cfg->trackatt || !cfg->attributedefs) {
 	printout(LOG_INFO,"No memory for %d'th device after %s, %s\n", i, name, strerror(errno));
       exit(1);
     }
diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp
index bdb9a9f9f08056cfa5a6de82fac1ba69efb4a1de..8215860cb88ed36c507dbfaf2f9610bfd727ff74 100644
--- a/sm5/smartd.cpp
+++ b/sm5/smartd.cpp
@@ -50,7 +50,7 @@
 
 // CVS ID strings
 extern const char *CVSid1, *CVSid2;
-const char *CVSid6="$Id: smartd.cpp,v 1.91 2003/01/03 12:23:41 pjwilliams Exp $" 
+const char *CVSid6="$Id: smartd.cpp,v 1.92 2003/01/03 17:25:12 ballen4705 Exp $" 
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID7;
 
 // global variable used for control of printing, passing arguments, etc.
@@ -330,6 +330,7 @@ void Directives() {
   printout(LOG_INFO,"  -t      Equivalent to -p and -u Directives\n");
   printout(LOG_INFO,"  -i ID   Ignore Attribute ID for -f Directive\n");
   printout(LOG_INFO,"  -I ID   Ignore Attribute ID for -p, -u or -t Directive\n");
+  printout(LOG_INFO,"  -v N,ST Modifies labeling of Attribute N (see man page)  \n");
   printout(LOG_INFO,"  -a      Equivalent to -H -f -t -l error -l selftest Directives\n");
   printout(LOG_INFO,"   #     Comment: text after a hash sign is ignored\n");
   printout(LOG_INFO,"   \\    Line continuation character\n");
@@ -767,7 +768,7 @@ int ataCheckDevice(atadevices_t *drive){
 	    char attname[64], *loc=attname;
 	    
 	    // get attribute name & skip white space
-	    ataPrintSmartAttribName(loc, att);
+	    ataPrintSmartAttribName(loc, att, con->attributedefs);
 	    while (*loc && *loc==' ') loc++;
 	    
 	    // warning message
@@ -794,7 +795,7 @@ int ataCheckDevice(atadevices_t *drive){
 	  if (!isattoff(id, cfg->trackatt, 0)){
 	    
 	    // get attribute name, skip spaces
-	    ataPrintSmartAttribName(loc, id);
+	    ataPrintSmartAttribName(loc, id, con->attributedefs);
 	    while (*loc && *loc==' ') loc++;
 	    
 	    // prefailure attribute
@@ -1147,18 +1148,37 @@ int parsetoken(char *token,cfgfile *cfg){
     arg=strtok(NULL,delim);
     if (!arg) {
       printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s needs email address(es)\n",
-        CONFIGFILE, lineno, name, token);
+	       CONFIGFILE, lineno, name, token);
       Directives();
       exit(1);
     }
     if (!(cfg->address=strdup(arg))){
       printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s: no free memory for email address(es) %s\n",
-        CONFIGFILE, lineno, name, token, arg);
+	       CONFIGFILE, lineno, name, token, arg);
+      Directives();
+      exit(1);
+    }
+    break;
+  case 'v':
+    // non-default vendor-specific attribute meaning
+    arg=strtok(NULL,delim);
+    if (!arg) {
+      // user forgot argument!
+      printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s needs attribute #,action pair\n",
+	       CONFIGFILE, lineno, name, token);
+      Directives();
+      exit(1);
+    }
+    if (parse_attribute_def(arg, cfg->attributedefs)){	
+      // user argument not recognized
+      printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s argument %s not recognized\n",
+	       CONFIGFILE, lineno, name, token, arg);
       Directives();
       exit(1);
     }
     break;
   default:
+    // Directive not recognized
     printout(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
              CONFIGFILE, lineno, name, token);
     Directives();
@@ -1228,8 +1248,9 @@ int parseconfigline(int entry, int lineno,char *line){
   cfg->name=strdup(name);
   cfg->failatt=(unsigned char *)calloc(32,1);
   cfg->trackatt=(unsigned char *)calloc(32,1);
+  cfg->attributedefs=(unsigned char *)calloc(256,1);
   
-  if (!cfg->name || !cfg->failatt || !cfg->trackatt) {
+  if (!cfg->name || !cfg->failatt || !cfg->trackatt || !cfg->attributedefs) {
     printout(LOG_INFO,"No memory to store file: %s line %d, %s\n", CONFIGFILE, lineno, strerror(errno));
     exit(1);
   }
@@ -1532,7 +1553,8 @@ int makeconfigentries(int num, char *name, int isata, int start){
     cfg->name=strdup(name);
     cfg->failatt=(unsigned char *)calloc(32,1);
     cfg->trackatt=(unsigned char *)calloc(32,1);
-    if (!cfg->name || !cfg->failatt || !cfg->trackatt) {
+    cfg->attributedefs=(unsigned char *)calloc(256,1);
+    if (!cfg->name || !cfg->failatt || !cfg->trackatt || !cfg->attributedefs) {
 	printout(LOG_INFO,"No memory for %d'th device after %s, %s\n", i, name, strerror(errno));
       exit(1);
     }
diff --git a/sm5/smartd.h b/sm5/smartd.h
index be899539b9fa30b75ecb8ecb3887daf6e022d7ac..bbb4c1c48655e83026bdb052d4018eb4aeb5318d 100644
--- a/sm5/smartd.h
+++ b/sm5/smartd.h
@@ -23,7 +23,7 @@
  */
 
 #ifndef CVSID7
-#define CVSID7 "$Id: smartd.h,v 1.24 2002/11/23 17:06:45 pjwilliams Exp $\n"
+#define CVSID7 "$Id: smartd.h,v 1.25 2003/01/03 17:25:13 ballen4705 Exp $\n"
 #endif
 
 // Configuration file
@@ -102,6 +102,9 @@ typedef struct configfile_s {
   // valid attribute values  are from 1 <= x <= 254
   unsigned char *failatt;
   unsigned char *trackatt;
+  // See the end of extern.h for a definition of the array of 256
+  // bytes that this points to.
+  unsigned char *attributedefs;
 } cfgfile;