📄 smartd.cpp
字号:
/* * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-8 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/ * */#ifndef _GNU_SOURCE#define _GNU_SOURCE#endif// unconditionally included files#include <stdio.h>#include <sys/types.h>#include <sys/stat.h> // umask#ifndef _WIN32#include <sys/wait.h>#include <unistd.h>#endif#include <signal.h>#include <fcntl.h>#include <string.h>#include <syslog.h>#include <stdarg.h>#include <stdlib.h>#include <errno.h>#include <time.h>#include <limits.h>#if SCSITIMEOUT#include <setjmp.h>#endif// see which system files to conditionally include#include "config.h"// conditionally included files#ifdef HAVE_GETOPT_LONG#include <getopt.h>#endif#ifdef HAVE_NETDB_H#include <netdb.h>#endif#ifdef _WIN32#ifdef _MSC_VER#pragma warning(disable:4761) // "conversion supplied"typedef unsigned short mode_t;typedef int pid_t;#endif#include <io.h> // umask()#include <process.h> // getpid()#endif // _WIN32#ifdef __CYGWIN__// From <windows.h>:// BOOL WINAPI FreeConsole(void);extern "C" int __stdcall FreeConsole(void);#include <io.h> // setmode()#endif // __CYGWIN__// locally included files#include "int64.h"#include "atacmds.h"#include "ataprint.h"#include "extern.h"#include "knowndrives.h"#include "scsicmds.h"#include "scsiata.h"#include "smartd.h"#include "utility.h"#ifdef _WIN32#include "hostname_win32.h" // gethost/domainname()#define HAVE_GETHOSTNAME 1#define HAVE_GETDOMAINNAME 1// fork()/signal()/initd simulation for native Windows#include "daemon_win32.h" // daemon_main/detach/signal()#undef SIGNALFN#define SIGNALFN daemon_signal#define strsignal daemon_strsignal#define sleep daemon_sleep#undef EXIT // see utility.h#define EXIT(x) { exitstatus = daemon_winsvc_exitcode = (x); exit((x)); }// SIGQUIT does not exits, CONTROL-Break signals SIGBREAK.#define SIGQUIT SIGBREAK#define SIGQUIT_KEYNAME "CONTROL-Break"#else // _WIN32#ifdef __CYGWIN__// 2x CONTROL-C simulates missing SIGQUIT via keyboard#define SIGQUIT_KEYNAME "2x CONTROL-C"#else // __CYGWIN__#define SIGQUIT_KEYNAME "CONTROL-\\"#endif // __CYGWIN__#endif // _WIN32#if defined (__SVR4) && defined (__sun)extern "C" int getdomainname(char *, int); // no declaration in header files!#endif#define ARGUSED(x) ((void)(x))// These are CVS identification information for *.cpp and *.h filesextern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *escalade_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *utility_c_cvsid;static const char *filenameandversion="$Id: smartd.cpp,v 1.397 2008/03/04 22:09:47 ballen4705 Exp $";#ifdef NEED_SOLARIS_ATA_CODEextern const char *os_solaris_ata_s_cvsid;#endif#ifdef _WIN32extern const char *daemon_win32_c_cvsid, *hostname_win32_c_cvsid, *syslog_win32_c_cvsid;#endifconst char *smartd_c_cvsid="$Id: smartd.cpp,v 1.397 2008/03/04 22:09:47 ballen4705 Exp $" ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID#ifdef DAEMON_WIN32_H_CVSIDDAEMON_WIN32_H_CVSID#endifEXTERN_H_CVSID INT64_H_CVSID#ifdef HOSTNAME_WIN32_H_CVSIDHOSTNAME_WIN32_H_CVSID#endifKNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SMARTD_H_CVSID#ifdef SYSLOG_H_CVSIDSYSLOG_H_CVSID#endifUTILITY_H_CVSID;extern const char *reportbug;// GNU copyleft statement. Needed for GPL purposes.const char *copyleftstring="smartd comes with ABSOLUTELY NO WARRANTY. This is\n" "free software, and you are welcome to redistribute it\n" "under the terms of the GNU General Public License\n" "Version 2. See http://www.gnu.org for further details.\n\n";extern unsigned char debugmode;// command-line: how long to sleep between checksstatic int checktime=CHECKTIME;// command-line: name of PID file (NULL for no pid file)static char* pid_file=NULL;// configuration file name#ifndef _WIN32static char* configfile = SMARTMONTOOLS_SYSCONFDIR "/" CONFIGFILENAME ;#elsestatic char* configfile = "./" CONFIGFILENAME ;#endif// configuration file "name" if read from stdinstatic /*const*/ char * const configfile_stdin = "<stdin>";// allocated memory for alternate configuration file namestatic char* configfile_alt = NULL;// command-line: when should we exit?static int quit=0;// command-line; this is the default syslog(3) log facility to use.static int facility=LOG_DAEMON;#ifndef _WIN32// command-line: fork into background?static bool do_fork=true;#endif// used for control of printing, passing arguments to atacmds.csmartmonctrl *con=NULL;// pointers to (real or simulated) entries in configuration file, and// maximum space currently allocated for these entries.cfgfile **cfgentries=NULL;int cfgentries_max=0;// pointers to ATA and SCSI devices being monitored, maximum and// actual numberscfgfile **ATAandSCSIdevlist=NULL;int ATAandSCSIdevlist_max=0;int numdevata=0, numdevscsi=0;// track memory usageextern int64_t bytes;// exit statusextern int exitstatus;// set to one if we catch a USR1 (check devices now)volatile int caughtsigUSR1=0;#ifdef _WIN32// set to one if we catch a USR2 (toggle debug mode)volatile int caughtsigUSR2=0;#endif// set to one if we catch a HUP (reload config file). In debug mode,// set to two, if we catch INT (also reload config file).volatile int caughtsigHUP=0;// set to signal value if we catch INT, QUIT, or TERMvolatile int caughtsigEXIT=0;#if SCSITIMEOUT// stack environment if we time out during SCSI access (USB devices)jmp_buf registerscsienv;#endif// tranlate cfg->pending into the correct Attribute numbersvoid TranslatePending(unsigned short pending, unsigned char *current, unsigned char *offline) { unsigned char curr = CURR_PEND(pending); unsigned char off = OFF_PEND(pending); // look for special value of CUR_UNC_DEFAULT that means DONT // monitor. 0 means DO test. if (curr==CUR_UNC_DEFAULT) curr=0; else if (curr==0) curr=CUR_UNC_DEFAULT; // look for special value of OFF_UNC_DEFAULT that means DONT // monitor. 0 means DO TEST. if (off==OFF_UNC_DEFAULT) off=0; else if (off==0) off=OFF_UNC_DEFAULT; *current=curr; *offline=off; return;}// free all memory associated with selftest part of configfile entry. Return NULLtestinfo* FreeTestData(testinfo *data){ // make sure we have something to do. if (!data) return NULL; // free space for text pattern data->regex=FreeNonZero(data->regex, -1, __LINE__, filenameandversion); // free compiled expression regfree(&(data->cregex)); // make sure that no sign of the compiled expression is left behind // (just in case, to help detect bugs if we ever try and refer to // that again). memset(&(data->cregex), '0', sizeof(regex_t)); // free remaining memory space data=FreeNonZero(data, sizeof(testinfo), __LINE__, filenameandversion); return NULL;}cfgfile **AllocateMoreSpace(cfgfile **oldarray, int *oldsize, char *listname){ // for now keep BLOCKSIZE small to help detect coding problems. // Perhaps increase in the future. const int BLOCKSIZE=8; int i; int olds = *oldsize; int news = olds + BLOCKSIZE; cfgfile **newptr=(cfgfile **)realloc(oldarray, news*sizeof(cfgfile *)); // did we get more space? if (newptr) { // clear remaining entries ala calloc() for (i=olds; i<news; i++) newptr[i]=NULL; bytes += BLOCKSIZE*sizeof(cfgfile *); *oldsize=news; #if 0 PrintOut(LOG_INFO, "allocating %d slots for %s\n", BLOCKSIZE, listname);#endif return newptr; } PrintOut(LOG_CRIT, "out of memory for allocating %s list\n", listname); EXIT(EXIT_NOMEM);}void PrintOneCVS(const char *a_cvs_id){ char out[CVSMAXLEN]; printone(out,a_cvs_id); PrintOut(LOG_INFO,"%s",out); return;}// prints CVS identity information for the executablevoid PrintCVS(void){ const char *configargs=strlen(SMARTMONTOOLS_CONFIGURE_ARGS)?SMARTMONTOOLS_CONFIGURE_ARGS:"[no arguments given]"; PrintOut(LOG_INFO,(char *)copyleftstring); PrintOut(LOG_INFO,"CVS version IDs of files used to build this code are:\n"); PrintOneCVS(atacmdnames_c_cvsid); PrintOneCVS(atacmds_c_cvsid); PrintOneCVS(ataprint_c_cvsid);#ifdef _WIN32 PrintOneCVS(daemon_win32_c_cvsid);#endif#ifdef _WIN32 PrintOneCVS(hostname_win32_c_cvsid);#endif PrintOneCVS(knowndrives_c_cvsid); PrintOneCVS(os_XXXX_c_cvsid);#ifdef NEED_SOLARIS_ATA_CODE PrintOneCVS( os_solaris_ata_s_cvsid);#endif PrintOneCVS(scsicmds_c_cvsid); PrintOneCVS(smartd_c_cvsid);#ifdef _WIN32 PrintOneCVS(syslog_win32_c_cvsid);#endif PrintOneCVS(utility_c_cvsid); PrintOut(LOG_INFO, "\nsmartmontools release " PACKAGE_VERSION " dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n"); PrintOut(LOG_INFO, "smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n"); PrintOut(LOG_INFO, "smartmontools build configured: " SMARTMONTOOLS_CONFIGURE_DATE "\n"); PrintOut(LOG_INFO, "smartd compile dated " __DATE__ " at "__TIME__ "\n"); PrintOut(LOG_INFO, "smartmontools configure arguments: %s\n", configargs); return;}// Removes config file entry, freeing all memoryvoid RmConfigEntry(cfgfile **anentry, int whatline){ cfgfile *cfg; // pointer should never be null! if (!anentry){ PrintOut(LOG_CRIT,"Internal error in RmConfigEntry() at line %d of file %s\n%s", whatline, filenameandversion, reportbug); EXIT(EXIT_BADCODE); } // only remove entries that exist! if (!(cfg=*anentry)) return; // entry exists -- free all of its memory cfg->name = FreeNonZero(cfg->name, -1,__LINE__,filenameandversion); cfg->smartthres = FreeNonZero(cfg->smartthres, sizeof(struct ata_smart_thresholds_pvt),__LINE__,filenameandversion); cfg->smartval = FreeNonZero(cfg->smartval, sizeof(struct ata_smart_values),__LINE__,filenameandversion); cfg->monitorattflags = FreeNonZero(cfg->monitorattflags, NMONITOR*32,__LINE__,filenameandversion); cfg->attributedefs = FreeNonZero(cfg->attributedefs, MAX_ATTRIBUTE_NUM,__LINE__,filenameandversion); if (cfg->mailwarn){ cfg->mailwarn->address = FreeNonZero(cfg->mailwarn->address, -1,__LINE__,filenameandversion); cfg->mailwarn->emailcmdline = FreeNonZero(cfg->mailwarn->emailcmdline, -1,__LINE__,filenameandversion); cfg->mailwarn = FreeNonZero(cfg->mailwarn, sizeof(maildata),__LINE__,filenameandversion); } cfg->testdata = FreeTestData(cfg->testdata); *anentry = FreeNonZero(cfg, sizeof(cfgfile),__LINE__,filenameandversion); return;}// deallocates all memory associated with cfgentries listvoid RmAllConfigEntries(){ int i; for (i=0; i<cfgentries_max; i++) RmConfigEntry(cfgentries+i, __LINE__); cfgentries=FreeNonZero(cfgentries, sizeof(cfgfile *)*cfgentries_max, __LINE__, filenameandversion); cfgentries_max=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -