Skip to content
Snippets Groups Projects
Commit 6b90ddb8 authored by (no author)'s avatar (no author)
Browse files

This commit was manufactured by cvs2svn to create tag

'RELEASE_5_0_16'.

git-svn-id: https://smartmontools.svn.sourceforge.net/svnroot/smartmontools/tags/RELEASE_5_0_16@132 4ea69e1a-61f1-4043-bf83-b5c94c648137
parent 7d8a8b1b
No related branches found
No related tags found
No related merge requests found
# The "checkoutlist" file is used to support additional version controlled
# administrative files in $CVSROOT/CVSROOT, such as template files.
#
# The first entry on a line is a filename which will be checked out from
# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
# The remainder of the line is an error message to use if the file cannot
# be checked out.
#
# File format:
#
# [<whitespace>]<filename><whitespace><error message><end-of-line>
#
# comment lines begin with '#'
# The "commitinfo" file is used to control pre-commit checks.
# The filter on the right is invoked with the repository and a list
# of files to check. A non-zero exit of the filter program will
# cause the commit to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".
# Set this to "no" if pserver shouldn't check system users/passwords
#SystemAuth=no
# Put CVS lock files in this directory rather than directly in the repository.
#LockDir=/var/lock/cvs
# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top
# level of the new working directory when using the `cvs checkout'
# command.
#TopLevelAdmin=no
# Set `LogHistory' to `all' or `TOFEWGCMAR' to log all transactions to the
# history file, or a subset as needed (ie `TMAR' logs all write operations)
#LogHistory=TOFEWGCMAR
# This file affects handling of files based on their names.
#
# The -t/-f options allow one to treat directories of files
# as a single file, or to transform a file in other ways on
# its way in and out of CVS.
#
# The -m option specifies whether CVS attempts to merge files.
#
# The -k option specifies keyword expansion (e.g. -kb for binary).
#
# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
#
# wildcard [option value][option value]...
#
# where option is one of
# -f from cvs filter value: path to filter
# -t to cvs filter value: path to filter
# -m update methodology value: MERGE or COPY
# -k expansion mode value: b, o, kkv, &c
#
# and value is a single-quote delimited value.
# For example:
#*.gif -k 'b'
# The "editinfo" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.
# The "loginfo" file controls where "cvs commit" log information
# is sent. The first entry on a line is a regular expression which must match
# the directory that the change is being made to, relative to the
# $CVSROOT. If a match is found, then the remainder of the line is a filter
# program that should expect log information on its standard input.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name ALL appears as a regular expression it is always used
# in addition to the first matching regex or DEFAULT.
#
# You may specify a format string as part of the
# filter. The string is composed of a `%' followed
# by a single format character, or followed by a set of format
# characters surrounded by `{' and `}' as separators. The format
# characters are:
#
# s = file name
# V = old version number (pre-checkin)
# v = new version number (post-checkin)
#
# For example:
#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
# or
#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
# Three different line formats are valid:
# key -a aliases...
# key [options] directory
# key [options] directory files...
#
# Where "options" are composed of:
# -i prog Run "prog" on "cvs commit" from top-level of module.
# -o prog Run "prog" on "cvs checkout" of module.
# -e prog Run "prog" on "cvs export" of module.
# -t prog Run "prog" on "cvs rtag" of module.
# -u prog Run "prog" on "cvs update" of module.
# -d dir Place module in directory "dir" instead of module name.
# -l Top-level directory only -- do not recurse.
#
# NOTE: If you change any of the "Run" options above, you'll have to
# release and re-checkout any working directories of these modules.
#
# And "directory" is a path to a directory relative to $CVSROOT.
#
# The "-a" option specifies an alias. An alias is interpreted as if
# everything on the right of the "-a" had been typed on the command line.
#
# You can encode a module within a module by using the special '&'
# character to interpose another module into the current module. This
# can be useful for creating a module that consists of many directories
# spread out over the entire source repository.
# The "notify" file controls where notifications from watches set by
# "cvs watch add" or "cvs edit" are sent. The first entry on a line is
# a regular expression which is tested against the directory that the
# change is being made to, relative to the $CVSROOT. If it matches,
# then the remainder of the line is a filter program that should contain
# one occurrence of %s for the user to notify, and information on its
# standard input.
#
# "ALL" or "DEFAULT" can be used in place of the regular expression.
#
# For example:
#ALL mail %s -s "CVS notification"
# The "rcsinfo" file is used to control templates with which the editor
# is invoked on commit and import.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being made to, relative to the
# $CVSROOT. For the first match that is found, then the remainder of the
# line is the name of the file that contains the template.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".
# The "taginfo" file is used to control pre-tag checks.
# The filter on the right is invoked with the following arguments:
#
# $1 -- tagname
# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
# $3 -- repository
# $4-> file revision [file revision ...]
#
# A non-zero exit of the filter program will cause the tag to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".
# The "verifymsg" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* scsiprint.c
*
* Home page of code is: http://smartmontools.sourceforge.net
*
* Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* You should have received a copy of the GNU General Public License
* (for example COPYING); if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This code was originally developed as a Senior Thesis by Michael Cornwell
* at the Concurrent Systems Laboratory (now part of the Storage Systems
* Research Center), Jack Baskin School of Engineering, University of
* California, Santa Cruz. http://ssrc.soe.ucsc.edu/
*
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include "smartctl.h"
#include "extern.h"
#include "scsicmds.h"
#include "scsiprint.h"
#define GBUF_SIZE 65535
const char* CVSid5="$Id: scsiprint.cpp,v 1.9 2002/10/23 20:36:59 ballen4705 Exp $"
CVSID3 CVSID4 CVSID5 CVSID6;
UINT8 gBuf[GBUF_SIZE];
UINT8 gSmartPage = 0;
UINT8 gTempPage = 0;
UINT8 gSelfTestPage = 0;
UINT8 gStartStopPage = 0;
UINT8 gTapeAlertsPage = 0;
void scsiGetSupportPages ( int device)
{
int i;
if (logsense ( device , SUPPORT_LOG_PAGES, (UINT8 *) &gBuf) != 0)
{
perror ( "Log Sense failed");
exit (1);
}
for ( i = 4; i < gBuf[3] + LOGPAGEHDRSIZE ; i++)
{
switch ( gBuf[i])
{
case TEMPERATURE_PAGE:
gTempPage = 1;
break;
case STARTSTOP_CYCLE_COUNTER_PAGE:
gStartStopPage = 1;
break;
case SELFTEST_RESULTS_PAGE:
gSelfTestPage = 1;
break;
case SMART_PAGE:
gSmartPage = 1;
break;
case TAPE_ALERTS_PAGE:
gTapeAlertsPage = 1;
break;
default:
break;
}
}
}
void scsiGetSmartData (int device)
{
UINT8 returnvalue;
UINT8 currenttemp;
UINT8 triptemp;
if ( scsiCheckSmart(device, gSmartPage,
&returnvalue, &currenttemp, &triptemp ) != 0)
{
perror ( "scsiGetSmartData Failed");
exit (1);
}
if ( returnvalue )
printf("S.M.A.R.T. Sense: (%02x) %s\n", (UINT8) returnvalue,
scsiSmartGetSenseCode(returnvalue));
else
printf("S.M.A.R.T. Sense: Ok!\n");
if ( (currenttemp || triptemp) && !gTempPage)
{
printf("Current Drive Temperature: %d C\n", currenttemp);
printf("Drive Trip Temperature: %d C\n", triptemp);
}
}
void scsiGetTapeAlertsData (int device)
{
unsigned short pagelength;
unsigned short parametercode;
int i;
int failure = 0;
if ( logsense( device, TAPE_ALERTS_PAGE, (UINT8 *) &gBuf) != 0)
{
perror ( "scsiGetSmartData Failed");
exit (1);
}
if ( gBuf[0] != 0x2e )
{
printf("TapeAlerts Log Sense Failed\n");
exit(-1);
}
pagelength = (unsigned short) gBuf[2] << 8 | gBuf[3];
for ( i = 4; i < pagelength;i+=5 )
{
parametercode = (unsigned short) gBuf[i] << 8 | gBuf[i+1];
if (gBuf[i+4])
{
printf("Tape Alerts Error!!!\n%s\n",
scsiTapeAlertsTapeDevice(parametercode));
failure = 1;
}
}
if(!failure)
printf("No Tape Alerts Failure\n");
}
void scsiGetStartStopData ( int device)
{
UINT32 currentStartStop;
UINT32 recommendedStartStop;
if ( logsense( device, STARTSTOP_CYCLE_COUNTER_PAGE, (UINT8 *) &gBuf) != 0)
{
perror ( "scsiGetStartStopData Failed");
exit (1);
}
if ( gBuf[0] != STARTSTOP_CYCLE_COUNTER_PAGE )
{
printf("StartStop Log Sense Failed\n");
exit(-1);
}
recommendedStartStop= (UINT32) gBuf[28]<< 24 | gBuf[29] << 8 |
gBuf[30] << 16 | gBuf[31];
currentStartStop= (UINT32) gBuf[36]<< 24 | gBuf[37] << 8 |
gBuf[38] << 16 | gBuf[39];
printf("Current start stop count: %u times\n", currentStartStop);
printf("Recommended start stop count: %u times\n", recommendedStartStop);
}
void scsiGetDriveInfo ( int device)
{
char manufacturer[9];
char product[17];
char revision[5];
UINT8 smartsupport;
if (stdinquiry ( device, (UINT8 *) &gBuf) != 0)
{
perror ( "Standard Inquiry failed");
}
memset ( &manufacturer, 0, 8);
manufacturer[8] = '\0';
strncpy ((char *) &manufacturer, (char *) &gBuf[8], 8);
memset ( &product, 0, 16);
strncpy ((char *) &product, (char *) &gBuf[16], 16);
product[16] = '\0';
memset ( &revision, 0, 4);
strncpy ((char *) &revision, (char *) &gBuf[32], 4);
revision[4] = '\0';
printf("Device: %s %s Version: %s\n", manufacturer, product, revision);
if ( scsiSmartSupport( device, (UINT8 *) &smartsupport) != 0)
{
printf("Device does not support %s\n",(gBuf[0] & 0x1f)?
"TapeAlerts": "S.M.A.R.T.");
exit (1);
}
printf("Device supports %s and is %s\n%s\n",
(gBuf[0] & 0x1f)? "TapeAlerts" : "S.M.A.R.T.",
(smartsupport & DEXCPT_ENABLE)? "Disable" : "Enabled",
(smartsupport & EWASC_ENABLE)? "Temperature Warning Enabled":
"Temperature Warning Disabled or Not Supported");
}
void scsiSmartEnable( int device)
{
/* Enable Exception Control */
if ( scsiSmartDEXCPTDisable(device) != 0)
{
exit (1);
}
printf("S.M.A.R.T. enabled\n");
if (scsiSmartEWASCEnable(device) != 0)
{
printf("Temperature Warning not Supported\n");
}
else
{
printf("Temperature Warning Enabled\n");
}
return;
}
void scsiSmartDisable (int device)
{
if ( scsiSmartDEXCPTEnable(device) != 0)
{
exit (1);
}
printf("S.M.A.R.T. Disabled\n");
}
void scsiPrintTemp (int device)
{
UINT8 temp;
UINT8 trip;
if ( scsiGetTemp(device, &temp, &trip) != 0)
{
exit (1);
}
printf("Current Drive Temperature: %d C\n", temp);
printf("Drive Trip Temperature: %d C\n", trip);
}
void scsiPrintStopStart ( int device )
{
/**
unsigned int css;
if ( scsiGetStartStop(device, unsigned int *css) != 0)
{
exit (1);
}
printf ("Start Stop Count: %d\n", css);
**/
}
void scsiPrintMain (int fd)
{
if (driveinfo)
scsiGetDriveInfo(fd);
if (smartenable)
scsiSmartEnable(fd);
if (smartdisable)
scsiSmartDisable(fd);
if (checksmart)
{
scsiGetSupportPages (fd);
if(gTapeAlertsPage)
scsiGetTapeAlertsData (fd);
else
{
scsiGetSmartData(fd);
if(gTempPage)
scsiPrintTemp(fd);
if(gStartStopPage)
scsiGetStartStopData (fd);
}
}
if ( smartexeoffimmediate )
{
if ( scsiSmartOfflineTest (fd) != 0)
{
printf( "Smartctl: Smart Offline Failed\n");
exit(-1);
}
printf ("Drive Command Successful offline test has begun\n");
printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT);
}
if ( smartshortcapselftest )
{
if ( scsiSmartShortCapSelfTest (fd) != 0)
{
printf( "Smartctl: Smart Short Self Test Failed\n");
exit(-1);
}
printf ("Drive Command Successful Short Self test has begun\n");
printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT);
}
if ( smartshortselftest )
{
if ( scsiSmartShortSelfTest (fd) != 0)
{
printf( "Smartctl: Smart Short Self Test Failed\n");
exit(-1);
}
printf ("Drive Command Successful Short Self test has begun\n");
printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT);
}
if ( smartextendselftest )
{
if ( scsiSmartExtendSelfTest (fd) != 0)
{
printf( "S.M.A.R.T. Extended Self Test Failed\n");
exit(-1);
}
printf ("Drive Command Successful Extended Self test has begun\n");
printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT);
}
if ( smartextendcapselftest )
{
if ( scsiSmartExtendCapSelfTest (fd) != 0)
{
printf( "S.M.A.R.T. Extended Self Test Failed\n");
exit(-1);
}
printf ("Drive Command Successful Extended Self test has begun\n");
printf ("Use smartctl -%c to abort test\n", SMARTSELFTESTABORT);
}
if ( smartselftestabort )
{
if ( scsiSmartSelfTestAbort (fd) != 0)
{
printf( "S.M.A.R.T. Self Test Abort Failed\n");
exit(-1);
}
printf ("Drive Command Successful self test aborted\n");
}
}
/*
* smartctl.c
*
* Home page of code is: http://smartmontools.sourceforge.net
*
* Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* You should have received a copy of the GNU General Public License
* (for example COPYING); if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This code was originally developed as a Senior Thesis by Michael Cornwell
* at the Concurrent Systems Laboratory (now part of the Storage Systems
* Research Center), Jack Baskin School of Engineering, University of
* California, Santa Cruz. http://ssrc.soe.ucsc.edu/
*
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <stdarg.h>
#include "smartctl.h"
#include "atacmds.h"
#include "ataprint.h"
#include "scsicmds.h"
#include "scsiprint.h"
extern const char *CVSid1, *CVSid2, *CVSid4, *CVSid5;
const char* CVSid6="$Id: smartctl.cpp,v 1.20 2002/10/25 08:50:21 ballen4705 Exp $"
CVSID1 CVSID2 CVSID4 CVSID5 CVSID6;
unsigned char driveinfo = FALSE;
unsigned char checksmart = FALSE;
unsigned char smartvendorattrib = FALSE;
unsigned char generalsmartvalues = FALSE;
unsigned char smartselftestlog = FALSE;
unsigned char smarterrorlog = FALSE;
unsigned char smartdisable = FALSE;
unsigned char smartenable = FALSE;
unsigned char smartstatus = FALSE;
unsigned char smartexeoffimmediate = FALSE;
unsigned char smartshortselftest = FALSE;
unsigned char smartextendselftest = FALSE;
unsigned char smartshortcapselftest = FALSE;
unsigned char smartextendcapselftest = FALSE;
unsigned char smartselftestabort = FALSE;
unsigned char smartautoofflineenable = FALSE;
unsigned char smartautoofflinedisable = FALSE;
unsigned char smartautosaveenable = FALSE;
unsigned char smartautosavedisable = FALSE;
unsigned char printcopyleft = FALSE;
unsigned char smart009minutes = FALSE;
unsigned char quietmode = FALSE;
unsigned char veryquietmode = FALSE;
int testcase = -1;
void printslogan(){
pout("smartctl version %d.%d-%d Copyright (C) 2002 Bruce Allen\n",RELEASE_MAJOR,RELEASE_MINOR,SMARTMONTOOLS_VERSION);
pout("Home page is %s\n\n",PROJECTHOME);
return;
}
int massagecvs(char *out,const char *in){
char filename[128], version[128], date[128];
int i=0;
const char *savein=in;
// skip to I of $Id:
while (*in !='\0' && *in!='I')
in++;
// skip to start of filename
if (!*in)
return 0;
in+=4;
// copy filename
i=0;
while (i<100 && *in!=',' && *in)
filename[i++]=*in++;
filename[i]='\0';
if (!*in)
return 0;
// skip ,v and space
in+=3;
i=0;
// copy version number
while (i<100 && *in!=' ' && *in)
version[i++]=*in++;
version[i]='\0';
if (!*in)
return 0;
// skip space
in++;
// copy date
i=0;
while (i<100 && *in!=' ' && *in)
date[i++]=*in++;
date[i]='\0';
sprintf(out,"%-13s revision: %-6s date: %-15s", filename, version, date);
return in-savein;
}
// prints a single set of CVS ids
void printone(const char *cvsid){
char strings[512];
const char *here;
int len,line=1;
here=cvsid;
while ((len=massagecvs(strings,here))){
switch (line++){
case 1:
pout("Module:");
break;
default:
pout(" uses:");
}
pout(" %s\n",strings);
here+=len;
}
return;
}
void printcopy(){
pout("smartctl comes with ABSOLUTELY NO WARRANTY. This\n");
pout("is free software, and you are welcome to redistribute it\n");
pout("under the terms of the GNU General Public License Version 2.\n");
pout("See http://www.gnu.org for further details.\n\n");
pout("CVS version IDs of files used to build this code are:\n");
printone(CVSid6);
printone(CVSid1);
printone(CVSid2);
printone(CVSid4);
printone(CVSid5);
return;
}
/* void prints help information for command syntax */
void Usage ( void){
printf("Usage: smartctl -[options] [device]\n");
printf("\nRead Only Options:\n");
printf(" %c Show version, copyright and license info\n", PRINTCOPYLEFT);
printf(" %c Show all SMART Information (ATA/SCSI)\n",SMARTVERBOSEALL);
printf(" %c Show SMART Drive Info (ATA/SCSI)\n",DRIVEINFO);
printf(" %c Show SMART Status (ATA/SCSI)\n",CHECKSMART);
printf(" %c Show SMART General Attributes (ATA Only)\n", GENERALSMARTVALUES);
printf(" %c Show SMART Vendor Attributes (ATA Only)\n", SMARTVENDORATTRIB);
printf(" %c Show SMART Drive Error Log (ATA Only\n", SMARTERRORLOG);
printf(" %c Show SMART Drive Self Test Log (ATA Only)\n", SMARTSELFTESTLOG);
printf(" %c Quiet: only show SMART drive errors (ATA Only)\n", QUIETMODE);
printf(" %c Very Quiet: no display, use exit status (ATA Only)\n", VERYQUIETMODE);
printf("\nVendor-specific Display Options:\n");
printf(" %c Raw Attribute 009 is minutes (ATA Only)\n", SMART009MINUTES);
printf("\nEnable/Disable Options:\n");
printf(" %c Enable SMART data collection (ATA/SCSI)\n",SMARTENABLE);
printf(" %c Disable SMART data collection (ATA/SCSI)\n",SMARTDISABLE);
printf(" %c Enable SMART Automatic Offline Test (ATA Only)\n", SMARTAUTOOFFLINEENABLE);
printf(" %c Disable SMART Automatic Offline Test (ATA Only)\n", SMARTAUTOOFFLINEDISABLE);
printf(" %c Enable SMART Attribute Autosave (ATA Only)\n", SMARTAUTOSAVEENABLE);
printf(" %c Disable SMART Attribute Autosave (ATA Only)\n", SMARTAUTOSAVEDISABLE);
printf("\nTest Options (no more than one):\n");
printf(" %c Execute Off-line data collection (ATA Only)\n", SMARTEXEOFFIMMEDIATE);
printf(" %c Execute Short Self Test (ATA Only)\n", SMARTSHORTSELFTEST );
printf(" %c Execute Short Self Test (Captive Mode) (ATA Only)\n", SMARTSHORTCAPSELFTEST );
printf(" %c Execute Extended Self Test (ATA Only)\n", SMARTEXTENDSELFTEST );
printf(" %c Execute Extended Self Test (Captive) (ATA Only)\n", SMARTEXTENDCAPSELFTEST );
printf(" %c Execute Self Test Abort (ATA Only)\n", SMARTSELFTESTABORT );
printf("\nExamples:\n");
printf(" smartctl -etf /dev/hda (Enables SMART on first disk)\n");
printf(" smartctl -a /dev/hda (Prints all SMART information)\n");
printf(" smartctl -X /dev/hda (Executes extended disk self-test)\n");
printf(" smartctl -qvL /dev/hda (Prints Self-Test & Attribute errors.)\n");
}
const char opts[] = {
DRIVEINFO, CHECKSMART, SMARTVERBOSEALL, SMARTVENDORATTRIB,
GENERALSMARTVALUES, SMARTERRORLOG, SMARTSELFTESTLOG, SMARTDISABLE,
SMARTENABLE, SMARTAUTOOFFLINEENABLE, SMARTAUTOOFFLINEDISABLE,
SMARTEXEOFFIMMEDIATE, SMARTSHORTSELFTEST, SMARTEXTENDSELFTEST,
SMARTSHORTCAPSELFTEST, SMARTEXTENDCAPSELFTEST, SMARTSELFTESTABORT,
SMARTAUTOSAVEENABLE,SMARTAUTOSAVEDISABLE,PRINTCOPYLEFT,SMART009MINUTES,QUIETMODE,VERYQUIETMODE,'h','?','\0'
};
/* Takes command options and sets features to be run */
void ParseOpts (int argc, char** argv){
int optchar;
extern char *optarg;
extern int optopt, optind, opterr;
opterr=optopt=0;
while (-1 != (optchar = getopt(argc, argv, opts))) {
switch (optchar){
case QUIETMODE:
quietmode=TRUE;
break;
case VERYQUIETMODE:
veryquietmode=TRUE;
break;
case SMART009MINUTES:
smart009minutes=TRUE;
break;
case PRINTCOPYLEFT :
printcopyleft=TRUE;
break;
case DRIVEINFO :
driveinfo = TRUE;
break;
case CHECKSMART :
checksmart = TRUE;
break;
case SMARTVERBOSEALL :
driveinfo = TRUE;
checksmart = TRUE;
generalsmartvalues = TRUE;
smartvendorattrib = TRUE;
smarterrorlog = TRUE;
smartselftestlog = TRUE;
break;
case SMARTVENDORATTRIB :
smartvendorattrib = TRUE;
break;
case GENERALSMARTVALUES :
generalsmartvalues = TRUE;
break;
case SMARTERRORLOG :
smarterrorlog = TRUE;
break;
case SMARTSELFTESTLOG :
smartselftestlog = TRUE;
break;
case SMARTDISABLE :
smartdisable = TRUE;
break;
case SMARTENABLE :
smartenable = TRUE;
break;
case SMARTAUTOSAVEENABLE:
smartautosaveenable = TRUE;
break;
case SMARTAUTOSAVEDISABLE:
smartautosavedisable = TRUE;
break;
case SMARTAUTOOFFLINEENABLE:
smartautoofflineenable = TRUE;
break;
case SMARTAUTOOFFLINEDISABLE:
smartautoofflinedisable = TRUE;
break;
case SMARTEXEOFFIMMEDIATE:
smartexeoffimmediate = TRUE;
testcase=OFFLINE_FULL_SCAN;
break;
case SMARTSHORTSELFTEST :
smartshortselftest = TRUE;
testcase=SHORT_SELF_TEST;
break;
case SMARTEXTENDSELFTEST :
smartextendselftest = TRUE;
testcase=EXTEND_SELF_TEST;
break;
case SMARTSHORTCAPSELFTEST:
smartshortcapselftest = TRUE;
testcase=SHORT_CAPTIVE_SELF_TEST;
break;
case SMARTEXTENDCAPSELFTEST:
smartextendcapselftest = TRUE;
testcase=EXTEND_CAPTIVE_SELF_TEST;
break;
case SMARTSELFTESTABORT:
smartselftestabort = TRUE;
testcase=ABORT_SELF_TEST;
break;
case 'h':
case '?':
default:
veryquietmode=FALSE;
printslogan();
if (optopt){
pout("=======> UNRECOGNIZED OPTION: %c <=======\n\n",optopt);
Usage();
exit(FAILCMD);
}
Usage();
exit(0);
}
}
// Do this here, so results are independent of argument order
if (quietmode)
veryquietmode=TRUE;
// error message if user has asked for more than one test
if (1<(smartexeoffimmediate+smartshortselftest+smartextendselftest+
smartshortcapselftest+smartextendcapselftest+smartselftestabort)){
veryquietmode=FALSE;
printslogan();
Usage();
printf ("\nERROR: smartctl can only run a single test (or abort) at a time.\n\n");
exit(FAILCMD);
}
// From here on, normal operations...
printslogan();
// Print Copyright/License info if needed
if (printcopyleft){
printcopy();
if (argc==2)
exit(0);
}
}
// Printing function (controlled by global veryquietmode)
void pout(char *fmt, ...){
va_list ap;
// initialize variable argument list
va_start(ap,fmt);
if (veryquietmode){
va_end(ap);
return;
}
// print out
vprintf(fmt,ap);
va_end(ap);
return;
}
/* Main Program */
int main (int argc, char **argv){
int fd,retval=0;
char *device;
// Part input arguments
ParseOpts(argc,argv);
// Further argument checking
if (argc != 3){
Usage();
return FAILCMD;
}
// open device - read-only mode is enough to issue needed commands
fd = open(device=argv[2], O_RDONLY);
if (fd<0) {
perror("Smartctl device open failed");
return FAILDEV;
}
if (device[5] == 'h')
retval=ataPrintMain(fd);
else if (device[5] == 's')
scsiPrintMain (fd);
else {
Usage();
return FAILCMD;
}
return retval;
}
/*
* Home page of code is: http://smartmontools.sourceforge.net
*
* Copyright (C) 2002 Bruce Allen <smartmontools-support@lists.sourceforge.net>
* Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* You should have received a copy of the GNU General Public License
* (for example COPYING); if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* This code was originally developed as a Senior Thesis by Michael Cornwell
* at the Concurrent Systems Laboratory (now part of the Storage Systems
* Research Center), Jack Baskin School of Engineering, University of
* California, Santa Cruz. http://ssrc.soe.ucsc.edu/
*
*/
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <linux/hdreg.h>
#include <syslog.h>
#include <stdarg.h>
#include "atacmds.h"
#include "scsicmds.h"
#include "smartd.h"
extern const char *CVSid1, *CVSid2;
const char *CVSid3="$Id: smartd.cpp,v 1.31 2002/10/25 14:54:14 ballen4705 Exp $"
CVSID1 CVSID4 CVSID7;
int daemon_init(void){
pid_t pid;
int i;
if ( (pid = fork()) < 0)
// unable to fork!
exit(1);
else if (pid != 0)
// we are the parent process -- exit cleanly
exit (0);
// from here on, we are the child process
setsid();
// close any open file descriptors
for (i=getdtablesize();i>=0;--i)
close(i);
// redirect any IO attempts to /dev/null
// open stdin
i=open("/dev/null",O_RDWR);
// stdout
dup(i);
// stderr
dup(i);
umask(0);
chdir("/");
return(0);
}
// This function prints either to stdout or to the syslog as needed
void printout(int priority,char *fmt, ...){
va_list ap;
// initialize variable argument list
va_start(ap,fmt);
if (debugmode)
vprintf(fmt,ap);
else
vsyslog(priority,fmt,ap);
va_end(ap);
return;
}
// Printing function for atacmds
void pout(char *fmt, ...){
va_list ap;
// initialize variable argument list
va_start(ap,fmt);
va_end(ap);
return;
#if (0)
// print out
vprintf(fmt,ap);
va_end(ap);
return;
#endif
}
void printhead(){
printout(LOG_INFO,"smartd version %d.%d-%d - S.M.A.R.T. Daemon.\n",
RELEASE_MAJOR, RELEASE_MINOR, SMARTMONTOOLS_VERSION);
printout(LOG_INFO,"Home page is %s\n\n",PROJECTHOME);
return;
}
/* prints help information for command syntax */
void Usage (void){
printout(LOG_INFO,"usage: smartd -[opts] \n\n");
printout(LOG_INFO,"Read Only Options:\n");
printout(LOG_INFO," %c Start smartd in debug Mode\n",DEBUGMODE);
printout(LOG_INFO," %c Print License, Copyright, and version information\n\n",PRINTCOPYLEFT);
printout(LOG_INFO,"Configuration file: /etc/smartd.conf\n");
}
// scan to see what ata devices there are, and if they support SMART
int atadevicescan (atadevices_t *devices, char *device){
int fd;
struct hd_driveid drive;
printout(LOG_INFO,"Opening device %s\n", device);
fd = open(device, O_RDONLY);
if (fd < 0) {
if (errno<sys_nerr)
printout(LOG_INFO,"%s: Device: %s, Opening device failed\n",sys_errlist[errno],device);
else
printout(LOG_INFO,"Device: %s, Opening device failed\n",device);
return 1;
}
if (ataReadHDIdentity (fd,&drive) || !ataSmartSupport(drive) || ataEnableSmart(fd)){
// device exists, but not able to do SMART
close(fd);
printout(LOG_INFO,"Device: %s, Found but not SMART capable, or couldn't enable SMART\n",device);
return 2;
}
// Does device support read values and read thresholds? We should
// modify this next block for devices that do support SMART status
// but don't support read values and read thresholds.
if (ataReadSmartValues (fd,&devices[numatadevices].smartval)){
close(fd);
printout(LOG_INFO,"Device: %s, Read SMART Values Failed\n",device);
return 3;
}
else if (ataReadSmartThresholds (fd,&devices[numatadevices].smartthres)){
close(fd);
printout(LOG_INFO,"Device: %s, Read SMART Thresholds Failed\n",device);
return 4;
}
// device exists, and does SMART. Add to list
printout(LOG_INFO,"%s Found and is SMART capable. Adding to \"monitor\" list.\n",device);
devices[numatadevices].fd = fd;
strcpy(devices[numatadevices].devicename, device);
devices[numatadevices].drive = drive;
// This makes NO sense. We may want to know if the drive supports
// Offline Surface Scan, for example. But checking if it supports
// self-tests seems useless. In any case, smartd NEVER uses this
// field anywhere...
devices[numatadevices].selftest =
isSupportSelfTest(devices[numatadevices].smartval);
numatadevices++;
return 0;
}
// This function is hard to read and ought to be rewritten. Why in the
// world is the four-byte integer cast to a pointer to an eight-byte
// object??
int scsidevicescan (scsidevices_t *devices, char *device){
int i, fd, smartsupport;
unsigned char tBuf[4096];
// open device
printout(LOG_INFO,"Opening device %s\n", device);
fd=open(device, O_RDWR);
if (fd<0) {
if (errno<sys_nerr)
printout(LOG_INFO,"%s: Device: %s, Opening device failed\n",sys_errlist[errno],device);
else
printout(LOG_INFO,"Device: %s, Opening device failed\n", device);
return 1;
}
// check that it's ready for commands
if (!testunitready(fd)){
printout(LOG_INFO,"Device: %s, Failed Test Unit Ready\n", device);
close(fd);
return 2;
}
// make sure that we can read mode page
if (modesense(fd, 0x1c, (UINT8 *) &tBuf)){
printout(LOG_INFO,"Device: %s, Failed read of ModePage 0x1c\n", device);
close(fd);
return 3;
}
// see if SMART is supported and enabled
if (scsiSmartSupport(fd, (UINT8 *) &smartsupport) ||
(smartsupport & DEXCPT_ENABLE)){
printout(LOG_INFO,"Device: %s, SMART not supported or not enabled\n", device);
close(fd);
return 4;
}
// now we can proceed to register the device
printout(LOG_INFO, "Device: %s, Found and is SMART capable. Adding to \"monitor\" list.\n",device);
devices[numscsidevices].fd = fd;
strcpy(devices[numscsidevices].devicename,device);
// register the supported functionality. The smartd code does not
// seem to make any further use of this information.
if (logsense(fd, SUPPORT_LOG_PAGES, (UINT8 *) &tBuf) == 0){
for ( i = 4; i < tBuf[3] + LOGPAGEHDRSIZE ; i++){
switch ( tBuf[i]){
case TEMPERATURE_PAGE:
devices[numscsidevices].TempPageSupported = 1;
break;
case SMART_PAGE:
devices[numscsidevices].SmartPageSupported = 1;
break;
default:
break;
}
}
}
numscsidevices++;
return 0;
}
void ataCompareSmartValues (atadevices_t *device, struct ata_smart_values new ){
int i;
int oldval,newval,idold,idnew;
for ( i =0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++){
// which device is it?
idnew=new.vendor_attributes[i].id;
idold=device->smartval.vendor_attributes[i].id;
if (idold && idnew){
// if it's a valid attribute, compare values
newval=new.vendor_attributes[i].current;
oldval=device->smartval.vendor_attributes[i].current;
if (oldval!=newval){
// values have changed; print them
char *loc,attributename[64];
loc=attributename;
ataPrintSmartAttribName(attributename,idnew);
// skip blank space in name
while (*loc && *loc==' ')
loc++;
printout(LOG_INFO, "Device: %s, SMART Attribute: %s changed from %i to %i\n",
device->devicename,loc,oldval,newval);
}
}
}
}
int ataCheckDevice( atadevices_t *drive){
struct ata_smart_values tempsmartval;
struct ata_smart_thresholds tempsmartthres;
int failed;
char *loc,attributename[64];
// Coming into this function, *drive contains the last values measured,
// and we read the NEW values into tempsmartval
if (ataReadSmartValues(drive->fd,&tempsmartval))
printout(LOG_INFO, "%s:Failed to read SMART values\n", drive->devicename);
// and we read the new thresholds into tempsmartthres
if (ataReadSmartThresholds (drive->fd, &tempsmartthres))
printout(LOG_INFO, "%s:Failed to read SMART thresholds\n",drive->devicename);
// See if any vendor attributes are below minimum, and print them out
if ((failed=ataCheckSmart(tempsmartval,tempsmartthres,1))){
ataPrintSmartAttribName(attributename,failed);
// skip blank space in name
loc=attributename;
while (*loc && *loc==' ')
loc++;
printout(LOG_CRIT,"Device: %s, Failed SMART attribute: %s. Use smartctl -a %s.\n",
drive->devicename,loc,drive->devicename);
}
// WHEN IT WORKS, we should here add a call to ataSmartStatus2()
// either in addition to or instead of the ataCheckSmart command
// above. This is the "right" long-term solution.
// see if any values have changed. Second argument is new values
ataCompareSmartValues (drive , tempsmartval);
// Save the new values into *drive for the next time around
drive->smartval = tempsmartval;
drive->smartthres = tempsmartthres;
return 0;
}
int scsiCheckDevice( scsidevices_t *drive){
UINT8 returnvalue;
UINT8 currenttemp;
UINT8 triptemp;
currenttemp = triptemp = 0;
if (scsiCheckSmart( drive->fd, drive->SmartPageSupported, &returnvalue, &currenttemp, &triptemp ) != 0)
printout(LOG_INFO, "%s:Failed to read SMART values\n", drive->devicename);
if (returnvalue)
printout(LOG_CRIT, "Device: %s, SMART Failure: (%02x) %s\n", drive->devicename,
returnvalue, scsiSmartGetSenseCode( returnvalue) );
else
printout(LOG_INFO,"Device: %s, Acceptable attribute: %d\n", drive->devicename, returnvalue);
// Seems to completely ignore what capabilities were found on the
// device when scanned
if (currenttemp){
if ( (currenttemp != drive->Temperature) && ( drive->Temperature) )
printout(LOG_INFO, "Device: %s, Temperature changed %d degrees to %d degrees since last reading\n",
drive->devicename, (int) (currenttemp - drive->Temperature), (unsigned int) currenttemp );
drive->Temperature = currenttemp;
}
return 0;
}
void CheckDevices ( atadevices_t *atadevices, scsidevices_t *scsidevices){
int i;
if (!numatadevices && !numscsidevices){
printout(LOG_INFO,"Unable to monitor any SMART enabled ATA or SCSI devices.\n");
return;
}
printout(LOG_INFO,"Started monitoring %d ATA and %d SCSI devices\n",numatadevices,numscsidevices);
while (1){
for (i = 0; i < numatadevices;i++)
ataCheckDevice ( &atadevices[i]);
for (i = 0; i < numscsidevices;i++)
scsiCheckDevice ( &scsidevices[i]);
sleep ( checktime );
}
}
int massagecvs(char *out,const char *in){
char filename[128], version[128], date[128];
int i=0;
const char *savein=in;
// skip to I of $Id:
while (*in !='\0' && *in!='I')
in++;
// skip to start of filename
if (!*in)
return 0;
in+=4;
// copy filename
i=0;
while (i<100 && *in!=',' && *in)
filename[i++]=*in++;
filename[i]='\0';
if (!*in)
return 0;
// skip ,v and space
in+=3;
i=0;
// copy version number
while (i<100 && *in!=' ' && *in)
version[i++]=*in++;
version[i]='\0';
if (!*in)
return 0;
// skip space
in++;
// copy date
i=0;
while (i<100 && *in!=' ' && *in)
date[i++]=*in++;
date[i]='\0';
sprintf(out,"%-13s revision: %-6s date: %-15s", filename, version, date);
return in-savein;
}
// prints a single set of CVS ids
void printone(const char *cvsid){
char strings[512];
const char *here;
int len,line=1;
here=cvsid;
while ((len=massagecvs(strings,here))){
switch (line++){
case 1:
printout(LOG_INFO,"Module:");
break;
default:
printout(LOG_INFO," uses:");
}
printout(LOG_INFO," %s\n",strings);
here+=len;
}
return;
}
char copyleftstring[]=
"smartd comes with ABSOLUTELY NO WARRANTY. This\n"
"is free software, and you are welcome to redistribute it\n"
"under the terms of the GNU General Public License Version 2.\n"
"See http://www.gnu.org for further details.\n\n";
cfgfile config[MAXENTRIES];
// returns number of entries in config file, or 0 if no config file exists
int parseconfigfile(){
FILE *fp;
int entry=0,lineno=0;
char line[MAXLINELEN+2];
// Open config file, if it exists
fp=fopen(CONFIGFILE,"r");
if (fp==NULL && errno!=ENOENT){
// file exists but we can't read it
if (errno<sys_nerr)
printout(LOG_INFO,"%s: Unable to open configuration file %s\n",
sys_errlist[errno],CONFIGFILE);
else
printout(LOG_INFO,"Unable to open configuration file %s\n",CONFIGFILE);
exit(1);
}
// No config file
if (fp==NULL)
return 0;
// configuration file exists. Read it and search for devices
printout(LOG_INFO,"Using configuration file %s\n",CONFIGFILE);
while (fgets(line,MAXLINELEN+2,fp)){
int len;
char *dev;
// track linenumber for error messages
lineno++;
// See if line is too long
len=strlen(line);
if (len>MAXLINELEN){
printout(LOG_INFO,"Error: line %d of file %s is more than than %d characters long.\n",
lineno,CONFIGFILE,MAXLINELEN);
exit(1);
}
// eliminate any terminating newline
if (line[len-1]=='\n'){
len--;
line[len]='\0';
}
// Skip white space
dev=line;
while (*dev && (*dev==' ' || *dev=='\t'))
dev++;
len=strlen(dev);
// If line is blank, or a comment, skip it
if (!len || *dev=='#')
continue;
// We've got a legit entry
if (entry>=MAXENTRIES){
printout(LOG_INFO,"Error: configuration file %s can have no more than %d entries\n",
CONFIGFILE,MAXENTRIES);
exit(1);
}
// Copy information into data structure for after forking
strcpy(config[entry].name,dev);
config[entry].lineno=lineno;
config[entry].tryscsi=config[entry].tryata=1;
// Try and recognize if a IDE or SCSI device
if (len>5 && !strncmp("/dev/h",dev, 6))
config[entry].tryscsi=0;
if (len>5 && !strncmp("/dev/s",dev, 6))
config[entry].tryata=0;
entry++;
}
fclose(fp);
if (entry)
return entry;
printout(LOG_INFO,"Configuration file %s contained no devices (like /dev/hda)\n",CONFIGFILE);
exit(1);
}
const char opts[] = { DEBUGMODE, EMAILNOTIFICATION, PRINTCOPYLEFT,'h','?','\0' };
/* Main Program */
int main (int argc, char **argv){
atadevices_t atadevices[MAXATADEVICES], *atadevicesptr;
scsidevices_t scsidevices[MAXSCSIDEVICES], *scsidevicesptr;
int optchar,i;
extern char *optarg;
extern int optopt, optind, opterr;
int entries;
numatadevices=0;
numscsidevices=0;
scsidevicesptr = scsidevices;
atadevicesptr = atadevices;
opterr=optopt=0;
// Parse input options:
while (-1 != (optchar = getopt(argc, argv, opts))){
switch(optchar) {
case PRINTCOPYLEFT:
printcopyleft=TRUE;
break;
case DEBUGMODE :
debugmode = TRUE;
break;
case EMAILNOTIFICATION:
emailnotification = TRUE;
break;
case '?':
case 'h':
default:
debugmode=1;
if (optopt) {
printhead();
printout(LOG_INFO,"=======> UNRECOGNIZED OPTION: %c <======= \n\n",optopt);
Usage();
exit(-1);
}
printhead();
Usage();
exit(0);
}
}
// If needed print copyright, license and version information
if (printcopyleft){
debugmode=1;
printhead();
printout(LOG_INFO,copyleftstring);
printout(LOG_INFO,"CVS version IDs of files used to build this code are:\n");
printone(CVSid3);
printone(CVSid1);
printone(CVSid2);
exit(0);
}
// print header
printhead();
// look in configuration file CONFIGFILE (normally /etc/smartd.conf)
entries=parseconfigfile();
// If in background as a daemon, fork and close file descriptors
if (!debugmode){
daemon_init();
}
// If we found a config file, look at its entries
if (entries)
for (i=0;i<entries;i++){
if (config[i].tryata && atadevicescan(atadevicesptr, config[i].name))
printout(LOG_INFO,"Unable to register ATA device %s at line %d of file %s\n",
config[i].name, config[i].lineno, CONFIGFILE);
if (config[i].tryscsi && scsidevicescan(scsidevicesptr, config[i].name))
printout(LOG_INFO,"Unable to register SCSI device %s at line %d of file %s\n",
config[i].name, config[i].lineno, CONFIGFILE);
}
else {
char deviceata[] = "/dev/hda";
char devicescsi[]= "/dev/sda";
printout(LOG_INFO,"No configuration file %s found. Searching for devices.\n",CONFIGFILE);
for(i=0;i<MAXATADEVICES;i++,deviceata[7]++)
atadevicescan(atadevicesptr, deviceata);
for(i=0;i<MAXSCSIDEVICES;i++,devicescsi[7]++)
scsidevicescan(scsidevicesptr, devicescsi);
}
CheckDevices(atadevicesptr, scsidevicesptr);
return 0;
}
#!/bin/bash
# execute this script in the current shell, using for example
# . cvs_script
unset CVS_SERVER
export CVS_RSH=ssh
export CVSROOT=:ext:ballen4705@cvs.smartmontools.sourceforge.net:/cvsroot/smartmontools
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment