Skip to content
Snippets Groups Projects
Commit 827b53d7 authored by ballen4705's avatar ballen4705
Browse files

Added additional -m Directive to smartd to enable a test email to be sent

to verify that the email warnings are working correctly.


git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/trunk@293 4ea69e1a-61f1-4043-bf83-b5c94c648137
parent 5434c530
Branches
No related tags found
No related merge requests found
CHANGELOG for smartmontools CHANGELOG for smartmontools
$Id: CHANGELOG,v 1.50 2002/11/17 05:57:32 ballen4705 Exp $ $Id: CHANGELOG,v 1.51 2002/11/21 14:11:18 ballen4705 Exp $
Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
...@@ -24,10 +24,30 @@ California, Santa Cruz. http://ssrc.soe.ucsc.edu/ ...@@ -24,10 +24,30 @@ California, Santa Cruz. http://ssrc.soe.ucsc.edu/
NOTES FOR FUTURE RELEASES: see TODO file. NOTES FOR FUTURE RELEASES: see TODO file.
CURRENT RELEASE (see VERSION file in this directory): CURRENT RELEASE (see VERSION file in this directory):
Allen: smartd: added Directive -m for sending test email and
for modifying email reminder behavior. Updated manual, and sample
configuration file to illustrate & explain this.
Allen: smartd: increased size of a continued smartd.conf line to
1023 characters.
Allen: Simplified Directive parsers and improved warning/error
messages.
smartmontools-5.0.45 smartmontools-5.0.45
Fixed bug in smartd where testunitready logic inverted Fixed bug in smartd where testunitready logic inverted
prevented functioning on scsi devices. prevented functioning on scsi devices.
The bug in question only affects smartd users with scsi devices.
To see if your version of smartd has the testunitready() bug, do
smartd -V
If the version of the module smartd.c in a line like:
Module: smartd.c revision: 1.66 date: 2002/11/17
has a revision greater than or equal to 1.30, and less than or equal to
1.64, then your version of the code has this problem.
This problem affected releases starting with RELEASE_5_0_16 up to and
including RELEASE_5_0_43.
Added testunitnotready to smartctl for symmetry with smartd. Added testunitnotready to smartctl for symmetry with smartd.
......
45 46
\# Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> \# Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
\# \#
\# $Id: smartd.8,v 1.30 2002/11/14 06:06:29 ballen4705 Exp $ \# $Id: smartd.8,v 1.31 2002/11/21 14:11:19 ballen4705 Exp $
\# \#
\# This program is free software; you can redistribute it and/or modify it \# 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 \# under the terms of the GNU General Public License as published by the Free
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
\# Research Center), Jack Baskin School of Engineering, University of \# Research Center), Jack Baskin School of Engineering, University of
\# California, Santa Cruz. http://ssrc.soe.ucsc.edu/ \# California, Santa Cruz. http://ssrc.soe.ucsc.edu/
\# \#
.TH SMARTD 8 "$Date: 2002/11/14 06:06:29 $" "smartmontools-5.0" .TH SMARTD 8 "$Date: 2002/11/21 14:11:19 $" "smartmontools-5.0"
.SH NAME .SH NAME
smartd \- S.M.A.R.T. Daemon smartd \- S.M.A.R.T. Daemon
.SH SYNOPSIS .SH SYNOPSIS
...@@ -208,10 +208,11 @@ Section below! ...@@ -208,10 +208,11 @@ Section below!
.B \ \ /dev/hdc -a -I 194 -I 5 -i 12 .B \ \ /dev/hdc -a -I 194 -I 5 -i 12
.B # .B #
.nf .nf
.B # SCSI disks: .B # SCSI disks. Send a TEST warning email to admin on
.B # startup. (Note: the -1 is the argument of -m.)
.B # .B #
.B \ \ /dev/sda .B \ \ /dev/sda
.B \ \ /dev/sdc -M admin@yoyodyne.com .B \ \ /dev/sdc -M admin@yoyodyne.com -m -1
.B # .B #
.nf .nf
.B # Strange device. It's SCSI: .B # Strange device. It's SCSI:
...@@ -255,7 +256,8 @@ name. ...@@ -255,7 +256,8 @@ name.
.B For ATA disks, if .B For ATA disks, if
.B no Directives appear, the disk will not be monitored. .B no Directives appear, the disk will not be monitored.
The '\-a' Directive will try to monitor everything possible. Conversely, the '\-a' Directive will try to monitor everything
possible.
.B If a SCSI disk is listed, .B If a SCSI disk is listed,
it will be monitored at the only implemented level: roughly equivalent it will be monitored at the only implemented level: roughly equivalent
...@@ -339,13 +341,17 @@ life period." ...@@ -339,13 +341,17 @@ life period."
command-line option.] command-line option.]
.TP .TP
.B \-M <ADD> .B \-M <ADD>
Mail: Send a warning email to the email address <ADD> if the '\-c', '\-l', '\-L', or '\-f' Mail: Send a warning email to the email address <ADD> if
Directives detect a failure or a new error. This Directive only the '\-c', '\-l', '\-L', or '\-f'
works in conjunction with these other Directives (or with the equivalent '\-a' Directives detect a failure or a new error.
Directive). To prevent your email in-box from getting filled up This Directive only works in conjunction with these other Directives
with warning messages, only a single warning will be sent for each of (or with the equivalent '\-a' Directive). To prevent your email
the enabled test types, '\-c', '\-l', '\-L', or '\-f', even if more in-box from getting filled up with warning messages, by default only a
than one failure or error is detected. 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 or if the failure or error persists. [This behavior can be
modified; see the '\-m' Directive below.]
The email is sent using the system The email is sent using the system
.B mail .B mail
...@@ -356,11 +362,50 @@ find the mail command (normally /bin/mail) the ...@@ -356,11 +362,50 @@ find the mail command (normally /bin/mail) the
command must be in the path of the command must be in the path of the
shell or environment from which shell or environment from which
.B smartd .B smartd
was started. was started. To test that the mail is being sent correctly, or to
alter the pattern of when mail is sent, see the `\-m' Directive below.
If you want to send email to more than one user, you can use the form To send email to more than one user, please use the following form for the address
<ADD>:
.B user1@add1,user2@add2,...,userN@addN .B user1@add1,user2@add2,...,userN@addN
with no spaces for <ADD>. (with no spaces).
.TP
.B \-m <N>
Modify Mail: Modifies the behavior of the '\-M' email Directive above,
and has no effect without this other Directive. This option controls
when, and how often, the '\-M' Directive sends email warning messages.
This Directive takes a decimal integer argument <N> in the range from
-3 to 3 inclusive.
.nf
.B If <N>=0 or 1:
.fi
equivalent to not having this '\-m' Directive present at all. Only
one warning email is sent for each type of disk problem detected.
.nf
.B If <N>=2:
.fi
send additional warning reminder emails, once per day, for each type
of disk problem detected.
.nf
.B If <N>=3:
.fi
send additional warning reminder emails, after a one-day interval,
then a two-day interval, then a four-day interval, and so on for each
type of disk problem detected. Each interval is twice as long as the
previous interval.
.nf
.B If <N>=-1, -2, or -3:
.fi
Negative values of <N> have the same meaning as the corresponding
positive value, but also send a single additional "test email"
immediately upon
.B smartd
startup. This allows one to verify that any email is correctly
delivered. For example, setting <N>=-2 will send a test email on
.B smartd
startup, and additional warning reminder emails at one-day intervals
after any disk problems are detected.
.TP .TP
.B \-p .B \-p
Prefail: Report anytime that a Prefail Attribute has changed Prefail: Report anytime that a Prefail Attribute has changed
...@@ -548,4 +593,4 @@ Please let us know if there is an on\-line source for this document. ...@@ -548,4 +593,4 @@ Please let us know if there is an on\-line source for this document.
.SH .SH
CVS ID OF THIS PAGE: CVS ID OF THIS PAGE:
$Id: smartd.8,v 1.30 2002/11/14 06:06:29 ballen4705 Exp $ $Id: smartd.8,v 1.31 2002/11/21 14:11:19 ballen4705 Exp $
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <limits.h>
#include "atacmds.h" #include "atacmds.h"
#include "scsicmds.h" #include "scsicmds.h"
#include "smartd.h" #include "smartd.h"
...@@ -45,7 +46,7 @@ ...@@ -45,7 +46,7 @@
// CVS ID strings // CVS ID strings
extern const char *CVSid1, *CVSid2; extern const char *CVSid1, *CVSid2;
const char *CVSid6="$Id: smartd.c,v 1.66 2002/11/17 05:30:11 ballen4705 Exp $" const char *CVSid6="$Id: smartd.c,v 1.67 2002/11/21 14:11:19 ballen4705 Exp $"
CVSID1 CVSID2 CVSID3 CVSID4 CVSID7; CVSID1 CVSID2 CVSID3 CVSID4 CVSID7;
// global variable used for control of printing, passing arguments, etc. // global variable used for control of printing, passing arguments, etc.
...@@ -89,20 +90,49 @@ void printout(int priority,char *fmt, ...){ ...@@ -89,20 +90,49 @@ void printout(int priority,char *fmt, ...){
// If address is null, this just prints a warning message. But if // If address is null, this just prints a warning message. But if
// address is non-null then send and log a warning email. // address is non-null then send and log a warning email.
void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...){ void printandmail(cfgfile *cfg, int which, int priority, char *fmt, ...){
char command[2048], message[256], hostname[256]; char command[2048], message[256], hostname[256], additional[256], original[256], further[256];
int status; int status;
time_t epoch;
va_list ap; va_list ap;
const int day=24*3600;
int days=0;
char *address=cfg->address;
mailinfo *mail=cfg->maildata+which;
// See if user wants us to send mail, or if we already have // See if user wants us to send mail
if (!address || mail->logged) if (!address)
return; return;
// record the time of the mail message, and increment counter. This // check for sanity
// is for later use if we decide to implement multiple email warning if (cfg->emailopt<0 || cfg->emailopt>3){
// messages after some delay time. printout(LOG_INFO,"internal error in printandmail(): cfg->emailopts=%d\n",cfg->emailopt);
mail->logged++; return;
mail->lastsent=time(NULL); }
// Return if a single warning mail has been sent.
if ((cfg->emailopt==0 || cfg->emailopt==1) && mail->logged)
return;
// To decide if to send mail, we need to know what time it is.
epoch=time(NULL);
// Return if less than one day has gone by
if (cfg->emailopt==2 && mail->logged && epoch<(mail->lastsent+day))
return;
// Return if less than 2^(logged-1) days have gone by
if (cfg->emailopt==3 && mail->logged){
days=0x01<<(mail->logged-1);
days*=day;
if (epoch<(mail->lastsent+days))
return;
}
// record the time of this mail message, and the first mail message
if (!mail->logged)
mail->firstsent=epoch;
mail->lastsent=epoch;
// get system host name (not null terminated if length=MAX) // get system host name (not null terminated if length=MAX)
if (gethostname(hostname, 256)) if (gethostname(hostname, 256))
...@@ -115,27 +145,53 @@ void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...){ ...@@ -115,27 +145,53 @@ void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...){
vsnprintf(message, 256, fmt, ap); vsnprintf(message, 256, fmt, ap);
va_end(ap); va_end(ap);
// now construct a command to send this as EMAIL, and issue it. // appropriate message about further information
snprintf(command, 2048, "mail -s '%s: SMART errors detected' %s > /dev/null 2> /dev/null << \"ENDMAIL\"\n" additional[0]=original[0]=further[0]='\0';
"This email was generated by the smartd daemon running on machine:\n" if (which) {
"%s\n" sprintf(further,"You can also use the smartctl utility for further investigation.\n");
switch (cfg->emailopt){
case 0:
case 1:
sprintf(additional,"No additional email messages about this problem will be sent.\n");
break;
case 2:
sprintf(additional,"Another email message will be sent in 24 hours if the problem persists\n");
break;
case 3:
sprintf(additional,"Another email message will be sent in %d days if the problem persists\n",
(0x01)<<mail->logged);
break;
}
if (cfg->emailopt>1 && mail->logged)
sprintf(original,"The original email about this issue was sent at %s\n",ctime(&(mail->firstsent)));
}
// now construct a command to send this as EMAIL
snprintf(command, 2048, "mail -s 'SMART errors detected on host: %s' %s > /dev/null 2> /dev/null << \"ENDMAIL\"\n"
"This email was generated by the smartd daemon running on host:\n"
"%s\n\n"
"The following warning/error was logged by the smartd daemon:\n" "The following warning/error was logged by the smartd daemon:\n"
"%s" "%s\n"
"Further details can be found in the machine's syslog (/var/log/messages).\n" "For further details see the syslog (/var/log/messages) on host:\n"
"You can also use the smartctl utility for further investigation.\n" "%s\n\n"
"No additional email messages about this problem will be sent.\n" "%s%s%s"
"ENDMAIL\n", "ENDMAIL\n",
hostname, address, hostname, message); hostname, address, hostname, message, hostname, further, original, additional);
#if (0)
snprintf(command,1024, "echo '%s' | mail -s '%s: smartd detected SMART errors' %s > /dev/null 2> /dev/null",
message, hostname, address);
#endif
// issue the command to send email
status=system(command); status=system(command);
if (WEXITSTATUS(status)) if (WEXITSTATUS(status))
printout(LOG_CRIT,"Email warning message to %s failed (32-bit exit status: %d)\n",address,status); printout(LOG_CRIT,"Email warning message to %s failed (32-bit exit status: %d)\n",address,status);
else else {
if (which)
printout(LOG_INFO,"Email warning message sent to %s\n",address); printout(LOG_INFO,"Email warning message sent to %s\n",address);
else
printout(LOG_INFO,"Email test message sent to %s\n",address);
}
// increment mail sent counter
mail->logged++;
return; return;
} }
...@@ -236,6 +292,7 @@ void Directives() { ...@@ -236,6 +292,7 @@ void Directives() {
printout(LOG_INFO," -L Monitor SMART Self-Test 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," -f Monitor 'Usage' Attributes, report failures\n");
printout(LOG_INFO," -M ADD Send email warning to address ADD\n"); printout(LOG_INFO," -M ADD Send email warning to address ADD\n");
printout(LOG_INFO," -m N Modify email warning behavior. -3 <= N <= 3\n");
printout(LOG_INFO," -p Report changes in 'Prefailure' Attributes\n"); printout(LOG_INFO," -p Report changes in 'Prefailure' Attributes\n");
printout(LOG_INFO," -u Report changes in 'Usage' 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," -t Equivalent to -p and -u Directives\n");
...@@ -593,6 +650,12 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -593,6 +650,12 @@ int ataCheckDevice(atadevices_t *drive){
char *name=drive->devicename; char *name=drive->devicename;
cfgfile *cfg=drive->cfg; cfgfile *cfg=drive->cfg;
// If user has asked, test the email warning system
if (cfg->emailopt<0){
cfg->emailopt*=-1;
printandmail(cfg, 0, LOG_CRIT, "TEST EMAIL from smartd for device: %s\n", drive->devicename);
}
// if we can't open device, fail gracefully rather than hard -- // if we can't open device, fail gracefully rather than hard --
// perhaps the next time around we'll be able to open it // perhaps the next time around we'll be able to open it
if ((fd=opendevice(name))<0) if ((fd=opendevice(name))<0)
...@@ -605,7 +668,7 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -605,7 +668,7 @@ int ataCheckDevice(atadevices_t *drive){
printout(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name); printout(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name);
else if (status==1){ else if (status==1){
printout(LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name); 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); printandmail(cfg, 1, LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name);
} }
} }
...@@ -638,7 +701,7 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -638,7 +701,7 @@ int ataCheckDevice(atadevices_t *drive){
// warning message // warning message
printout(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc); 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); printandmail(cfg, 2, LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc);
} }
} }
...@@ -688,7 +751,7 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -688,7 +751,7 @@ int ataCheckDevice(atadevices_t *drive){
if (new>old){ if (new>old){
printout(LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n", printout(LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
name, (int)old, new); name, (int)old, new);
printandmail(cfg->address, cfg->maildata+2, LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n", printandmail(cfg, 3, LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
name, (int)old, new); name, (int)old, new);
} }
if (new>=0) if (new>=0)
...@@ -704,7 +767,7 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -704,7 +767,7 @@ int ataCheckDevice(atadevices_t *drive){
if (new>old){ if (new>old){
printout(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n", printout(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
name, old, new); name, old, new);
printandmail(cfg->address, cfg->maildata+3, LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n", printandmail(cfg, 4, LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
name, old, new); name, old, new);
} }
// this last line is probably not needed, count always increases // this last line is probably not needed, count always increases
...@@ -724,6 +787,12 @@ int scsiCheckDevice(scsidevices_t *drive){ ...@@ -724,6 +787,12 @@ int scsiCheckDevice(scsidevices_t *drive){
int fd; int fd;
cfgfile *cfg=drive->cfg; cfgfile *cfg=drive->cfg;
// If the user has asked for it, test the email warning system
if (cfg->emailopt<0){
cfg->emailopt*=-1;
printandmail(cfg, 0, LOG_CRIT, "TEST EMAIL from smartd for device: %s\n", drive->devicename);
}
// if we can't open device, fail gracefully rather than hard -- // if we can't open device, fail gracefully rather than hard --
// perhaps the next time around we'll be able to open it // perhaps the next time around we'll be able to open it
if ((fd=opendevice(drive->devicename))<0) if ((fd=opendevice(drive->devicename))<0)
...@@ -737,7 +806,7 @@ int scsiCheckDevice(scsidevices_t *drive){ ...@@ -737,7 +806,7 @@ int scsiCheckDevice(scsidevices_t *drive){
if (returnvalue) { if (returnvalue) {
printout(LOG_CRIT, "Device: %s, SMART Failure: (%d) %s\n", drive->devicename, printout(LOG_CRIT, "Device: %s, SMART Failure: (%d) %s\n", drive->devicename,
(int)returnvalue, scsiSmartGetSenseCode(returnvalue)); (int)returnvalue, scsiSmartGetSenseCode(returnvalue));
printandmail(cfg->address, cfg->maildata, LOG_CRIT, "Device: %s, SMART Failure: (%d) %s\n", drive->devicename, printandmail(cfg, 1, LOG_CRIT, "Device: %s, SMART Failure: (%d) %s\n", drive->devicename,
(int)returnvalue, scsiSmartGetSenseCode(returnvalue)); (int)returnvalue, scsiSmartGetSenseCode(returnvalue));
} }
else if (debugmode) else if (debugmode)
...@@ -786,6 +855,35 @@ char copyleftstring[]= ...@@ -786,6 +855,35 @@ char copyleftstring[]=
cfgfile config[MAXENTRIES]; cfgfile config[MAXENTRIES];
// exits with an error message, or returns integer value of token
int inttoken(char *arg, char *name, char *token, int lineno, char *configfile, int min, int max){
char *endptr;
int val;
// make sure argument is there
if (!arg) {
printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes integer argument from %d to %d.\n",
configfile, lineno, name, token, min, max);
Directives();
exit(1);
}
// get argument value (base 10), check that it's integer, and in-range
val=strtol(arg,&endptr,10);
if (*endptr!='\0' || val<min || val>max ) {
printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n",
configfile, lineno, name, token, arg, min, max);
Directives();
exit(1);
}
// all is well; return value
return val;
}
// This function returns non-zero if it has correctly parsed a token,
// else zero if it has failed to parse a token. Or it exits with a
// directive message if there is a token-parsing problem.
int parsetoken(char *token,cfgfile *cfg){ int parsetoken(char *token,cfgfile *cfg){
char sym=token[1]; char sym=token[1];
char *name=cfg->name; char *name=cfg->name;
...@@ -798,8 +896,8 @@ int parsetoken(char *token,cfgfile *cfg){ ...@@ -798,8 +896,8 @@ int parsetoken(char *token,cfgfile *cfg){
// is the token not recognized? // is the token not recognized?
if (*token!='-' || strlen(token)!=2) { if (*token!='-' || strlen(token)!=2) {
printout(LOG_CRIT,"Drive: %s, unknown Directive: %s at line %d of file %s\n", printout(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
name,token,lineno,CONFIGFILE); CONFIGFILE, lineno, name, token);
Directives(); Directives();
exit(1); exit(1);
} }
...@@ -807,7 +905,6 @@ int parsetoken(char *token,cfgfile *cfg){ ...@@ -807,7 +905,6 @@ int parsetoken(char *token,cfgfile *cfg){
// let's parse the token and swallow its argument // let's parse the token and swallow its argument
switch (sym) { switch (sym) {
char *arg; char *arg;
char *endptr;
int val; int val;
case 'P': case 'P':
...@@ -862,67 +959,43 @@ int parsetoken(char *token,cfgfile *cfg){ ...@@ -862,67 +959,43 @@ int parsetoken(char *token,cfgfile *cfg){
cfg->selftest=1; cfg->selftest=1;
cfg->errorlog=1; cfg->errorlog=1;
break; break;
case 'm':
// email warning option
cfg->emailopt=inttoken(arg=strtok(NULL,delim), name, token, lineno, CONFIGFILE, -3, 3);
break;
case 'i':
// ignore failure of usage attribute
val=inttoken(arg=strtok(NULL,delim), name, token, lineno, CONFIGFILE, 1, 255);
isattoff(val,cfg->failatt,1);
break;
case 'I':
// ignore attribute for tracking purposes
val=inttoken(arg=strtok(NULL,delim), name, token, lineno, CONFIGFILE, 1, 255);
isattoff(val,cfg->trackatt,1);
break;
case 'C':
// period (time interval) for checking
checktime=inttoken(arg=strtok(NULL,delim), name, token, lineno, CONFIGFILE, 10, INT_MAX);
break;
case 'M': case 'M':
// send email to address that follows // send email to address that follows
arg=strtok(NULL,delim); arg=strtok(NULL,delim);
if (!arg) { if (!arg) {
printout(LOG_CRIT,"Drive %s Directive: %s at line %d of file %s needs email address.\n", printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s needs email address(es)\n",
name,token,lineno,CONFIGFILE); CONFIGFILE, lineno, name, token);
Directives(); Directives();
exit(1); exit(1);
} }
if (!(cfg->address=strdup(arg))){ 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", printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s: no free memory for email address(es) %s\n",
name,token,lineno,CONFIGFILE,arg); CONFIGFILE, lineno, name, token, arg);
Directives(); Directives();
exit(1); exit(1);
} }
break; break;
case 'i': // ignore
case 'I': // ignore
case 'C': // period (time interval) for checking
// ignore a particular vendor attribute for tracking (i) or
// failure (I). Or give a check interval for sleeping.
arg=strtok(NULL,delim);
// make sure argument is there
if (!arg) {
printout(LOG_CRIT,"Drive %s Directive: %s at line %d of file %s needs integer argument.\n",
name,token,lineno,CONFIGFILE);
Directives();
exit(1);
}
// get argument value, check that it's properly-formed, an
// integer, and in-range
val=strtol(arg,&endptr,10);
switch (sym) {
case 'C':
if (*endptr!='\0' || val<10) {
printout(LOG_CRIT,"Drive %s Directive: %s, line %d, file %s, has argument: %s, mimimum is ten secoonds\n",
name,token,lineno,CONFIGFILE,arg);
Directives();
exit(1);
}
checktime=val;
return 1;
case 'i':
case 'I':
if (*endptr!='\0' || val<=0 || val>255 ) {
printout(LOG_CRIT,"Drive %s Directive: %s, line %d, file %s, has argument: %s, needs 0 < n < 256\n",
name,token,lineno,CONFIGFILE,arg);
Directives();
exit(1);
}
// put into correct list (bitmaps, access only with isattoff()
// function. Turns OFF corresponding attribute.
if (sym=='I')
isattoff(val,cfg->trackatt,1);
else
isattoff(val,cfg->failatt,1);
return 1;
}
default: default:
printout(LOG_CRIT,"Drive: %s, unknown Directive: %s at line %d of file %s\n", printout(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
name,token,lineno,CONFIGFILE); CONFIGFILE, lineno, name, token);
Directives(); Directives();
exit(1); exit(1);
} }
...@@ -1011,6 +1084,14 @@ int parseconfigline(int entry, int lineno,char *line){ ...@@ -1011,6 +1084,14 @@ int parseconfigline(int entry, int lineno,char *line){
exit(1); exit(1);
} }
// additional sanity check. Has user set -m without -M?
if (cfg->emailopt && !cfg->address){
printout(LOG_CRIT,"Drive: %s, Directive -m useless without address Directive -M on line %d of file %s\n",
cfg->name, cfg->lineno, CONFIGFILE);
Directives();
exit(1);
}
entry++; entry++;
free(copy); free(copy);
return 1; return 1;
......
...@@ -23,13 +23,14 @@ DEVICESCAN ...@@ -23,13 +23,14 @@ DEVICESCAN
/dev/hdb -c l L -t -I 194 /dev/hdb -c l L -t -I 194
# A very silent check. Only report SMART health status if it fails # A very silent check. Only report SMART health status if it fails
/dev/hdc -c # But send an email in this case
/dev/hdc -c -M admin@yoyodyne.com
# First two SCSI disks. Note that only the S directive applies # First two SCSI disks. This will monitor everything that smartd can
monitor.
/dev/sda -S /dev/sda -S
/dev/sdb -S /dev/sdb -S
# HERE IS A LIST OF DIRECTIVES FOR THIS CONFIGURATION FILE # HERE IS A LIST OF DIRECTIVES FOR THIS CONFIGURATION FILE
# -A Device is an ATA device # -A Device is an ATA device
# -S Device is a SCSI device # -S Device is a SCSI device
...@@ -40,6 +41,7 @@ DEVICESCAN ...@@ -40,6 +41,7 @@ DEVICESCAN
# -L Monitor SMART Self-Test Log for new errors # -L Monitor SMART Self-Test Log for new errors
# -f Monitor for failure of any 'Usage' Attributes # -f Monitor for failure of any 'Usage' Attributes
# -M ADD Send warning email to ADD for -c, -l, -L, and -f # -M ADD Send warning email to ADD for -c, -l, -L, and -f
# -m N Modify email warning behavior. -3 <= N <= 3
# -p Report changes in 'Prefailure' Attributes # -p Report changes in 'Prefailure' Attributes
# -u Report changes in 'Usage' Attributes # -u Report changes in 'Usage' Attributes
# -t Equivalent to -p and -u Directives # -t Equivalent to -p and -u Directives
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include <limits.h>
#include "atacmds.h" #include "atacmds.h"
#include "scsicmds.h" #include "scsicmds.h"
#include "smartd.h" #include "smartd.h"
...@@ -45,7 +46,7 @@ ...@@ -45,7 +46,7 @@
// CVS ID strings // CVS ID strings
extern const char *CVSid1, *CVSid2; extern const char *CVSid1, *CVSid2;
const char *CVSid6="$Id: smartd.cpp,v 1.66 2002/11/17 05:30:11 ballen4705 Exp $" const char *CVSid6="$Id: smartd.cpp,v 1.67 2002/11/21 14:11:19 ballen4705 Exp $"
CVSID1 CVSID2 CVSID3 CVSID4 CVSID7; CVSID1 CVSID2 CVSID3 CVSID4 CVSID7;
// global variable used for control of printing, passing arguments, etc. // global variable used for control of printing, passing arguments, etc.
...@@ -89,20 +90,49 @@ void printout(int priority,char *fmt, ...){ ...@@ -89,20 +90,49 @@ void printout(int priority,char *fmt, ...){
// If address is null, this just prints a warning message. But if // If address is null, this just prints a warning message. But if
// address is non-null then send and log a warning email. // address is non-null then send and log a warning email.
void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...){ void printandmail(cfgfile *cfg, int which, int priority, char *fmt, ...){
char command[2048], message[256], hostname[256]; char command[2048], message[256], hostname[256], additional[256], original[256], further[256];
int status; int status;
time_t epoch;
va_list ap; va_list ap;
const int day=24*3600;
int days=0;
char *address=cfg->address;
mailinfo *mail=cfg->maildata+which;
// See if user wants us to send mail, or if we already have // See if user wants us to send mail
if (!address || mail->logged) if (!address)
return; return;
// record the time of the mail message, and increment counter. This // check for sanity
// is for later use if we decide to implement multiple email warning if (cfg->emailopt<0 || cfg->emailopt>3){
// messages after some delay time. printout(LOG_INFO,"internal error in printandmail(): cfg->emailopts=%d\n",cfg->emailopt);
mail->logged++; return;
mail->lastsent=time(NULL); }
// Return if a single warning mail has been sent.
if ((cfg->emailopt==0 || cfg->emailopt==1) && mail->logged)
return;
// To decide if to send mail, we need to know what time it is.
epoch=time(NULL);
// Return if less than one day has gone by
if (cfg->emailopt==2 && mail->logged && epoch<(mail->lastsent+day))
return;
// Return if less than 2^(logged-1) days have gone by
if (cfg->emailopt==3 && mail->logged){
days=0x01<<(mail->logged-1);
days*=day;
if (epoch<(mail->lastsent+days))
return;
}
// record the time of this mail message, and the first mail message
if (!mail->logged)
mail->firstsent=epoch;
mail->lastsent=epoch;
// get system host name (not null terminated if length=MAX) // get system host name (not null terminated if length=MAX)
if (gethostname(hostname, 256)) if (gethostname(hostname, 256))
...@@ -115,27 +145,53 @@ void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...){ ...@@ -115,27 +145,53 @@ void printandmail(char *address, mailinfo *mail, int priority, char *fmt, ...){
vsnprintf(message, 256, fmt, ap); vsnprintf(message, 256, fmt, ap);
va_end(ap); va_end(ap);
// now construct a command to send this as EMAIL, and issue it. // appropriate message about further information
snprintf(command, 2048, "mail -s '%s: SMART errors detected' %s > /dev/null 2> /dev/null << \"ENDMAIL\"\n" additional[0]=original[0]=further[0]='\0';
"This email was generated by the smartd daemon running on machine:\n" if (which) {
"%s\n" sprintf(further,"You can also use the smartctl utility for further investigation.\n");
switch (cfg->emailopt){
case 0:
case 1:
sprintf(additional,"No additional email messages about this problem will be sent.\n");
break;
case 2:
sprintf(additional,"Another email message will be sent in 24 hours if the problem persists\n");
break;
case 3:
sprintf(additional,"Another email message will be sent in %d days if the problem persists\n",
(0x01)<<mail->logged);
break;
}
if (cfg->emailopt>1 && mail->logged)
sprintf(original,"The original email about this issue was sent at %s\n",ctime(&(mail->firstsent)));
}
// now construct a command to send this as EMAIL
snprintf(command, 2048, "mail -s 'SMART errors detected on host: %s' %s > /dev/null 2> /dev/null << \"ENDMAIL\"\n"
"This email was generated by the smartd daemon running on host:\n"
"%s\n\n"
"The following warning/error was logged by the smartd daemon:\n" "The following warning/error was logged by the smartd daemon:\n"
"%s" "%s\n"
"Further details can be found in the machine's syslog (/var/log/messages).\n" "For further details see the syslog (/var/log/messages) on host:\n"
"You can also use the smartctl utility for further investigation.\n" "%s\n\n"
"No additional email messages about this problem will be sent.\n" "%s%s%s"
"ENDMAIL\n", "ENDMAIL\n",
hostname, address, hostname, message); hostname, address, hostname, message, hostname, further, original, additional);
#if (0)
snprintf(command,1024, "echo '%s' | mail -s '%s: smartd detected SMART errors' %s > /dev/null 2> /dev/null",
message, hostname, address);
#endif
// issue the command to send email
status=system(command); status=system(command);
if (WEXITSTATUS(status)) if (WEXITSTATUS(status))
printout(LOG_CRIT,"Email warning message to %s failed (32-bit exit status: %d)\n",address,status); printout(LOG_CRIT,"Email warning message to %s failed (32-bit exit status: %d)\n",address,status);
else else {
if (which)
printout(LOG_INFO,"Email warning message sent to %s\n",address); printout(LOG_INFO,"Email warning message sent to %s\n",address);
else
printout(LOG_INFO,"Email test message sent to %s\n",address);
}
// increment mail sent counter
mail->logged++;
return; return;
} }
...@@ -236,6 +292,7 @@ void Directives() { ...@@ -236,6 +292,7 @@ void Directives() {
printout(LOG_INFO," -L Monitor SMART Self-Test 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," -f Monitor 'Usage' Attributes, report failures\n");
printout(LOG_INFO," -M ADD Send email warning to address ADD\n"); printout(LOG_INFO," -M ADD Send email warning to address ADD\n");
printout(LOG_INFO," -m N Modify email warning behavior. -3 <= N <= 3\n");
printout(LOG_INFO," -p Report changes in 'Prefailure' Attributes\n"); printout(LOG_INFO," -p Report changes in 'Prefailure' Attributes\n");
printout(LOG_INFO," -u Report changes in 'Usage' 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," -t Equivalent to -p and -u Directives\n");
...@@ -593,6 +650,12 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -593,6 +650,12 @@ int ataCheckDevice(atadevices_t *drive){
char *name=drive->devicename; char *name=drive->devicename;
cfgfile *cfg=drive->cfg; cfgfile *cfg=drive->cfg;
// If user has asked, test the email warning system
if (cfg->emailopt<0){
cfg->emailopt*=-1;
printandmail(cfg, 0, LOG_CRIT, "TEST EMAIL from smartd for device: %s\n", drive->devicename);
}
// if we can't open device, fail gracefully rather than hard -- // if we can't open device, fail gracefully rather than hard --
// perhaps the next time around we'll be able to open it // perhaps the next time around we'll be able to open it
if ((fd=opendevice(name))<0) if ((fd=opendevice(name))<0)
...@@ -605,7 +668,7 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -605,7 +668,7 @@ int ataCheckDevice(atadevices_t *drive){
printout(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name); printout(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name);
else if (status==1){ else if (status==1){
printout(LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name); 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); printandmail(cfg, 1, LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name);
} }
} }
...@@ -638,7 +701,7 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -638,7 +701,7 @@ int ataCheckDevice(atadevices_t *drive){
// warning message // warning message
printout(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc); 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); printandmail(cfg, 2, LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %s.\n", name, loc);
} }
} }
...@@ -688,7 +751,7 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -688,7 +751,7 @@ int ataCheckDevice(atadevices_t *drive){
if (new>old){ if (new>old){
printout(LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n", printout(LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
name, (int)old, new); name, (int)old, new);
printandmail(cfg->address, cfg->maildata+2, LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n", printandmail(cfg, 3, LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
name, (int)old, new); name, (int)old, new);
} }
if (new>=0) if (new>=0)
...@@ -704,7 +767,7 @@ int ataCheckDevice(atadevices_t *drive){ ...@@ -704,7 +767,7 @@ int ataCheckDevice(atadevices_t *drive){
if (new>old){ if (new>old){
printout(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n", printout(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
name, old, new); name, old, new);
printandmail(cfg->address, cfg->maildata+3, LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n", printandmail(cfg, 4, LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
name, old, new); name, old, new);
} }
// this last line is probably not needed, count always increases // this last line is probably not needed, count always increases
...@@ -724,6 +787,12 @@ int scsiCheckDevice(scsidevices_t *drive){ ...@@ -724,6 +787,12 @@ int scsiCheckDevice(scsidevices_t *drive){
int fd; int fd;
cfgfile *cfg=drive->cfg; cfgfile *cfg=drive->cfg;
// If the user has asked for it, test the email warning system
if (cfg->emailopt<0){
cfg->emailopt*=-1;
printandmail(cfg, 0, LOG_CRIT, "TEST EMAIL from smartd for device: %s\n", drive->devicename);
}
// if we can't open device, fail gracefully rather than hard -- // if we can't open device, fail gracefully rather than hard --
// perhaps the next time around we'll be able to open it // perhaps the next time around we'll be able to open it
if ((fd=opendevice(drive->devicename))<0) if ((fd=opendevice(drive->devicename))<0)
...@@ -737,7 +806,7 @@ int scsiCheckDevice(scsidevices_t *drive){ ...@@ -737,7 +806,7 @@ int scsiCheckDevice(scsidevices_t *drive){
if (returnvalue) { if (returnvalue) {
printout(LOG_CRIT, "Device: %s, SMART Failure: (%d) %s\n", drive->devicename, printout(LOG_CRIT, "Device: %s, SMART Failure: (%d) %s\n", drive->devicename,
(int)returnvalue, scsiSmartGetSenseCode(returnvalue)); (int)returnvalue, scsiSmartGetSenseCode(returnvalue));
printandmail(cfg->address, cfg->maildata, LOG_CRIT, "Device: %s, SMART Failure: (%d) %s\n", drive->devicename, printandmail(cfg, 1, LOG_CRIT, "Device: %s, SMART Failure: (%d) %s\n", drive->devicename,
(int)returnvalue, scsiSmartGetSenseCode(returnvalue)); (int)returnvalue, scsiSmartGetSenseCode(returnvalue));
} }
else if (debugmode) else if (debugmode)
...@@ -786,6 +855,35 @@ char copyleftstring[]= ...@@ -786,6 +855,35 @@ char copyleftstring[]=
cfgfile config[MAXENTRIES]; cfgfile config[MAXENTRIES];
// exits with an error message, or returns integer value of token
int inttoken(char *arg, char *name, char *token, int lineno, char *configfile, int min, int max){
char *endptr;
int val;
// make sure argument is there
if (!arg) {
printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes integer argument from %d to %d.\n",
configfile, lineno, name, token, min, max);
Directives();
exit(1);
}
// get argument value (base 10), check that it's integer, and in-range
val=strtol(arg,&endptr,10);
if (*endptr!='\0' || val<min || val>max ) {
printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n",
configfile, lineno, name, token, arg, min, max);
Directives();
exit(1);
}
// all is well; return value
return val;
}
// This function returns non-zero if it has correctly parsed a token,
// else zero if it has failed to parse a token. Or it exits with a
// directive message if there is a token-parsing problem.
int parsetoken(char *token,cfgfile *cfg){ int parsetoken(char *token,cfgfile *cfg){
char sym=token[1]; char sym=token[1];
char *name=cfg->name; char *name=cfg->name;
...@@ -798,8 +896,8 @@ int parsetoken(char *token,cfgfile *cfg){ ...@@ -798,8 +896,8 @@ int parsetoken(char *token,cfgfile *cfg){
// is the token not recognized? // is the token not recognized?
if (*token!='-' || strlen(token)!=2) { if (*token!='-' || strlen(token)!=2) {
printout(LOG_CRIT,"Drive: %s, unknown Directive: %s at line %d of file %s\n", printout(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
name,token,lineno,CONFIGFILE); CONFIGFILE, lineno, name, token);
Directives(); Directives();
exit(1); exit(1);
} }
...@@ -807,7 +905,6 @@ int parsetoken(char *token,cfgfile *cfg){ ...@@ -807,7 +905,6 @@ int parsetoken(char *token,cfgfile *cfg){
// let's parse the token and swallow its argument // let's parse the token and swallow its argument
switch (sym) { switch (sym) {
char *arg; char *arg;
char *endptr;
int val; int val;
case 'P': case 'P':
...@@ -862,67 +959,43 @@ int parsetoken(char *token,cfgfile *cfg){ ...@@ -862,67 +959,43 @@ int parsetoken(char *token,cfgfile *cfg){
cfg->selftest=1; cfg->selftest=1;
cfg->errorlog=1; cfg->errorlog=1;
break; break;
case 'm':
// email warning option
cfg->emailopt=inttoken(arg=strtok(NULL,delim), name, token, lineno, CONFIGFILE, -3, 3);
break;
case 'i':
// ignore failure of usage attribute
val=inttoken(arg=strtok(NULL,delim), name, token, lineno, CONFIGFILE, 1, 255);
isattoff(val,cfg->failatt,1);
break;
case 'I':
// ignore attribute for tracking purposes
val=inttoken(arg=strtok(NULL,delim), name, token, lineno, CONFIGFILE, 1, 255);
isattoff(val,cfg->trackatt,1);
break;
case 'C':
// period (time interval) for checking
checktime=inttoken(arg=strtok(NULL,delim), name, token, lineno, CONFIGFILE, 10, INT_MAX);
break;
case 'M': case 'M':
// send email to address that follows // send email to address that follows
arg=strtok(NULL,delim); arg=strtok(NULL,delim);
if (!arg) { if (!arg) {
printout(LOG_CRIT,"Drive %s Directive: %s at line %d of file %s needs email address.\n", printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s needs email address(es)\n",
name,token,lineno,CONFIGFILE); CONFIGFILE, lineno, name, token);
Directives(); Directives();
exit(1); exit(1);
} }
if (!(cfg->address=strdup(arg))){ 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", printout(LOG_CRIT,"File %s line %d (drive %s): Directive: %s: no free memory for email address(es) %s\n",
name,token,lineno,CONFIGFILE,arg); CONFIGFILE, lineno, name, token, arg);
Directives(); Directives();
exit(1); exit(1);
} }
break; break;
case 'i': // ignore
case 'I': // ignore
case 'C': // period (time interval) for checking
// ignore a particular vendor attribute for tracking (i) or
// failure (I). Or give a check interval for sleeping.
arg=strtok(NULL,delim);
// make sure argument is there
if (!arg) {
printout(LOG_CRIT,"Drive %s Directive: %s at line %d of file %s needs integer argument.\n",
name,token,lineno,CONFIGFILE);
Directives();
exit(1);
}
// get argument value, check that it's properly-formed, an
// integer, and in-range
val=strtol(arg,&endptr,10);
switch (sym) {
case 'C':
if (*endptr!='\0' || val<10) {
printout(LOG_CRIT,"Drive %s Directive: %s, line %d, file %s, has argument: %s, mimimum is ten secoonds\n",
name,token,lineno,CONFIGFILE,arg);
Directives();
exit(1);
}
checktime=val;
return 1;
case 'i':
case 'I':
if (*endptr!='\0' || val<=0 || val>255 ) {
printout(LOG_CRIT,"Drive %s Directive: %s, line %d, file %s, has argument: %s, needs 0 < n < 256\n",
name,token,lineno,CONFIGFILE,arg);
Directives();
exit(1);
}
// put into correct list (bitmaps, access only with isattoff()
// function. Turns OFF corresponding attribute.
if (sym=='I')
isattoff(val,cfg->trackatt,1);
else
isattoff(val,cfg->failatt,1);
return 1;
}
default: default:
printout(LOG_CRIT,"Drive: %s, unknown Directive: %s at line %d of file %s\n", printout(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
name,token,lineno,CONFIGFILE); CONFIGFILE, lineno, name, token);
Directives(); Directives();
exit(1); exit(1);
} }
...@@ -1011,6 +1084,14 @@ int parseconfigline(int entry, int lineno,char *line){ ...@@ -1011,6 +1084,14 @@ int parseconfigline(int entry, int lineno,char *line){
exit(1); exit(1);
} }
// additional sanity check. Has user set -m without -M?
if (cfg->emailopt && !cfg->address){
printout(LOG_CRIT,"Drive: %s, Directive -m useless without address Directive -M on line %d of file %s\n",
cfg->name, cfg->lineno, CONFIGFILE);
Directives();
exit(1);
}
entry++; entry++;
free(copy); free(copy);
return 1; return 1;
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
*/ */
#ifndef CVSID7 #ifndef CVSID7
#define CVSID7 "$Id: smartd.h,v 1.21 2002/11/13 10:04:13 ballen4705 Exp $\n" #define CVSID7 "$Id: smartd.h,v 1.22 2002/11/21 14:11:20 ballen4705 Exp $\n"
#endif #endif
// Configuration file // Configuration file
...@@ -39,9 +39,9 @@ ...@@ -39,9 +39,9 @@
#define MAXENTRIES 64 #define MAXENTRIES 64
// maximum length of a continued line in configuration file // maximum length of a continued line in configuration file
#define MAXCONTLINE 511 #define MAXCONTLINE 1023
// how often SMART status is checked, in seconds // default for how often SMART status is checked, in seconds
#define CHECKTIME 1800 #define CHECKTIME 1800
// maximum number of ATA devices to monitor // maximum number of ATA devices to monitor
...@@ -66,6 +66,8 @@ typedef struct mailinfo { ...@@ -66,6 +66,8 @@ typedef struct mailinfo {
int logged; int logged;
// time last email was sent, as defined by man 2 time // time last email was sent, as defined by man 2 time
time_t lastsent; time_t lastsent;
// time problem initially logged
time_t firstsent;
} mailinfo; } mailinfo;
// Used to store a list of devices and options that were in the // Used to store a list of devices and options that were in the
...@@ -85,8 +87,9 @@ typedef struct configfile_s { ...@@ -85,8 +87,9 @@ typedef struct configfile_s {
char errorlog; char errorlog;
// Should we ignore missing capabilities/SMART errors // Should we ignore missing capabilities/SMART errors
char permissive; char permissive;
// mailing information for each of the previous error types // mailing information for four of the previous error types plus mailtest
mailinfo maildata[4]; mailinfo maildata[5];
char emailopt;
// address to send email to // address to send email to
char *address; char *address;
// counts of ata and self-test errors. Perhaps ought to be in the // counts of ata and self-test errors. Perhaps ought to be in the
...@@ -123,6 +126,6 @@ typedef struct scsidevices_s { ...@@ -123,6 +126,6 @@ typedef struct scsidevices_s {
// Declare our own printing functions... // Declare our own printing functions...
void printout(int priority,char *fmt, ...) __attribute__ ((format(printf, 2, 3))); 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))); void printandmail(cfgfile *cfg, int which, int priority, char *fmt, ...) __attribute__ ((format(printf, 4, 5)));
int ataCheckDevice(atadevices_t *drive); int ataCheckDevice(atadevices_t *drive);
Release: 45 Release: 46
Summary: SMARTmontools - for monitoring S.M.A.R.T. disks and devices Summary: SMARTmontools - for monitoring S.M.A.R.T. disks and devices
Summary(cs): SMARTmontools - pro monitorovn S.M.A.R.T. disk a zazen Summary(cs): SMARTmontools - pro monitorovn S.M.A.R.T. disk a zazen
Summary(de): SMARTmontools - zur berwachung von S.M.A.R.T.-Platten und-Gerten Summary(de): SMARTmontools - zur berwachung von S.M.A.R.T.-Platten und-Gerten
...@@ -30,7 +30,7 @@ Packager: Bruce Allen <smartmontools-support@lists.sourceforge.net> ...@@ -30,7 +30,7 @@ Packager: Bruce Allen <smartmontools-support@lists.sourceforge.net>
# http://ftp1.sourceforge.net/smartmontools/smartmontools-%{version}-%{release}.tar.gz # http://ftp1.sourceforge.net/smartmontools/smartmontools-%{version}-%{release}.tar.gz
# CVS ID of this file is: # CVS ID of this file is:
# $Id: smartmontools.spec,v 1.69 2002/11/17 05:57:32 ballen4705 Exp $ # $Id: smartmontools.spec,v 1.70 2002/11/21 14:11:20 ballen4705 Exp $
# Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net> # Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
# Home page: http://smartmontools.sourceforge.net/ # Home page: http://smartmontools.sourceforge.net/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment