From 437046344bcced48cc281f96bf084bc69249acbd Mon Sep 17 00:00:00 2001
From: ballen4705 <ballen4705@4ea69e1a-61f1-4043-bf83-b5c94c648137>
Date: Tue, 12 Nov 2002 21:16:25 +0000
Subject: [PATCH] Added feature to send email warnings when errors detected by
 smartd.  But this is NOT YET TESTED!  Be cautious in using this for now.

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@246 4ea69e1a-61f1-4043-bf83-b5c94c648137
---
 sm5/CHANGELOG     |  8 +++--
 sm5/VERSION       |  2 +-
 sm5/smartd.8      | 34 +++++++++++++++++----
 sm5/smartd.c      | 75 +++++++++++++++++++++++++++++++----------------
 sm5/smartd.conf.5 | 34 +++++++++++++++++----
 sm5/smartd.cpp    | 75 +++++++++++++++++++++++++++++++----------------
 sm5/smartd.h      | 15 +++++-----
 7 files changed, 168 insertions(+), 75 deletions(-)

diff --git a/sm5/CHANGELOG b/sm5/CHANGELOG
index 7c862eb1c..bc0a26b1b 100644
--- a/sm5/CHANGELOG
+++ b/sm5/CHANGELOG
@@ -1,6 +1,6 @@
 CHANGELOG for smartmontools
 
-$Id: CHANGELOG,v 1.43 2002/11/11 10:55:42 ballen4705 Exp $
+$Id: CHANGELOG,v 1.44 2002/11/12 21:16:25 ballen4705 Exp $
 
 Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 
@@ -25,7 +25,11 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 CURRENT RELEASE (see VERSION file in this directory):
 
-smartmontools-5.0.37
+  Added a new smartd configuration file Directive: -M ADDRESS.
+  This sends a single warning email to ADDRESS for failures or
+  errors detected with the -c, -L, -l, or -f Directives.
+
+smartmontools-5.0.38
 
   Modified perror() statements in atacmds.c so that printout for SMART
   commands errors is properly suppressed or queued depending upon users
diff --git a/sm5/VERSION b/sm5/VERSION
index e522732c7..a2720097d 100644
--- a/sm5/VERSION
+++ b/sm5/VERSION
@@ -1 +1 @@
-38
+39
diff --git a/sm5/smartd.8 b/sm5/smartd.8
index 11cc7b7ec..ff8f6de74 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.25 2002/11/11 12:43:53 ballen4705 Exp $
+\# $Id: smartd.8,v 1.26 2002/11/12 21:16:25 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: 2002/11/11 12:43:53 $" "smartmontools-5.0"
+.TH SMARTD 8  "$Date: 2002/11/12 21:16:25 $" "smartmontools-5.0"
 .SH NAME
 smartd \- S.M.A.R.T. Daemon
 .SH SYNOPSIS
@@ -250,9 +250,7 @@ name on any line of the
 configuration file. Note that
 .B these are NOT command-line options for 
 .B smartd.
-The command-line options for
-.B smartd
-are listed above.  The Directives below may appear in any order,
+The Directives below may appear in any order,
 following the device name.  For the moment, apart from the '\-S'
 Directive, these Directives only apply to ATA disks. 
 .B  For ATA disks, if
@@ -332,6 +330,30 @@ life period."
 .B smartctl \-v
 command-line option.]
 .TP
+.B \-M <ADD>
+Mail:  Send a warning email to the email address <ADD> if the '\-c', '\-l', '\-L', or '\-f'
+Directives detect a failure or a new error.  This Directive only
+works in conjunction with these other Directives (or with the equivalent '\-a'
+Directive).  To prevent your email in-box from getting filled up
+with warning messages, only a single warning will be sent for each of
+the enabled test types, '\-c', '\-l', '\-L', or '\-f', even if more
+than one failure or error is detected.
+
+The email is sent using the system 
+.B mail
+command.  In order that
+.B smartd
+find the mail command (normally /bin/mail) the
+.B mail
+command must be in the path of the
+shell or environment from which
+.B smartd
+was started.
+
+If you want to send email to more than one user, you can use the form
+.B  user1@add1,user2@add2,...,userN@addN
+with no spaces for <ADD>. 
+.TP
 .B \-p
 Prefail: Report anytime that a Prefail Attribute has changed
 its value since the last check, 30 minutes ago. [Please see the
@@ -518,4 +540,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.25 2002/11/11 12:43:53 ballen4705 Exp $
+$Id: smartd.8,v 1.26 2002/11/12 21:16:25 ballen4705 Exp $
diff --git a/sm5/smartd.c b/sm5/smartd.c
index e0c9e1703..410c2f677 100644
--- a/sm5/smartd.c
+++ b/sm5/smartd.c
@@ -45,7 +45,7 @@
 
 // CVS ID strings
 extern const char *CVSid1, *CVSid2;
-const char *CVSid6="$Id: smartd.c,v 1.55 2002/11/11 10:50:08 ballen4705 Exp $" 
+const char *CVSid6="$Id: smartd.c,v 1.56 2002/11/12 21:16:25 ballen4705 Exp $" 
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID7;
 
 // global variable used for control of printing, passing arguments, etc.
@@ -87,8 +87,9 @@ void printout(int priority,char *fmt, ...){
   return;
 }
 
-
-void printandmail(mailinfo *mail, int priority, char *fmt, ...){
+// If address is null, this just prints a warning message.  But if
+// address is non-null then send and log a warning email.
+void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...){
   int pid;
   va_list ap;
   
@@ -99,7 +100,7 @@ void printandmail(mailinfo *mail, int priority, char *fmt, ...){
   va_end(ap);
   
   // See if user wants us to send mail
-  if (mail==NULL)
+  if (!address)
     return;
   
   // Have we already sent a message about this?
@@ -127,7 +128,11 @@ void printandmail(mailinfo *mail, int priority, char *fmt, ...){
   }
   else {
     // We are the child process, send email
-    char command[1024], message[256];
+    char command[1024], message[256], hostname[256];
+
+    if (gethostname(hostname, 256)){
+      sprintf(hostname,"hostname: unknown");
+    }
 
     // print warning string into message
     va_start(ap, fmt);
@@ -135,7 +140,8 @@ void printandmail(mailinfo *mail, int priority, char *fmt, ...){
     va_end(ap);
 
     // now construct a command to send this as EMAIL, and issue it.
-    snprintf(command,1024, "echo '%s' | mail -s 'smartd warning: S.M.A.R.T. errors' %s > /dev/null 2> /dev/null", message, mail->address);
+    snprintf(command,1024, "echo '%s' | mail -s '%s: smartd detected SMART errors' %s > /dev/null 2> /dev/null",
+	     message, hostname, address);
     exit(system(command));
   }
 }
@@ -227,21 +233,22 @@ void printhead(){
 // prints help info for configuration file directives
 void Directives() {
   printout(LOG_INFO,"Configuration file Directives (following device name):\n");
-  printout(LOG_INFO,"  -A    Device is an ATA device\n");
-  printout(LOG_INFO,"  -S    Device is a SCSI device\n");
-  printout(LOG_INFO,"  -C N  Check disks once every N seconds, where N>=10.\n");
-  printout(LOG_INFO,"  -P    Permissive, ignore apparent lack of SMART.\n");
-  printout(LOG_INFO,"  -c    Monitor SMART Health Status, report if failed\n");
-  printout(LOG_INFO,"  -l    Monitor SMART Error Log, report new errors\n");
-  printout(LOG_INFO,"  -L    Monitor SMART Self-Test Log, report new errors\n");
-  printout(LOG_INFO,"  -f    Monitor 'Usage' Attributes, report failures\n");
-  printout(LOG_INFO,"  -p    Report changes in 'Prefailure' Attributes\n");
-  printout(LOG_INFO,"  -u    Report changes in 'Usage' Attributes\n");
-  printout(LOG_INFO,"  -t    Equivalent to -p and -u Directives\n");
-  printout(LOG_INFO,"  -a    Equivalent to -c -l -L -f -t 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,"   #    Comment: text after a hash sign is ignored\n");
+  printout(LOG_INFO,"  -A     Device is an ATA device\n");
+  printout(LOG_INFO,"  -S     Device is a SCSI device\n");
+  printout(LOG_INFO,"  -C N   Check disks once every N seconds, where N>=10.\n");
+  printout(LOG_INFO,"  -P     Permissive, ignore apparent lack of SMART.\n");
+  printout(LOG_INFO,"  -c     Monitor SMART Health Status, report if failed\n");
+  printout(LOG_INFO,"  -l     Monitor SMART Error Log, report new errors\n");
+  printout(LOG_INFO,"  -L     Monitor SMART Self-Test Log, report new errors\n");
+  printout(LOG_INFO,"  -f     Monitor 'Usage' Attributes, report failures\n");
+  printout(LOG_INFO,"  -M ADD Send email warning to address ADD\n");
+  printout(LOG_INFO,"  -p     Report changes in 'Prefailure' Attributes\n");
+  printout(LOG_INFO,"  -u     Report changes in 'Usage' Attributes\n");
+  printout(LOG_INFO,"  -t     Equivalent to -p and -u Directives\n");
+  printout(LOG_INFO,"  -a     Equivalent to -c -l -L -f -t 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,"   #     Comment: text after a hash sign is ignored\n");
   printout(LOG_INFO,"   \\    Line continuation character\n");
   printout(LOG_INFO,"Attribute ID is a decimal integer 1 <= ID <= 255\n");
   printout(LOG_INFO,"All but -S Directive are only implemented for ATA devices\n");
@@ -594,7 +601,7 @@ int ataCheckDevice(atadevices_t *drive){
     if (status==-1)
       printout(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name);
     else if (status==1)
-      printout(LOG_CRIT,"Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n",name);
+      printandmail(cfg->address, cfg->maildata , LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name);
   }
   
   // Check everything that depends upon SMART Data (eg, Attribute values)
@@ -607,7 +614,7 @@ int ataCheckDevice(atadevices_t *drive){
       printout(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name);
     else {  
       // look for failed usage attributes, or track usage or prefail attributes
-      for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++) {
+      for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){
 	int att;
 	
 	// This block looks for usage attributes that have failed.
@@ -625,7 +632,7 @@ int ataCheckDevice(atadevices_t *drive){
 	    while (*loc && *loc==' ') loc++;
 	    
 	    // warning message
-	    printout(LOG_CRIT,"Device: %s, Failed SMART usage Attribute: %s.\n", name, loc);
+	    printandmail(cfg->address, cfg->maildata+1, LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc);
 	  }
 	}
 	
@@ -673,7 +680,7 @@ int ataCheckDevice(atadevices_t *drive){
     unsigned char old=cfg->selflogcount;
     int new=selftesterrorcount(fd, name);
     if (new>old){
-      printout(LOG_CRIT,"Device: %s, Self-Test Log error count increased from %d to %d\n",
+      printandmail(cfg->address, cfg->maildata+2, LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
 	       name, (int)old, new);
     }
     if (new>=0)
@@ -687,7 +694,7 @@ int ataCheckDevice(atadevices_t *drive){
     int old=cfg->ataerrorcount;
     int new=ataerrorcount(fd, name);
     if (new>old){
-      printout(LOG_CRIT,"Device: %s, ATA error count increased from %d to %d\n",
+      printandmail(cfg->address, cfg->maildata+3, LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
 	       name, old, new);
     }
     // this last line is probably not needed, count always increases
@@ -841,6 +848,22 @@ int parsetoken(char *token,cfgfile *cfg){
     cfg->selftest=1;
     cfg->errorlog=1;
     break;
+  case 'M':
+    // send email to address that follows
+    arg=strtok(NULL,delim);
+    if (!arg) {
+      printout(LOG_CRIT,"Drive %s Directive: %s at line %d of file %s needs email address.\n",
+	       name,token,lineno,CONFIGFILE);
+      Directives();
+      exit(1);
+    }
+    if (!(cfg->address=strdup(arg))){
+      printout(LOG_CRIT,"Drive %s Directive: %s at line %d of file %s: no free memory for address %s.\n",
+	       name,token,lineno,CONFIGFILE,arg);
+      Directives();
+      exit(1);
+    }
+    break;
   case 'i': // ignore
   case 'I': // ignore
   case 'C': // period (time interval) for checking
diff --git a/sm5/smartd.conf.5 b/sm5/smartd.conf.5
index 82a1182e6..4c0da2962 100644
--- a/sm5/smartd.conf.5
+++ b/sm5/smartd.conf.5
@@ -1,6 +1,6 @@
 \# Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
 \# 
-\# $Id: smartd.conf.5,v 1.3 2002/11/11 12:43:53 ballen4705 Exp $
+\# $Id: smartd.conf.5,v 1.4 2002/11/12 21:16:25 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.CONF 5  "$Date: 2002/11/11 12:43:53 $" "smartmontools-5.0"
+.TH SMARTD.CONF 5  "$Date: 2002/11/12 21:16:25 $" "smartmontools-5.0"
 .SH NAME
 /etc/smartd.conf \- S.M.A.R.T. Monitoring Daemon Configuration File
 
@@ -147,9 +147,7 @@ name on any line of the
 configuration file. Note that
 .B these are NOT command-line options for 
 .B smartd.
-The command-line options for
-.B smartd
-are listed above.  The Directives below may appear in any order,
+The Directives below may appear in any order,
 following the device name.  For the moment, apart from the '\-S'
 Directive, these Directives only apply to ATA disks. 
 .B  For ATA disks, if
@@ -229,6 +227,30 @@ life period."
 .B smartctl \-v
 command-line option.]
 .TP
+.B \-M <ADD>
+Mail:  Send a warning email to the email address <ADD> if the '\-c', '\-l', '\-L', or '\-f'
+Directives detect a failure or a new error.  This Directive only
+works in conjunction with these other Directives (or with the equivalent '\-a'
+Directive).  To prevent your email in-box from getting filled up
+with warning messages, only a single warning will be sent for each of
+the enabled test types, '\-c', '\-l', '\-L', or '\-f', even if more
+than one failure or error is detected.
+
+The email is sent using the system 
+.B mail
+command.  In order that
+.B smartd
+find the mail command (normally /bin/mail) the
+.B mail
+command must be in the path of the
+shell or environment from which
+.B smartd
+was started.
+
+If you want to send email to more than one user, you can use the form
+.B  user1@add1,user2@add2,...,userN@addN
+with no spaces for <ADD>. 
+.TP
 .B \-p
 Prefail: Report anytime that a Prefail Attribute has changed
 its value since the last check, 30 minutes ago. [Please see the
@@ -345,4 +367,4 @@ SEE ALSO:
 
 .SH
 CVS ID OF THIS PAGE:
-$Id: smartd.conf.5,v 1.3 2002/11/11 12:43:53 ballen4705 Exp $
+$Id: smartd.conf.5,v 1.4 2002/11/12 21:16:25 ballen4705 Exp $
diff --git a/sm5/smartd.cpp b/sm5/smartd.cpp
index c5cb8c541..2b67f290d 100644
--- a/sm5/smartd.cpp
+++ b/sm5/smartd.cpp
@@ -45,7 +45,7 @@
 
 // CVS ID strings
 extern const char *CVSid1, *CVSid2;
-const char *CVSid6="$Id: smartd.cpp,v 1.55 2002/11/11 10:50:08 ballen4705 Exp $" 
+const char *CVSid6="$Id: smartd.cpp,v 1.56 2002/11/12 21:16:25 ballen4705 Exp $" 
 CVSID1 CVSID2 CVSID3 CVSID4 CVSID7;
 
 // global variable used for control of printing, passing arguments, etc.
@@ -87,8 +87,9 @@ void printout(int priority,char *fmt, ...){
   return;
 }
 
-
-void printandmail(mailinfo *mail, int priority, char *fmt, ...){
+// If address is null, this just prints a warning message.  But if
+// address is non-null then send and log a warning email.
+void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...){
   int pid;
   va_list ap;
   
@@ -99,7 +100,7 @@ void printandmail(mailinfo *mail, int priority, char *fmt, ...){
   va_end(ap);
   
   // See if user wants us to send mail
-  if (mail==NULL)
+  if (!address)
     return;
   
   // Have we already sent a message about this?
@@ -127,7 +128,11 @@ void printandmail(mailinfo *mail, int priority, char *fmt, ...){
   }
   else {
     // We are the child process, send email
-    char command[1024], message[256];
+    char command[1024], message[256], hostname[256];
+
+    if (gethostname(hostname, 256)){
+      sprintf(hostname,"hostname: unknown");
+    }
 
     // print warning string into message
     va_start(ap, fmt);
@@ -135,7 +140,8 @@ void printandmail(mailinfo *mail, int priority, char *fmt, ...){
     va_end(ap);
 
     // now construct a command to send this as EMAIL, and issue it.
-    snprintf(command,1024, "echo '%s' | mail -s 'smartd warning: S.M.A.R.T. errors' %s > /dev/null 2> /dev/null", message, mail->address);
+    snprintf(command,1024, "echo '%s' | mail -s '%s: smartd detected SMART errors' %s > /dev/null 2> /dev/null",
+	     message, hostname, address);
     exit(system(command));
   }
 }
@@ -227,21 +233,22 @@ void printhead(){
 // prints help info for configuration file directives
 void Directives() {
   printout(LOG_INFO,"Configuration file Directives (following device name):\n");
-  printout(LOG_INFO,"  -A    Device is an ATA device\n");
-  printout(LOG_INFO,"  -S    Device is a SCSI device\n");
-  printout(LOG_INFO,"  -C N  Check disks once every N seconds, where N>=10.\n");
-  printout(LOG_INFO,"  -P    Permissive, ignore apparent lack of SMART.\n");
-  printout(LOG_INFO,"  -c    Monitor SMART Health Status, report if failed\n");
-  printout(LOG_INFO,"  -l    Monitor SMART Error Log, report new errors\n");
-  printout(LOG_INFO,"  -L    Monitor SMART Self-Test Log, report new errors\n");
-  printout(LOG_INFO,"  -f    Monitor 'Usage' Attributes, report failures\n");
-  printout(LOG_INFO,"  -p    Report changes in 'Prefailure' Attributes\n");
-  printout(LOG_INFO,"  -u    Report changes in 'Usage' Attributes\n");
-  printout(LOG_INFO,"  -t    Equivalent to -p and -u Directives\n");
-  printout(LOG_INFO,"  -a    Equivalent to -c -l -L -f -t 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,"   #    Comment: text after a hash sign is ignored\n");
+  printout(LOG_INFO,"  -A     Device is an ATA device\n");
+  printout(LOG_INFO,"  -S     Device is a SCSI device\n");
+  printout(LOG_INFO,"  -C N   Check disks once every N seconds, where N>=10.\n");
+  printout(LOG_INFO,"  -P     Permissive, ignore apparent lack of SMART.\n");
+  printout(LOG_INFO,"  -c     Monitor SMART Health Status, report if failed\n");
+  printout(LOG_INFO,"  -l     Monitor SMART Error Log, report new errors\n");
+  printout(LOG_INFO,"  -L     Monitor SMART Self-Test Log, report new errors\n");
+  printout(LOG_INFO,"  -f     Monitor 'Usage' Attributes, report failures\n");
+  printout(LOG_INFO,"  -M ADD Send email warning to address ADD\n");
+  printout(LOG_INFO,"  -p     Report changes in 'Prefailure' Attributes\n");
+  printout(LOG_INFO,"  -u     Report changes in 'Usage' Attributes\n");
+  printout(LOG_INFO,"  -t     Equivalent to -p and -u Directives\n");
+  printout(LOG_INFO,"  -a     Equivalent to -c -l -L -f -t 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,"   #     Comment: text after a hash sign is ignored\n");
   printout(LOG_INFO,"   \\    Line continuation character\n");
   printout(LOG_INFO,"Attribute ID is a decimal integer 1 <= ID <= 255\n");
   printout(LOG_INFO,"All but -S Directive are only implemented for ATA devices\n");
@@ -594,7 +601,7 @@ int ataCheckDevice(atadevices_t *drive){
     if (status==-1)
       printout(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name);
     else if (status==1)
-      printout(LOG_CRIT,"Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n",name);
+      printandmail(cfg->address, cfg->maildata , LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name);
   }
   
   // Check everything that depends upon SMART Data (eg, Attribute values)
@@ -607,7 +614,7 @@ int ataCheckDevice(atadevices_t *drive){
       printout(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name);
     else {  
       // look for failed usage attributes, or track usage or prefail attributes
-      for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++) {
+      for (i=0; i<NUMBER_ATA_SMART_ATTRIBUTES; i++){
 	int att;
 	
 	// This block looks for usage attributes that have failed.
@@ -625,7 +632,7 @@ int ataCheckDevice(atadevices_t *drive){
 	    while (*loc && *loc==' ') loc++;
 	    
 	    // warning message
-	    printout(LOG_CRIT,"Device: %s, Failed SMART usage Attribute: %s.\n", name, loc);
+	    printandmail(cfg->address, cfg->maildata+1, LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc);
 	  }
 	}
 	
@@ -673,7 +680,7 @@ int ataCheckDevice(atadevices_t *drive){
     unsigned char old=cfg->selflogcount;
     int new=selftesterrorcount(fd, name);
     if (new>old){
-      printout(LOG_CRIT,"Device: %s, Self-Test Log error count increased from %d to %d\n",
+      printandmail(cfg->address, cfg->maildata+2, LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
 	       name, (int)old, new);
     }
     if (new>=0)
@@ -687,7 +694,7 @@ int ataCheckDevice(atadevices_t *drive){
     int old=cfg->ataerrorcount;
     int new=ataerrorcount(fd, name);
     if (new>old){
-      printout(LOG_CRIT,"Device: %s, ATA error count increased from %d to %d\n",
+      printandmail(cfg->address, cfg->maildata+3, LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
 	       name, old, new);
     }
     // this last line is probably not needed, count always increases
@@ -841,6 +848,22 @@ int parsetoken(char *token,cfgfile *cfg){
     cfg->selftest=1;
     cfg->errorlog=1;
     break;
+  case 'M':
+    // send email to address that follows
+    arg=strtok(NULL,delim);
+    if (!arg) {
+      printout(LOG_CRIT,"Drive %s Directive: %s at line %d of file %s needs email address.\n",
+	       name,token,lineno,CONFIGFILE);
+      Directives();
+      exit(1);
+    }
+    if (!(cfg->address=strdup(arg))){
+      printout(LOG_CRIT,"Drive %s Directive: %s at line %d of file %s: no free memory for address %s.\n",
+	       name,token,lineno,CONFIGFILE,arg);
+      Directives();
+      exit(1);
+    }
+    break;
   case 'i': // ignore
   case 'I': // ignore
   case 'C': // period (time interval) for checking
diff --git a/sm5/smartd.h b/sm5/smartd.h
index 02ee37c08..c5e2677a6 100644
--- a/sm5/smartd.h
+++ b/sm5/smartd.h
@@ -23,7 +23,7 @@
  */
 
 #ifndef CVSID7
-#define CVSID7 "$Id: smartd.h,v 1.19 2002/11/10 21:54:19 ballen4705 Exp $\n"
+#define CVSID7 "$Id: smartd.h,v 1.20 2002/11/12 21:16:25 ballen4705 Exp $\n"
 #endif
 
 // Configuration file
@@ -75,8 +75,6 @@ typedef struct mailinfo {
   int logged;
   // time last email was sent, as defined by man 2 time
   time_t lastsent;
-  // address to send email to
-  char *address;
 } mailinfo;
 
 // Used to store a list of devices and options that were in the
@@ -97,7 +95,9 @@ typedef struct configfile_s {
   // Should we ignore missing capabilities/SMART errors
   char permissive;
   // mailing information for each of the previous error types
-  mailinfo *mailinfop[6];
+  mailinfo maildata[4];
+  // address to send email to
+  char *address;
   // counts of ata and self-test errors.  Perhaps ought to be in the
   // atadevices_t structure.
   unsigned char selflogcount;
@@ -120,9 +120,8 @@ typedef struct atadevices_s {
 }  atadevices_t;
 
 
-// Declare our own printing function...
-void printout(int priority,char *fmt, ...)
-     __attribute__ ((format (printf, 2, 3)));
-
+// Declare our own printing functions...
+void printout(int priority,char *fmt, ...) __attribute__ ((format(printf, 2, 3)));
+void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...) __attribute__ ((format(printf, 4, 5)));   
 
 int ataCheckDevice(atadevices_t *drive);
-- 
GitLab