📄 smartd.cpp
字号:
"Use ID = 0 to turn off -C and/or -U Directives\n" "Example: /dev/hda -a\n", configfile); return;}/* Returns a pointer to a static string containing a formatted list of the valid arguments to the option opt or NULL on failure. */const char *GetValidArgList(char opt) { switch (opt) { case 'c': return "<FILE_NAME>, -"; case 's': return "valid_regular_expression"; case 'l': return "daemon, local0, local1, local2, local3, local4, local5, local6, local7"; case 'q': return "nodev, errors, nodevstartup, never, onecheck, showtests"; case 'r': return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; case 'p': return "<FILE_NAME>"; case 'i': return "<INTEGER_SECONDS>"; default: return NULL; }}/* prints help information for command syntax */void Usage (void){ PrintOut(LOG_INFO,"Usage: smartd [options]\n\n");#ifdef HAVE_GETOPT_LONG PrintOut(LOG_INFO," -c NAME|-, --configfile=NAME|-\n"); PrintOut(LOG_INFO," Read configuration file NAME or stdin [default is %s]\n\n", configfile); PrintOut(LOG_INFO," -d, --debug\n"); PrintOut(LOG_INFO," Start smartd in debug mode\n\n"); PrintOut(LOG_INFO," -D, --showdirectives\n"); PrintOut(LOG_INFO," Print the configuration file Directives and exit\n\n"); PrintOut(LOG_INFO," -h, --help, --usage\n"); PrintOut(LOG_INFO," Display this help and exit\n\n"); PrintOut(LOG_INFO," -i N, --interval=N\n"); PrintOut(LOG_INFO," Set interval between disk checks to N seconds, where N >= 10\n\n"); PrintOut(LOG_INFO," -l local[0-7], --logfacility=local[0-7]\n");#ifndef _WIN32 PrintOut(LOG_INFO," Use syslog facility local0 - local7 or daemon [default]\n\n");#else PrintOut(LOG_INFO," Log to \"./smartd.log\", stdout, stderr [default is event log]\n\n");#endif#ifndef _WIN32 PrintOut(LOG_INFO," -n, --no-fork\n"); PrintOut(LOG_INFO," Do not fork into background\n\n");#endif // _WIN32 PrintOut(LOG_INFO," -p NAME, --pidfile=NAME\n"); PrintOut(LOG_INFO," Write PID file NAME\n\n"); PrintOut(LOG_INFO," -q WHEN, --quit=WHEN\n"); PrintOut(LOG_INFO," Quit on one of: %s\n\n", GetValidArgList('q')); PrintOut(LOG_INFO," -r, --report=TYPE\n"); PrintOut(LOG_INFO," Report transactions for one of: %s\n\n", GetValidArgList('r'));#ifdef _WIN32 PrintOut(LOG_INFO," --service\n"); PrintOut(LOG_INFO," Running as windows service (see man page), install with:\n"); PrintOut(LOG_INFO," smartd install [options]\n"); PrintOut(LOG_INFO," Remove service with:\n"); PrintOut(LOG_INFO," smartd remove\n\n");#else#endif // _WIN32 || __CYGWIN__ PrintOut(LOG_INFO," -V, --version, --license, --copyright\n"); PrintOut(LOG_INFO," Print License, Copyright, and version information\n");#else PrintOut(LOG_INFO," -c NAME|- Read configuration file NAME or stdin [default is %s]\n", configfile); PrintOut(LOG_INFO," -d Start smartd in debug mode\n"); PrintOut(LOG_INFO," -D Print the configuration file Directives and exit\n"); PrintOut(LOG_INFO," -h Display this help and exit\n"); PrintOut(LOG_INFO," -i N Set interval between disk checks to N seconds, where N >= 10\n"); PrintOut(LOG_INFO," -l local? Use syslog facility local0 - local7, or daemon\n"); PrintOut(LOG_INFO," -n Do not fork into background\n"); PrintOut(LOG_INFO," -p NAME Write PID file NAME\n"); PrintOut(LOG_INFO," -q WHEN Quit on one of: %s\n", GetValidArgList('q')); PrintOut(LOG_INFO," -r TYPE Report transactions for one of: %s\n", GetValidArgList('r')); PrintOut(LOG_INFO," -V Print License, Copyright, and version information\n");#endif}// returns negative if problem, else fd>=0static int OpenDevice(char *device, char *mode, int scanning) { int fd; char *s=device; // If there is an ASCII "space" character in the device name, // terminate string there. This is for 3ware and highpoint devices only. if ((s=strchr(device,' '))) *s='\0'; // open the device fd = deviceopen(device, mode); // if we removed a space, put it back in please if (s) *s=' '; // if we failed to open the device, complain! if (fd < 0) { // For linux+devfs, a nonexistent device gives a strange error // message. This makes the error message a bit more sensible. // If no debug and scanning - don't print errors if (debugmode || !scanning) { if (errno==ENOENT || errno==ENOTDIR) errno=ENODEV; PrintOut(LOG_INFO,"Device: %s, %s, open() failed\n", device, strerror(errno)); } return -1; } // device opened sucessfully return fd;}int CloseDevice(int fd, char *name){ if (deviceclose(fd)){ PrintOut(LOG_INFO,"Device: %s, %s, close(%d) failed\n", name, strerror(errno), fd); return 1; } // device sucessfully closed return 0;}// returns <0 on failureint ATAErrorCount(int fd, char *name){ struct ata_smart_errorlog log; if (-1==ataReadErrorLog(fd,&log)){ PrintOut(LOG_INFO,"Device: %s, Read SMART Error Log Failed\n",name); return -1; } // return current number of ATA errors return log.error_log_pointer?log.ata_error_count:0;}// returns <0 if problem. Otherwise, bottom 8 bits are the self test// error count, and top bits are the power-on hours of the last error.int SelfTestErrorCount(int fd, char *name){ struct ata_smart_selftestlog log; if (-1==ataReadSelfTestLog(fd,&log)){ PrintOut(LOG_INFO,"Device: %s, Read SMART Self Test Log Failed\n",name); return -1; } // return current number of self-test errors return ataPrintSmartSelfTestlog(&log,0);}// scan to see what ata devices there are, and if they support SMARTint ATADeviceScan(cfgfile *cfg, int scanning){ int fd, supported=0; struct ata_identify_device drive; char *name=cfg->name; int retainsmartdata=0; int retid; char *mode; // should we try to register this as an ATA device? switch (cfg->controller_type) { case CONTROLLER_ATA: case CONTROLLER_3WARE_678K: case CONTROLLER_MARVELL_SATA: case CONTROLLER_HPT: case CONTROLLER_UNKNOWN: mode="ATA"; break; case CONTROLLER_3WARE_678K_CHAR: mode="ATA_3WARE_678K"; break; case CONTROLLER_3WARE_9000_CHAR: mode="ATA_3WARE_9000"; break; case CONTROLLER_SAT: mode="SCSI"; break; default: // not a recognized ATA or SATA device. We should never enter // this branch. return 1; } // open the device if ((fd=OpenDevice(name, mode, scanning))<0) // device open failed return 1; PrintOut(LOG_INFO,"Device: %s, opened\n", name); // pass user settings on to low-level ATA commands con->controller_port=cfg->controller_port; con->hpt_data[0]=cfg->hpt_data[0]; con->hpt_data[1]=cfg->hpt_data[1]; con->hpt_data[2]=cfg->hpt_data[2]; con->controller_type=cfg->controller_type; con->controller_explicit=cfg->controller_explicit; con->fixfirmwarebug = cfg->fixfirmwarebug; con->satpassthrulen = cfg->satpassthrulen; // Get drive identity structure if ((retid=ataReadHDIdentity (fd,&drive))){ if (retid<0) // Unable to read Identity structure PrintOut(LOG_INFO,"Device: %s, not ATA, no IDENTIFY DEVICE Structure\n",name); else PrintOut(LOG_INFO,"Device: %s, packet devices [this device %s] not SMART capable\n", name, packetdevicetype(retid-1)); CloseDevice(fd, name); return 2; } // Show if device in database, and use preset vendor attribute // options unless user has requested otherwise. if (cfg->ignorepresets) PrintOut(LOG_INFO, "Device: %s, smartd database not searched (Directive: -P ignore).\n", name); else { // do whatever applypresets decides to do. Will allocate memory if // cfg->attributedefs is needed. if (applypresets(&drive, &cfg->attributedefs, con)<0) PrintOut(LOG_INFO, "Device: %s, not found in smartd database.\n", name); else PrintOut(LOG_INFO, "Device: %s, found in smartd database.\n", name); // then save the correct state of the flag (applypresets may have changed it) cfg->fixfirmwarebug = con->fixfirmwarebug; } // If requested, show which presets would be used for this drive if (cfg->showpresets) { int savedebugmode=debugmode; PrintOut(LOG_INFO, "Device %s: presets are:\n", name); if (!debugmode) debugmode=2; showpresets(&drive); debugmode=savedebugmode; } // see if drive supports SMART supported=ataSmartSupport(&drive); if (supported!=1) { if (supported==0) // drive does NOT support SMART PrintOut(LOG_INFO,"Device: %s, lacks SMART capability\n",name); else // can't tell if drive supports SMART PrintOut(LOG_INFO,"Device: %s, ATA IDENTIFY DEVICE words 82-83 don't specify if SMART capable.\n",name); // should we proceed anyway? if (cfg->permissive){ PrintOut(LOG_INFO,"Device: %s, proceeding since '-T permissive' Directive given.\n",name); } else { PrintOut(LOG_INFO,"Device: %s, to proceed anyway, use '-T permissive' Directive.\n",name); CloseDevice(fd, name); return 2; } } if (ataEnableSmart(fd)){ // Enable SMART command has failed PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name); CloseDevice(fd, name); return 2; } // disable device attribute autosave... if (cfg->autosave==1){ if (ataDisableAutoSave(fd)) PrintOut(LOG_INFO,"Device: %s, could not disable SMART Attribute Autosave.\n",name); else PrintOut(LOG_INFO,"Device: %s, disabled SMART Attribute Autosave.\n",name); } // or enable device attribute autosave if (cfg->autosave==2){ if (ataEnableAutoSave(fd)) PrintOut(LOG_INFO,"Device: %s, could not enable SMART Attribute Autosave.\n",name); else PrintOut(LOG_INFO,"Device: %s, enabled SMART Attribute Autosave.\n",name); } // capability check: SMART status if (cfg->smartcheck && ataSmartStatus2(fd)==-1){ PrintOut(LOG_INFO,"Device: %s, not capable of SMART Health Status check\n",name); cfg->smartcheck=0; } // capability check: Read smart values and thresholds. Note that // smart values are ALSO needed even if we ONLY want to know if the // device is self-test log or error-log capable! After ATA-5, this // information was ALSO reproduced in the IDENTIFY DEVICE response, // but sadly not for ATA-5. Sigh. // do we need to retain SMART data after returning from this routine? retainsmartdata=cfg->usagefailed || cfg->prefail || cfg->usage || cfg->tempdiff || cfg->tempinfo || cfg->tempcrit; // do we need to get SMART data? if (retainsmartdata || cfg->autoofflinetest || cfg->selftest || cfg->errorlog || cfg->pending!=DONT_MONITOR_UNC) { unsigned char currentpending, offlinepending; cfg->smartval=(struct ata_smart_values *)Calloc(1,sizeof(struct ata_smart_values)); cfg->smartthres=(struct ata_smart_thresholds_pvt *)Calloc(1,sizeof(struct ata_smart_thresholds_pvt)); if (!cfg->smartval || !cfg->smartthres){ PrintOut(LOG_CRIT,"Not enough memory to obtain SMART data\n"); EXIT(EXIT_NOMEM); } if (ataReadSmartValues(fd,cfg->smartval) || ataReadSmartThresholds (fd,cfg->smartthres)){ PrintOut(LOG_INFO,"Device: %s, Read SMART Values and/or Thresholds Failed\n",name); retainsmartdata=cfg->usagefailed=cfg->prefail=cfg->usage=0; cfg->tempdiff = cfg->tempinfo = cfg->tempcrit = 0; cfg->pending=DONT_MONITOR_UNC; } // see if the necessary Attribute is there to monitor offline or // current pending sectors or temperature TranslatePending(cfg->pending, ¤tpending, &offlinepending); if (currentpending && ATAReturnAttributeRawValue(currentpending, cfg->smartval)<0) { PrintOut(LOG_INFO,"Device: %s, can't monitor Current Pending Sector count - no Attribute %d\n", name, (int)currentpending); cfg->pending &= 0xff00; cfg->pending |= CUR_UNC_DEFAULT; } if (offlinepending && ATAReturnAttributeRawValue(offlinepending, cfg->smartval)<0) { PrintOut(LOG_INFO,"Device: %s, can't monitor Offline Uncorrectable Sector count - no Attribute %d\n", name, (int)offlinepending); cfg->pending &= 0x00ff; cfg->pending |= OFF_UNC_DEFAULT<<8; } if ( (cfg->tempdiff || cfg->tempinfo || cfg->tempcrit) && !ATAReturnTemperatureValue(cfg->smartval, cfg->attributedefs)) { PrintOut(LOG_CRIT, "Device: %s, can't monitor Temperature, ignoring -W Directive\n", name); cfg->tempdiff = cfg->tempinfo = cfg->tempcrit = 0; } } // enable/disable automatic on-line testing if (cfg->autoofflinetest){ // is this an enable or disable request? const char *what=(cfg->autoofflinetest==1)?"disable":"enable"; if (!cfg->smartval) PrintOut(LOG_INFO,"Device: %s, could not %s SMART Automatic Offline Testing.\n",name, what); else { // if command appears unsupported, issue a warning... if (!isSupportAutomaticTimer(cfg->smartval)) PrintOut(LOG_INFO,"Device: %s, SMART Automatic Offline Testing unsupported...\n",name); // ... but then try anyway if ((cfg->autoofflinetest==1)?ataDisableAutoOffline(fd):ataEnableAutoOffline(fd)) PrintOut(LOG_INFO,"Device: %s, %s SMART Automatic Offline Testing failed.\n", name, what); else PrintOut(LOG_INFO,"Device: %s, %sd SMART Automatic Offline Testing.\n", name, what); } } // capability check: self-test-log if (cfg->selftest){ int retval; // start with service disabled, and re-enable it if all works OK cfg->selftest=0; cfg->selflogcount=0; cfg->selfloghour=0; if (!cfg->smartval) PrintOut(LOG_INFO, "Device: %s, no SMART Self-Test log (SMART READ DATA failed); disabling -l selftest\n", name); else if (!cfg->permissive && !isSmartTestLogCapable(cfg->smartval, &drive)) PrintOut(LOG_INFO, "Device: %s, appears to lack SMART Self-Test log; disabling -l selftest (override with -T permissive Directive)\n", name); else if ((retval=SelfTestErrorCount(fd, name))<0) PrintOut(LOG_INFO, "Device: %s, no SMART Self-Test log; remove -l selftest Directive from smartd.conf\n", name); else { cfg->selftest=1; cfg->selflogcount=SELFTEST_ERRORCOUNT(retval); cfg->selfloghour =SELFTEST_ERRORHOURS(retval); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -