root/trunk/smartmontools/smartd.cpp @ 3681

Revision 3681, 174.0 KB (checked in by samm2, 6 months ago)

smartd.cpp: add S/N to SCSI device identifier, lu_id is N/A on some drives

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * Home page of code is: http://smartmontools.sourceforge.net
3 *
4 * Copyright (C) 2002-11 Bruce Allen <smartmontools-support@lists.sourceforge.net>
5 * Copyright (C) 2000    Michael Cornwell <cornwell@acm.org>
6 * Copyright (C) 2008    Oliver Bock <brevilo@users.sourceforge.net>
7 * Copyright (C) 2008-12 Christian Franke <smartmontools-support@lists.sourceforge.net>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * You should have received a copy of the GNU General Public License
15 * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
16 *
17 * This code was originally developed as a Senior Thesis by Michael Cornwell
18 * at the Concurrent Systems Laboratory (now part of the Storage Systems
19 * Research Center), Jack Baskin School of Engineering, University of
20 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
21 *
22 */
23
24#ifndef _GNU_SOURCE
25// TODO: Why is this define necessary?
26#define _GNU_SOURCE
27#endif
28
29// unconditionally included files
30#include <stdio.h>
31#include <sys/types.h>
32#include <sys/stat.h>   // umask
33#include <signal.h>
34#include <fcntl.h>
35#include <string.h>
36#include <syslog.h>
37#include <stdarg.h>
38#include <stdlib.h>
39#include <errno.h>
40#include <time.h>
41#include <limits.h>
42#include <getopt.h>
43
44#include <stdexcept>
45#include <string>
46#include <vector>
47#include <algorithm> // std::replace()
48
49// see which system files to conditionally include
50#include "config.h"
51
52// conditionally included files
53#ifndef _WIN32
54#include <sys/wait.h>
55#endif
56#ifdef HAVE_UNISTD_H
57#include <unistd.h>
58#endif
59#ifdef HAVE_NETDB_H
60#include <netdb.h>
61#endif
62
63#ifdef _WIN32
64#ifdef _MSC_VER
65#pragma warning(disable:4761) // "conversion supplied"
66typedef unsigned short mode_t;
67typedef int pid_t;
68#endif
69#include <io.h> // umask()
70#include <process.h> // getpid()
71#endif // _WIN32
72
73#ifdef __CYGWIN__
74#include <io.h> // setmode()
75#endif // __CYGWIN__
76
77#ifdef HAVE_LIBCAP_NG
78#include <cap-ng.h>
79#endif // LIBCAP_NG
80
81// locally included files
82#include "int64.h"
83#include "atacmds.h"
84#include "dev_interface.h"
85#include "knowndrives.h"
86#include "scsicmds.h"
87#include "utility.h"
88
89// This is for solaris, where signal() resets the handler to SIG_DFL
90// after the first signal is caught.
91#ifdef HAVE_SIGSET
92#define SIGNALFN sigset
93#else
94#define SIGNALFN signal
95#endif
96
97#ifdef _WIN32
98#include <winsock2.h>  // ws2_32.dll
99// AC_SEARCH_LIBS and AC_CHECK_FUNCS do not work due to DLL linkage
100#define HAVE_GETHOSTNAME   1
101#define HAVE_GETHOSTBYNAME 1
102// fork()/signal()/initd simulation for native Windows
103#include "daemon_win32.h" // daemon_main/detach/signal()
104#include "wtssendmsg.h" // wts_send_message()
105#undef SIGNALFN
106#define SIGNALFN  daemon_signal
107#define strsignal daemon_strsignal
108#define sleep     daemon_sleep
109// SIGQUIT does not exist, CONTROL-Break signals SIGBREAK.
110#define SIGQUIT SIGBREAK
111#define SIGQUIT_KEYNAME "CONTROL-Break"
112#else  // _WIN32
113#define SIGQUIT_KEYNAME "CONTROL-\\"
114#endif // _WIN32
115
116#if defined (__SVR4) && defined (__sun)
117extern "C" int getdomainname(char *, int); // no declaration in header files!
118#endif
119
120const char * smartd_cpp_cvsid = "$Id$"
121  CONFIG_H_CVSID;
122
123// smartd exit codes
124#define EXIT_BADCMD    1   // command line did not parse
125#define EXIT_BADCONF   2   // syntax error in config file
126#define EXIT_STARTUP   3   // problem forking daemon
127#define EXIT_PID       4   // problem creating pid file
128#define EXIT_NOCONF    5   // config file does not exist
129#define EXIT_READCONF  6   // config file exists but cannot be read
130
131#define EXIT_NOMEM     8   // out of memory
132#define EXIT_BADCODE   10  // internal error - should NEVER happen
133
134#define EXIT_BADDEV    16  // we can't monitor this device
135#define EXIT_NODEV     17  // no devices to monitor
136
137#define EXIT_SIGNAL    254 // abort on signal
138
139
140// command-line: 1=debug mode, 2=print presets
141static unsigned char debugmode = 0;
142
143// command-line: how long to sleep between checks
144#define CHECKTIME 1800
145static int checktime=CHECKTIME;
146
147// command-line: name of PID file (empty for no pid file)
148static std::string pid_file;
149
150// command-line: path prefix of persistent state file, empty if no persistence.
151static std::string state_path_prefix
152#ifdef SMARTMONTOOLS_SAVESTATES
153          = SMARTMONTOOLS_SAVESTATES
154#endif
155                                    ;
156
157// command-line: path prefix of attribute log file, empty if no logs.
158static std::string attrlog_path_prefix
159#ifdef SMARTMONTOOLS_ATTRIBUTELOG
160          = SMARTMONTOOLS_ATTRIBUTELOG
161#endif
162                                    ;
163
164// configuration file name
165static const char * configfile;
166// configuration file "name" if read from stdin
167static const char * const configfile_stdin = "<stdin>";
168// path of alternate configuration file
169static std::string configfile_alt;
170
171// command-line: when should we exit?
172static int quit=0;
173
174// command-line; this is the default syslog(3) log facility to use.
175static int facility=LOG_DAEMON;
176
177#ifndef _WIN32
178// command-line: fork into background?
179static bool do_fork=true;
180#endif
181
182#ifdef HAVE_LIBCAP_NG
183// command-line: enable capabilities?
184static bool enable_capabilities = false;
185#endif
186
187#if defined(_WIN32) || defined(__CYGWIN__)
188// TODO: This smartctl only variable is also used in os_win32.cpp
189unsigned char failuretest_permissive = 0;
190#endif
191
192// set to one if we catch a USR1 (check devices now)
193static volatile int caughtsigUSR1=0;
194
195#ifdef _WIN32
196// set to one if we catch a USR2 (toggle debug mode)
197static volatile int caughtsigUSR2=0;
198#endif
199
200// set to one if we catch a HUP (reload config file). In debug mode,
201// set to two, if we catch INT (also reload config file).
202static volatile int caughtsigHUP=0;
203
204// set to signal value if we catch INT, QUIT, or TERM
205static volatile int caughtsigEXIT=0;
206
207// This function prints either to stdout or to the syslog as needed.
208static void PrintOut(int priority, const char *fmt, ...)
209                     __attribute_format_printf(2, 3);
210
211// Attribute monitoring flags.
212// See monitor_attr_flags below.
213enum {
214  MONITOR_IGN_FAILUSE = 0x01,
215  MONITOR_IGNORE      = 0x02,
216  MONITOR_RAW_PRINT   = 0x04,
217  MONITOR_RAW         = 0x08,
218  MONITOR_AS_CRIT     = 0x10,
219  MONITOR_RAW_AS_CRIT = 0x20,
220};
221
222// Array of flags for each attribute.
223class attribute_flags
224{
225public:
226  attribute_flags()
227    { memset(m_flags, 0, sizeof(m_flags)); }
228
229  bool is_set(int id, unsigned char flag) const
230    { return (0 < id && id < (int)sizeof(m_flags) && (m_flags[id] & flag)); }
231
232  void set(int id, unsigned char flags)
233    {
234      if (0 < id && id < (int)sizeof(m_flags))
235        m_flags[id] |= flags;
236    }
237
238private:
239  unsigned char m_flags[256];
240};
241
242
243/// Configuration data for a device. Read from smartd.conf.
244/// Supports copy & assignment and is compatible with STL containers.
245struct dev_config
246{
247  int lineno;                             // Line number of entry in file
248  std::string name;                       // Device name (with optional extra info)
249  std::string dev_name;                   // Device name (plain, for SMARTD_DEVICE variable)
250  std::string dev_type;                   // Device type argument from -d directive, empty if none
251  std::string dev_idinfo;                 // Device identify info for warning emails
252  std::string state_file;                 // Path of the persistent state file, empty if none
253  std::string attrlog_file;               // Path of the persistent attrlog file, empty if none
254  bool smartcheck;                        // Check SMART status
255  bool usagefailed;                       // Check for failed Usage Attributes
256  bool prefail;                           // Track changes in Prefail Attributes
257  bool usage;                             // Track changes in Usage Attributes
258  bool selftest;                          // Monitor number of selftest errors
259  bool errorlog;                          // Monitor number of ATA errors
260  bool xerrorlog;                         // Monitor number of ATA errors (Extended Comprehensive error log)
261  bool offlinests;                        // Monitor changes in offline data collection status
262  bool offlinests_ns;                     // Disable auto standby if in progress
263  bool selfteststs;                       // Monitor changes in self-test execution status
264  bool selfteststs_ns;                    // Disable auto standby if in progress
265  bool permissive;                        // Ignore failed SMART commands
266  char autosave;                          // 1=disable, 2=enable Autosave Attributes
267  char autoofflinetest;                   // 1=disable, 2=enable Auto Offline Test
268  firmwarebug_defs firmwarebugs;          // -F directives from drivedb or smartd.conf
269  bool ignorepresets;                     // Ignore database of -v options
270  bool showpresets;                       // Show database entry for this device
271  bool removable;                         // Device may disappear (not be present)
272  char powermode;                         // skip check, if disk in idle or standby mode
273  bool powerquiet;                        // skip powermode 'skipping checks' message
274  int powerskipmax;                       // how many times can be check skipped
275  unsigned char tempdiff;                 // Track Temperature changes >= this limit
276  unsigned char tempinfo, tempcrit;       // Track Temperatures >= these limits as LOG_INFO, LOG_CRIT+mail
277  regular_expression test_regex;          // Regex for scheduled testing
278
279  // Configuration of email warning messages
280  std::string emailcmdline;               // script to execute, empty if no messages
281  std::string emailaddress;               // email address, or empty
282  unsigned char emailfreq;                // Emails once (1) daily (2) diminishing (3)
283  bool emailtest;                         // Send test email?
284
285  // ATA ONLY
286  int dev_rpm; // rotation rate, 0 = unknown, 1 = SSD, >1 = HDD
287  int set_aam; // disable(-1), enable(1..255->0..254) Automatic Acoustic Management
288  int set_apm; // disable(-1), enable(2..255->1..254) Advanced Power Management
289  int set_lookahead; // disable(-1), enable(1) read look-ahead
290  int set_standby; // set(1..255->0..254) standby timer
291  bool set_security_freeze; // Freeze ATA security
292  int set_wcache; // disable(-1), enable(1) write cache
293
294  bool sct_erc_set;                       // set SCT ERC to:
295  unsigned short sct_erc_readtime;        // ERC read time (deciseconds)
296  unsigned short sct_erc_writetime;       // ERC write time (deciseconds)
297
298  unsigned char curr_pending_id;          // ID of current pending sector count, 0 if none
299  unsigned char offl_pending_id;          // ID of offline uncorrectable sector count, 0 if none
300  bool curr_pending_incr, offl_pending_incr; // True if current/offline pending values increase
301  bool curr_pending_set,  offl_pending_set;  // True if '-C', '-U' set in smartd.conf
302
303  attribute_flags monitor_attr_flags;     // MONITOR_* flags for each attribute
304
305  ata_vendor_attr_defs attribute_defs;    // -v options
306
307  dev_config();
308};
309
310dev_config::dev_config()
311: lineno(0),
312  smartcheck(false),
313  usagefailed(false),
314  prefail(false),
315  usage(false),
316  selftest(false),
317  errorlog(false),
318  xerrorlog(false),
319  offlinests(false),  offlinests_ns(false),
320  selfteststs(false), selfteststs_ns(false),
321  permissive(false),
322  autosave(0),
323  autoofflinetest(0),
324  ignorepresets(false),
325  showpresets(false),
326  removable(false),
327  powermode(0),
328  powerquiet(false),
329  powerskipmax(0),
330  tempdiff(0),
331  tempinfo(0), tempcrit(0),
332  emailfreq(0),
333  emailtest(false),
334  dev_rpm(0),
335  set_aam(0), set_apm(0),
336  set_lookahead(0),
337  set_standby(0),
338  set_security_freeze(false),
339  set_wcache(0),
340  sct_erc_set(false),
341  sct_erc_readtime(0), sct_erc_writetime(0),
342  curr_pending_id(0), offl_pending_id(0),
343  curr_pending_incr(false), offl_pending_incr(false),
344  curr_pending_set(false),  offl_pending_set(false)
345{
346}
347
348
349// Number of allowed mail message types
350static const int SMARTD_NMAIL = 13;
351// Type for '-M test' mails (state not persistent)
352static const int MAILTYPE_TEST = 0;
353// TODO: Add const or enum for all mail types.
354
355struct mailinfo {
356  int logged;// number of times an email has been sent
357  time_t firstsent;// time first email was sent, as defined by time(2)
358  time_t lastsent; // time last email was sent, as defined by time(2)
359
360  mailinfo()
361    : logged(0), firstsent(0), lastsent(0) { }
362};
363
364/// Persistent state data for a device.
365struct persistent_dev_state
366{
367  unsigned char tempmin, tempmax;         // Min/Max Temperatures
368
369  unsigned char selflogcount;             // total number of self-test errors
370  unsigned short selfloghour;             // lifetime hours of last self-test error
371
372  time_t scheduled_test_next_check;       // Time of next check for scheduled self-tests
373
374  uint64_t selective_test_last_start;     // Start LBA of last scheduled selective self-test
375  uint64_t selective_test_last_end;       // End LBA of last scheduled selective self-test
376
377  mailinfo maillog[SMARTD_NMAIL];         // log info on when mail sent
378
379  // ATA ONLY
380  int ataerrorcount;                      // Total number of ATA errors
381
382  // Persistent part of ata_smart_values:
383  struct ata_attribute {
384    unsigned char id;
385    unsigned char val;
386    unsigned char worst; // Byte needed for 'raw64' attribute only.
387    uint64_t raw;
388    unsigned char resvd;
389
390    ata_attribute() : id(0), val(0), worst(0), raw(0), resvd(0) { }
391  };
392  ata_attribute ata_attributes[NUMBER_ATA_SMART_ATTRIBUTES];
393
394  persistent_dev_state();
395};
396
397persistent_dev_state::persistent_dev_state()
398: tempmin(0), tempmax(0),
399  selflogcount(0),
400  selfloghour(0),
401  scheduled_test_next_check(0),
402  selective_test_last_start(0),
403  selective_test_last_end(0),
404  ataerrorcount(0)
405{
406}
407
408/// Non-persistent state data for a device.
409struct temp_dev_state
410{
411  bool must_write;                        // true if persistent part should be written
412
413  bool not_cap_offline;                   // true == not capable of offline testing
414  bool not_cap_conveyance;
415  bool not_cap_short;
416  bool not_cap_long;
417  bool not_cap_selective;
418
419  unsigned char temperature;              // last recorded Temperature (in Celsius)
420  time_t tempmin_delay;                   // time where Min Temperature tracking will start
421
422  bool powermodefail;                     // true if power mode check failed
423  int powerskipcnt;                       // Number of checks skipped due to idle or standby mode
424
425  // SCSI ONLY
426  unsigned char SmartPageSupported;       // has log sense IE page (0x2f)
427  unsigned char TempPageSupported;        // has log sense temperature page (0xd)
428  unsigned char SuppressReport;           // minimize nuisance reports
429  unsigned char modese_len;               // mode sense/select cmd len: 0 (don't
430                                          // know yet) 6 or 10
431
432  // ATA ONLY
433  uint64_t num_sectors;                   // Number of sectors
434  ata_smart_values smartval;              // SMART data
435  ata_smart_thresholds_pvt smartthres;    // SMART thresholds
436  bool offline_started;                   // true if offline data collection was started
437  bool selftest_started;                  // true if self-test was started
438
439  temp_dev_state();
440};
441
442temp_dev_state::temp_dev_state()
443: must_write(false),
444  not_cap_offline(false),
445  not_cap_conveyance(false),
446  not_cap_short(false),
447  not_cap_long(false),
448  not_cap_selective(false),
449  temperature(0),
450  tempmin_delay(0),
451  powermodefail(false),
452  powerskipcnt(0),
453  SmartPageSupported(false),
454  TempPageSupported(false),
455  SuppressReport(false),
456  modese_len(0),
457  num_sectors(0),
458  offline_started(false),
459  selftest_started(false)
460{
461  memset(&smartval, 0, sizeof(smartval));
462  memset(&smartthres, 0, sizeof(smartthres));
463}
464
465/// Runtime state data for a device.
466struct dev_state
467: public persistent_dev_state,
468  public temp_dev_state
469{
470  void update_persistent_state();
471  void update_temp_state();
472};
473
474/// Container for configuration info for each device.
475typedef std::vector<dev_config> dev_config_vector;
476
477/// Container for state info for each device.
478typedef std::vector<dev_state> dev_state_vector;
479
480// Copy ATA attributes to persistent state.
481void dev_state::update_persistent_state()
482{
483  for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
484    const ata_smart_attribute & ta = smartval.vendor_attributes[i];
485    ata_attribute & pa = ata_attributes[i];
486    pa.id = ta.id;
487    if (ta.id == 0) {
488      pa.val = pa.worst = 0; pa.raw = 0;
489      continue;
490    }
491    pa.val = ta.current;
492    pa.worst = ta.worst;
493    pa.raw =            ta.raw[0]
494           | (          ta.raw[1] <<  8)
495           | (          ta.raw[2] << 16)
496           | ((uint64_t)ta.raw[3] << 24)
497           | ((uint64_t)ta.raw[4] << 32)
498           | ((uint64_t)ta.raw[5] << 40);
499    pa.resvd = ta.reserv;
500  }
501}
502
503// Copy ATA from persistent to temp state.
504void dev_state::update_temp_state()
505{
506  for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
507    const ata_attribute & pa = ata_attributes[i];
508    ata_smart_attribute & ta = smartval.vendor_attributes[i];
509    ta.id = pa.id;
510    if (pa.id == 0) {
511      ta.current = ta.worst = 0;
512      memset(ta.raw, 0, sizeof(ta.raw));
513      continue;
514    }
515    ta.current = pa.val;
516    ta.worst = pa.worst;
517    ta.raw[0] = (unsigned char) pa.raw;
518    ta.raw[1] = (unsigned char)(pa.raw >>  8);
519    ta.raw[2] = (unsigned char)(pa.raw >> 16);
520    ta.raw[3] = (unsigned char)(pa.raw >> 24);
521    ta.raw[4] = (unsigned char)(pa.raw >> 32);
522    ta.raw[5] = (unsigned char)(pa.raw >> 40);
523    ta.reserv = pa.resvd;
524  }
525}
526
527// Parse a line from a state file.
528static bool parse_dev_state_line(const char * line, persistent_dev_state & state)
529{
530  static const regular_expression regex(
531    "^ *"
532     "((temperature-min)" // (1 (2)
533     "|(temperature-max)" // (3)
534     "|(self-test-errors)" // (4)
535     "|(self-test-last-err-hour)" // (5)
536     "|(scheduled-test-next-check)" // (6)
537     "|(selective-test-last-start)" // (7)
538     "|(selective-test-last-end)" // (8)
539     "|(ata-error-count)"  // (9)
540     "|(mail\\.([0-9]+)\\." // (10 (11)
541       "((count)" // (12 (13)
542       "|(first-sent-time)" // (14)
543       "|(last-sent-time)" // (15)
544       ")" // 12)
545      ")" // 10)
546     "|(ata-smart-attribute\\.([0-9]+)\\." // (16 (17)
547       "((id)" // (18 (19)
548       "|(val)" // (20)
549       "|(worst)" // (21)
550       "|(raw)" // (22)
551       "|(resvd)" // (23)
552       ")" // 18)
553      ")" // 16)
554     ")" // 1)
555     " *= *([0-9]+)[ \n]*$", // (24)
556    REG_EXTENDED
557  );
558
559  const int nmatch = 1+24;
560  regmatch_t match[nmatch];
561  if (!regex.execute(line, nmatch, match))
562    return false;
563  if (match[nmatch-1].rm_so < 0)
564    return false;
565
566  uint64_t val = strtoull(line + match[nmatch-1].rm_so, (char **)0, 10);
567
568  int m = 1;
569  if (match[++m].rm_so >= 0)
570    state.tempmin = (unsigned char)val;
571  else if (match[++m].rm_so >= 0)
572    state.tempmax = (unsigned char)val;
573  else if (match[++m].rm_so >= 0)
574    state.selflogcount = (unsigned char)val;
575  else if (match[++m].rm_so >= 0)
576    state.selfloghour = (unsigned short)val;
577  else if (match[++m].rm_so >= 0)
578    state.scheduled_test_next_check = (time_t)val;
579  else if (match[++m].rm_so >= 0)
580    state.selective_test_last_start = val;
581  else if (match[++m].rm_so >= 0)
582    state.selective_test_last_end = val;
583  else if (match[++m].rm_so >= 0)
584    state.ataerrorcount = (int)val;
585  else if (match[m+=2].rm_so >= 0) {
586    int i = atoi(line+match[m].rm_so);
587    if (!(0 <= i && i < SMARTD_NMAIL))
588      return false;
589    if (i == MAILTYPE_TEST) // Don't suppress test mails
590      return true;
591    if (match[m+=2].rm_so >= 0)
592      state.maillog[i].logged = (int)val;
593    else if (match[++m].rm_so >= 0)
594      state.maillog[i].firstsent = (time_t)val;
595    else if (match[++m].rm_so >= 0)
596      state.maillog[i].lastsent = (time_t)val;
597    else
598      return false;
599  }
600  else if (match[m+=5+1].rm_so >= 0) {
601    int i = atoi(line+match[m].rm_so);
602    if (!(0 <= i && i < NUMBER_ATA_SMART_ATTRIBUTES))
603      return false;
604    if (match[m+=2].rm_so >= 0)
605      state.ata_attributes[i].id = (unsigned char)val;
606    else if (match[++m].rm_so >= 0)
607      state.ata_attributes[i].val = (unsigned char)val;
608    else if (match[++m].rm_so >= 0)
609      state.ata_attributes[i].worst = (unsigned char)val;
610    else if (match[++m].rm_so >= 0)
611      state.ata_attributes[i].raw = val;
612    else if (match[++m].rm_so >= 0)
613      state.ata_attributes[i].resvd = (unsigned char)val;
614    else
615      return false;
616  }
617  else
618    return false;
619  return true;
620}
621
622// Read a state file.
623static bool read_dev_state(const char * path, persistent_dev_state & state)
624{
625  stdio_file f(path, "r");
626  if (!f) {
627    if (errno != ENOENT)
628      pout("Cannot read state file \"%s\"\n", path);
629    return false;
630  }
631#ifdef __CYGWIN__
632  setmode(fileno(f), O_TEXT); // Allow files with \r\n
633#endif
634
635  persistent_dev_state new_state;
636  int good = 0, bad = 0;
637  char line[256];
638  while (fgets(line, sizeof(line), f)) {
639    const char * s = line + strspn(line, " \t");
640    if (!*s || *s == '#')
641      continue;
642    if (!parse_dev_state_line(line, new_state))
643      bad++;
644    else
645      good++;
646  }
647
648  if (bad) {
649    if (!good) {
650      pout("%s: format error\n", path);
651      return false;
652    }
653    pout("%s: %d invalid line(s) ignored\n", path, bad);
654  }
655
656  // This sets the values missing in the file to 0.
657  state = new_state;
658  return true;
659}
660
661static void write_dev_state_line(FILE * f, const char * name, uint64_t val)
662{
663  if (val)
664    fprintf(f, "%s = %"PRIu64"\n", name, val);
665}
666
667static void write_dev_state_line(FILE * f, const char * name1, int id, const char * name2, uint64_t val)
668{
669  if (val)
670    fprintf(f, "%s.%d.%s = %"PRIu64"\n", name1, id, name2, val);
671}
672
673// Write a state file
674static bool write_dev_state(const char * path, const persistent_dev_state & state)
675{
676  // Rename old "file" to "file~"
677  std::string pathbak = path; pathbak += '~';
678  unlink(pathbak.c_str());
679  rename(path, pathbak.c_str());
680
681  stdio_file f(path, "w");
682  if (!f) {
683    pout("Cannot create state file \"%s\"\n", path);
684    return false;
685  }
686
687  fprintf(f, "# smartd state file\n");
688  write_dev_state_line(f, "temperature-min", state.tempmin);
689  write_dev_state_line(f, "temperature-max", state.tempmax);
690  write_dev_state_line(f, "self-test-errors", state.selflogcount);
691  write_dev_state_line(f, "self-test-last-err-hour", state.selfloghour);
692  write_dev_state_line(f, "scheduled-test-next-check", state.scheduled_test_next_check);
693  write_dev_state_line(f, "selective-test-last-start", state.selective_test_last_start);
694  write_dev_state_line(f, "selective-test-last-end", state.selective_test_last_end);
695
696  int i;
697  for (i = 0; i < SMARTD_NMAIL; i++) {
698    if (i == MAILTYPE_TEST) // Don't suppress test mails
699      continue;
700    const mailinfo & mi = state.maillog[i];
701    if (!mi.logged)
702      continue;
703    write_dev_state_line(f, "mail", i, "count", mi.logged);
704    write_dev_state_line(f, "mail", i, "first-sent-time", mi.firstsent);
705    write_dev_state_line(f, "mail", i, "last-sent-time", mi.lastsent);
706  }
707
708  // ATA ONLY
709  write_dev_state_line(f, "ata-error-count", state.ataerrorcount);
710
711  for (i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
712    const persistent_dev_state::ata_attribute & pa = state.ata_attributes[i];
713    if (!pa.id)
714      continue;
715    write_dev_state_line(f, "ata-smart-attribute", i, "id", pa.id);
716    write_dev_state_line(f, "ata-smart-attribute", i, "val", pa.val);
717    write_dev_state_line(f, "ata-smart-attribute", i, "worst", pa.worst);
718    write_dev_state_line(f, "ata-smart-attribute", i, "raw", pa.raw);
719    write_dev_state_line(f, "ata-smart-attribute", i, "resvd", pa.resvd);
720  }
721
722  return true;
723}
724
725// Write to the attrlog file
726static bool write_dev_attrlog(const char * path, const persistent_dev_state & state)
727{
728  stdio_file f(path, "a");
729  if (!f) {
730    pout("Cannot create attribute log file \"%s\"\n", path);
731    return false;
732  }
733
734  // ATA ONLY
735  time_t now = time(0);
736  struct tm * tms = gmtime(&now);
737  fprintf(f, "%d-%02d-%02d %02d:%02d:%02d;",
738             1900+tms->tm_year, 1+tms->tm_mon, tms->tm_mday,
739             tms->tm_hour, tms->tm_min, tms->tm_sec);
740  for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
741    const persistent_dev_state::ata_attribute & pa = state.ata_attributes[i];
742    if (!pa.id)
743      continue;
744    fprintf(f, "\t%d;%d;%"PRIu64";", pa.id, pa.val, pa.raw);
745  }
746  fprintf(f, "\n");
747
748  return true;
749}
750
751// Write all state files. If write_always is false, don't write
752// unless must_write is set.
753static void write_all_dev_states(const dev_config_vector & configs,
754                                 dev_state_vector & states,
755                                 bool write_always = true)
756{
757  for (unsigned i = 0; i < states.size(); i++) {
758    const dev_config & cfg = configs.at(i);
759    if (cfg.state_file.empty())
760      continue;
761    dev_state & state = states[i];
762    if (!write_always && !state.must_write)
763      continue;
764    if (!write_dev_state(cfg.state_file.c_str(), state))
765      continue;
766    state.must_write = false;
767    if (write_always || debugmode)
768      PrintOut(LOG_INFO, "Device: %s, state written to %s\n",
769               cfg.name.c_str(), cfg.state_file.c_str());
770  }
771}
772
773// Write to all attrlog files
774static void write_all_dev_attrlogs(const dev_config_vector & configs,
775                                   dev_state_vector & states)
776{
777  for (unsigned i = 0; i < states.size(); i++) {
778    const dev_config & cfg = configs.at(i);
779    if (cfg.attrlog_file.empty())
780      continue;
781    dev_state & state = states[i];
782    write_dev_attrlog(cfg.attrlog_file.c_str(), state);
783  }
784}
785
786// remove the PID file
787static void RemovePidFile()
788{
789  if (!pid_file.empty()) {
790    if (unlink(pid_file.c_str()))
791      PrintOut(LOG_CRIT,"Can't unlink PID file %s (%s).\n", 
792               pid_file.c_str(), strerror(errno));
793    pid_file.clear();
794  }
795  return;
796}
797
798extern "C" { // signal handlers require C-linkage
799
800//  Note if we catch a SIGUSR1
801static void USR1handler(int sig)
802{
803  if (SIGUSR1==sig)
804    caughtsigUSR1=1;
805  return;
806}
807
808#ifdef _WIN32
809//  Note if we catch a SIGUSR2
810static void USR2handler(int sig)
811{
812  if (SIGUSR2==sig)
813    caughtsigUSR2=1;
814  return;
815}
816#endif
817
818// Note if we catch a HUP (or INT in debug mode)
819static void HUPhandler(int sig)
820{
821  if (sig==SIGHUP)
822    caughtsigHUP=1;
823  else
824    caughtsigHUP=2;
825  return;
826}
827
828// signal handler for TERM, QUIT, and INT (if not in debug mode)
829static void sighandler(int sig)
830{
831  if (!caughtsigEXIT)
832    caughtsigEXIT=sig;
833  return;
834}
835
836} // extern "C"
837
838// Cleanup, print Goodbye message and remove pidfile
839static int Goodbye(int status)
840{
841  // delete PID file, if one was created
842  RemovePidFile();
843
844  // if we are exiting because of a code bug, tell user
845  if (status==EXIT_BADCODE)
846        PrintOut(LOG_CRIT, "Please inform " PACKAGE_BUGREPORT ", including output of smartd -V.\n");
847
848  // and this should be the final output from smartd before it exits
849  PrintOut(status?LOG_CRIT:LOG_INFO, "smartd is exiting (exit status %d)\n", status);
850
851  return status;
852}
853
854// a replacement for setenv() which is not available on all platforms.
855// Note that the string passed to putenv must not be freed or made
856// invalid, since a pointer to it is kept by putenv(). This means that
857// it must either be a static buffer or allocated off the heap. The
858// string can be freed if the environment variable is redefined or
859// deleted via another call to putenv(). So we keep these in an object
860// as long as the popen() call is underway.
861
862class temp_environ
863{
864public:
865  temp_environ()
866    : m_name(0) { }
867
868  ~temp_environ();
869
870  void set(const char * name, const char * value);
871
872private:
873  const char * m_name;
874  std::string m_buf;
875
876  temp_environ(const temp_environ &);
877  void operator=(const temp_environ &);
878};
879
880temp_environ::~temp_environ()
881{
882  if (m_name)
883    putenv(const_cast<char *>(m_name));
884  // Now it is safe to free m_buf
885}
886
887void temp_environ::set(const char * name, const char * value)
888{
889  m_name = name; // Assumes that name is a static string
890  m_buf = name; m_buf += '='; m_buf += value;
891  putenv(const_cast<char *>(m_buf.c_str()));
892}
893
894#ifdef _WIN32
895
896// Wrapper for winsock startup/cleanup
897struct winsock_initializer
898{
899  winsock_initializer()
900    { WSADATA wsad; status = WSAStartup(0x0202 /*2.2*/, &wsad); }
901  ~winsock_initializer()
902    { if (!status) WSACleanup(); }
903  int status;
904};
905
906#endif // _WIN32
907
908#if defined(HAVE_GETADDRINFO) || defined(HAVE_GETHOSTBYNAME)
909
910static bool get_dnsdomain(const char * hostname, char * domainname, unsigned maxsize)
911{
912#ifdef HAVE_GETADDRINFO
913  struct addrinfo hints;
914  memset(&hints, 0, sizeof(hints));
915  hints.ai_flags = AI_CANONNAME;
916  struct addrinfo * info = 0;
917  int err = getaddrinfo(hostname, (const char *)0, &hints, &info);
918  if (err || !info) {
919    PrintOut(LOG_CRIT, "Error retrieving getaddrinfo(%s): %s\n", hostname, gai_strerror(err));
920    return false;
921  }
922
923  const char * p = info->ai_canonname;
924
925#else // defined(HAVE_GETHOSTBYNAME)
926  const struct hostent * hp = gethostbyname(hostname);
927  if (!hp)
928    return false;
929
930  // Does this work if gethostbyname() returns an IPv6 name in
931  // colon/dot notation?  [BA]
932  const char * p = hp->h_name;
933
934#endif
935  if (!p)
936    return false;
937  p = strchr(p, '.');
938  if (!p)
939    domainname[0] = 0;
940  else {
941    strncpy(domainname, p + 1, maxsize);
942    domainname[maxsize-1] = 0;
943  }
944
945#ifdef HAVE_GETADDRINFO
946  freeaddrinfo(info);
947#endif
948  return true;
949}
950
951#endif // defined(HAVE_GETADDRINFO) || defined(HAVE_GETHOSTBYNAME)
952
953#define EBUFLEN 1024
954
955static void MailWarning(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...)
956                        __attribute_format_printf(4, 5);
957
958// If either address or executable path is non-null then send and log
959// a warning email, or execute executable
960static void MailWarning(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...)
961{
962  static const char * const whichfail[] = {
963    "EmailTest",                  // 0
964    "Health",                     // 1
965    "Usage",                      // 2
966    "SelfTest",                   // 3
967    "ErrorCount",                 // 4
968    "FailedHealthCheck",          // 5
969    "FailedReadSmartData",        // 6
970    "FailedReadSmartErrorLog",    // 7
971    "FailedReadSmartSelfTestLog", // 8
972    "FailedOpenDevice",           // 9
973    "CurrentPendingSector",       // 10
974    "OfflineUncorrectableSector", // 11
975    "Temperature"                 // 12
976  };
977 
978  // See if user wants us to send mail
979  if (cfg.emailaddress.empty() && cfg.emailcmdline.empty())
980    return;
981
982  std::string address = cfg.emailaddress;
983  const char * executable = cfg.emailcmdline.c_str();
984
985  // which type of mail are we sending?
986  mailinfo * mail=(state.maillog)+which;
987
988  // checks for sanity
989  if (cfg.emailfreq<1 || cfg.emailfreq>3) {
990    PrintOut(LOG_CRIT,"internal error in MailWarning(): cfg.mailwarn->emailfreq=%d\n",cfg.emailfreq);
991    return;
992  }
993  if (which<0 || which>=SMARTD_NMAIL || sizeof(whichfail)!=SMARTD_NMAIL*sizeof(char *)) {
994    PrintOut(LOG_CRIT,"Contact " PACKAGE_BUGREPORT "; internal error in MailWarning(): which=%d, size=%d\n",
995             which, (int)sizeof(whichfail));
996    return;
997  }
998
999  // Return if a single warning mail has been sent.
1000  if ((cfg.emailfreq==1) && mail->logged)
1001    return;
1002
1003  // Return if this is an email test and one has already been sent.
1004  if (which == 0 && mail->logged)
1005    return;
1006 
1007  // To decide if to send mail, we need to know what time it is.
1008  time_t epoch = time(0);
1009
1010  // Return if less than one day has gone by
1011  const int day = 24*3600;
1012  if (cfg.emailfreq==2 && mail->logged && epoch<(mail->lastsent+day))
1013    return;
1014
1015  // Return if less than 2^(logged-1) days have gone by
1016  if (cfg.emailfreq==3 && mail->logged) {
1017    int days = 0x01 << (mail->logged - 1);
1018    days*=day;
1019    if  (epoch<(mail->lastsent+days))
1020      return;
1021  }
1022
1023#ifdef HAVE_LIBCAP_NG
1024  if (enable_capabilities) {
1025    PrintOut(LOG_ERR, "Sending a mail was supressed. "
1026             "Mails can't be send when capabilites are enabled\n");
1027    return;
1028  }
1029#endif
1030
1031  // record the time of this mail message, and the first mail message
1032  if (!mail->logged)
1033    mail->firstsent=epoch;
1034  mail->lastsent=epoch;
1035
1036#ifdef _WIN32
1037  // Init winsock during first call
1038  static winsock_initializer init_winsock;
1039  if (init_winsock.status)
1040    PrintOut(LOG_CRIT, "WSAStartup() failed: %d\n", init_winsock.status);
1041#endif
1042
1043  // get system host & domain names (not null terminated if length=MAX)
1044  const char * unknown = "[Unknown]", * none = "[None]";
1045  char hostname[256], domainname[256];
1046
1047#ifdef HAVE_GETHOSTNAME
1048  if (gethostname(hostname, sizeof(hostname)))
1049    strcpy(hostname, unknown);
1050  else {
1051    hostname[sizeof(hostname)-1] = 0;
1052#if defined(HAVE_GETADDRINFO) || defined(HAVE_GETHOSTBYNAME)
1053    if (!get_dnsdomain(hostname, domainname, sizeof(domainname)))
1054      strcpy(domainname, unknown);
1055    else if (!domainname[0])
1056      strcpy(domainname, none);
1057#else
1058    strcpy(domainname, unknown);
1059#endif
1060  }
1061#else
1062  strcpy(hostname, unknown);
1063  strcpy(domainname, unknown);
1064#endif
1065 
1066#ifdef HAVE_GETDOMAINNAME
1067  char nisdomain[256];
1068  if (getdomainname(nisdomain, sizeof(nisdomain)))
1069    strcpy(nisdomain, unknown);
1070  else {
1071    nisdomain[sizeof(nisdomain)-1] = 0;
1072    if (!nisdomain[0])
1073      strcpy(nisdomain, none);
1074  }
1075#endif
1076 
1077  // print warning string into message
1078  char message[256];
1079  va_list ap;
1080  va_start(ap, fmt);
1081  vsnprintf(message, sizeof(message), fmt, ap);
1082  va_end(ap);
1083
1084  // appropriate message about further information
1085  char additional[256], original[256], further[256], dates[DATEANDEPOCHLEN];
1086  additional[0]=original[0]=further[0]='\0';
1087  if (which) {
1088    sprintf(further,"You can also use the smartctl utility for further investigation.\n");
1089
1090    switch (cfg.emailfreq) {
1091    case 1:
1092      sprintf(additional,"No additional email messages about this problem will be sent.\n");
1093      break;
1094    case 2:
1095      sprintf(additional,"Another email message will be sent in 24 hours if the problem persists.\n");
1096      break;
1097    case 3:
1098      sprintf(additional,"Another email message will be sent in %d days if the problem persists\n",
1099              (0x01)<<mail->logged);
1100      break;
1101    }
1102    if (cfg.emailfreq>1 && mail->logged) {
1103      dateandtimezoneepoch(dates, mail->firstsent);
1104      sprintf(original,"The original email about this issue was sent at %s\n", dates);
1105    }
1106  }
1107
1108  char subject[256];
1109  snprintf(subject, sizeof(subject), "SMART error (%s) detected on host: %s", whichfail[which], hostname);
1110
1111  // If the user has set cfg.emailcmdline, use that as mailer, else "mail" or "mailx".
1112  if (!*executable)
1113#ifdef DEFAULT_MAILER
1114    executable = DEFAULT_MAILER ;
1115#else
1116#ifndef _WIN32
1117    executable = "mail";
1118#else
1119    executable = "blat"; // http://blat.sourceforge.net/
1120#endif
1121#endif
1122
1123#ifndef _WIN32 // blat mailer needs comma
1124  // replace commas by spaces to separate recipients
1125  std::replace(address.begin(), address.end(), ',', ' ');
1126#endif
1127  // Export information in environment variables that will be useful
1128  // for user scripts
1129  temp_environ env[12];
1130  env[0].set("SMARTD_MAILER", executable);
1131  env[1].set("SMARTD_MESSAGE", message);
1132  env[2].set("SMARTD_SUBJECT", subject);
1133  dateandtimezoneepoch(dates, mail->firstsent);
1134  env[3].set("SMARTD_TFIRST", dates);
1135  snprintf(dates, DATEANDEPOCHLEN,"%d", (int)mail->firstsent);
1136  env[4].set("SMARTD_TFIRSTEPOCH", dates);
1137  env[5].set("SMARTD_FAILTYPE", whichfail[which]);
1138  if (!address.empty())
1139    env[6].set("SMARTD_ADDRESS", address.c_str());
1140  env[7].set("SMARTD_DEVICESTRING", cfg.name.c_str());
1141
1142  // Allow 'smartctl ... -d $SMARTD_DEVICETYPE $SMARTD_DEVICE'
1143  env[8].set("SMARTD_DEVICETYPE",
1144             (!cfg.dev_type.empty() ? cfg.dev_type.c_str() : "auto"));
1145  env[9].set("SMARTD_DEVICE", cfg.dev_name.c_str());
1146
1147  env[10].set("SMARTD_DEVICEINFO", cfg.dev_idinfo.c_str());
1148
1149  // Format message
1150  char fullmessage[1024];
1151  snprintf(fullmessage, sizeof(fullmessage),
1152           "This email was generated by the smartd daemon running on:\n\n"
1153           "   host name: %s\n"
1154           "  DNS domain: %s\n"
1155#ifdef HAVE_GETDOMAINNAME
1156           "  NIS domain: %s\n"
1157#endif
1158           "\n",
1159           hostname,
1160           domainname
1161#ifdef HAVE_GETDOMAINNAME
1162           , nisdomain
1163#endif
1164           );
1165
1166  int boxmsgoffs = strlen(fullmessage); // start of message for message box on Windows
1167
1168  snprintf(fullmessage + boxmsgoffs, sizeof(fullmessage) - boxmsgoffs,
1169           "The following warning/error was logged by the smartd daemon:\n\n"
1170           "%s\n\n"
1171           "Device info:\n"
1172           "%s\n\n"
1173#ifndef _WIN32
1174           "For details see host's SYSLOG.\n\n"
1175#else
1176           "For details see the event log or log file of smartd.\n\n"
1177#endif
1178           "%s%s%s",
1179           message,
1180           cfg.dev_idinfo.c_str(),
1181           further, original, additional);
1182
1183  env[11].set("SMARTD_FULLMESSAGE", fullmessage);
1184
1185  // now construct a command to send this as EMAIL
1186  char command[2048];
1187
1188#ifndef _WIN32
1189  if (!address.empty())
1190    snprintf(command, sizeof(command),
1191             "$SMARTD_MAILER -s '%s' %s 2>&1 << \"ENDMAIL\"\n"
1192             "%sENDMAIL\n", subject, address.c_str(), fullmessage);
1193  else
1194    snprintf(command, sizeof(command), "%s 2>&1", executable);
1195 
1196  // tell SYSLOG what we are about to do...
1197  const char * newadd = (!address.empty()? address.c_str() : "<nomailer>");
1198  const char * newwarn = (which? "Warning via" : "Test of");
1199
1200  PrintOut(LOG_INFO,"%s %s to %s ...\n",
1201           which?"Sending warning via":"Executing test of", executable, newadd);
1202 
1203  // issue the command to send mail or to run the user's executable
1204  errno=0;
1205  FILE * pfp;
1206  if (!(pfp=popen(command, "r")))
1207    // failed to popen() mail process
1208    PrintOut(LOG_CRIT,"%s %s to %s: failed (fork or pipe failed, or no memory) %s\n", 
1209             newwarn,  executable, newadd, errno?strerror(errno):"");
1210  else {
1211    // pipe suceeded!
1212    int len, status;
1213    char buffer[EBUFLEN];
1214
1215    // if unexpected output on stdout/stderr, null terminate, print, and flush
1216    if ((len=fread(buffer, 1, EBUFLEN, pfp))) {
1217      int count=0;
1218      int newlen = len<EBUFLEN ? len : EBUFLEN-1;
1219      buffer[newlen]='\0';
1220      PrintOut(LOG_CRIT,"%s %s to %s produced unexpected output (%s%d bytes) to STDOUT/STDERR: \n%s\n", 
1221               newwarn, executable, newadd, len!=newlen?"here truncated to ":"", newlen, buffer);
1222     
1223      // flush pipe if needed
1224      while (fread(buffer, 1, EBUFLEN, pfp) && count<EBUFLEN)
1225        count++;
1226
1227      // tell user that pipe was flushed, or that something is really wrong
1228      if (count && count<EBUFLEN)
1229        PrintOut(LOG_CRIT,"%s %s to %s: flushed remaining STDOUT/STDERR\n", 
1230                 newwarn, executable, newadd);
1231      else if (count)
1232        PrintOut(LOG_CRIT,"%s %s to %s: more than 1 MB STDOUT/STDERR flushed, breaking pipe\n", 
1233                 newwarn, executable, newadd);
1234    }
1235   
1236    // if something went wrong with mail process, print warning
1237    errno=0;
1238    if (-1==(status=pclose(pfp)))
1239      PrintOut(LOG_CRIT,"%s %s to %s: pclose(3) failed %s\n", newwarn, executable, newadd,
1240               errno?strerror(errno):"");
1241    else {
1242      // mail process apparently succeeded. Check and report exit status
1243      int status8;
1244
1245      if (WIFEXITED(status)) {
1246        // exited 'normally' (but perhaps with nonzero status)
1247        status8=WEXITSTATUS(status);
1248       
1249        if (status8>128) 
1250          PrintOut(LOG_CRIT,"%s %s to %s: failed (32-bit/8-bit exit status: %d/%d) perhaps caught signal %d [%s]\n", 
1251                   newwarn, executable, newadd, status, status8, status8-128, strsignal(status8-128));
1252        else if (status8) 
1253          PrintOut(LOG_CRIT,"%s %s to %s: failed (32-bit/8-bit exit status: %d/%d)\n", 
1254                   newwarn, executable, newadd, status, status8);
1255        else
1256          PrintOut(LOG_INFO,"%s %s to %s: successful\n", newwarn, executable, newadd);
1257      }
1258     
1259      if (WIFSIGNALED(status))
1260        PrintOut(LOG_INFO,"%s %s to %s: exited because of uncaught signal %d [%s]\n", 
1261                 newwarn, executable, newadd, WTERMSIG(status), strsignal(WTERMSIG(status)));
1262     
1263      // this branch is probably not possible. If subprocess is
1264      // stopped then pclose() should not return.
1265      if (WIFSTOPPED(status)) 
1266        PrintOut(LOG_CRIT,"%s %s to %s: process STOPPED because it caught signal %d [%s]\n",
1267                 newwarn, executable, newadd, WSTOPSIG(status), strsignal(WSTOPSIG(status)));
1268     
1269    }
1270  }
1271 
1272#else // _WIN32
1273
1274  // No "here-documents" on Windows, so must use separate commandline and stdin
1275  const char * stdinbuf = "";
1276  command[0] = 0;
1277  int boxtype = -1;
1278  const char * newadd = "<nomailer>";
1279  if (!address.empty()) {
1280    // address "console", ... => show warning (also) via message box(es)
1281    char addr1[9+1+13] = ""; int n1 = -1, n2 = -1;
1282    if (sscanf(address.c_str(), "%9[a-z]%n,%n", addr1, &n1, &n2) == 1 && (n1 == (int)address.size() || n2 > 0)) {
1283      if (!strcmp(addr1, "console"))
1284        boxtype = 0;
1285      else if (!strcmp(addr1, "active"))
1286        boxtype = 1;
1287      else if (!strcmp(addr1, "connected"))
1288        boxtype = 2;
1289      if (boxtype >= 0)
1290        address.erase(0, (n2 > n1 ? n2 : n1));
1291    }
1292
1293    if (!address.empty()) {
1294      // Use "blat" parameter syntax (TODO: configure via -M for other mailers)
1295      snprintf(command, sizeof(command),
1296               "%s - -q -subject \"%s\" -to \"%s\"",
1297               executable, subject, address.c_str());
1298      newadd = address.c_str();
1299    }
1300
1301    stdinbuf = fullmessage;
1302  }
1303  else
1304    snprintf(command, sizeof(command), "%s", executable);
1305
1306  const char * newwarn = (which ? "Warning via" : "Test of");
1307  if (boxtype >= 0) {
1308    // show message box(es) via send message
1309    int errcnt = 0;
1310    int msgcnt = wts_send_message(boxtype, subject, stdinbuf+boxmsgoffs, &errcnt);
1311    PrintOut(LOG_INFO,"%s message box: %d message%s sent, %d failed\n", newwarn,
1312      msgcnt, (msgcnt==1 ? "" : "s"), errcnt);
1313  }
1314  if (command[0]) {
1315    char stdoutbuf[800]; // < buffer in syslog_win32::vsyslog()
1316    int rc;
1317    // run command
1318    PrintOut(LOG_INFO,"%s %s to %s ...\n",
1319             (which?"Sending warning via":"Executing test of"), executable, newadd);
1320    rc = daemon_spawn(command, stdinbuf, strlen(stdinbuf), stdoutbuf, sizeof(stdoutbuf));
1321    if (rc >= 0 && stdoutbuf[0])
1322      PrintOut(LOG_CRIT,"%s %s to %s produced unexpected output (%d bytes) to STDOUT/STDERR:\n%s\n",
1323        newwarn, executable, newadd, (int)strlen(stdoutbuf), stdoutbuf);
1324    if (rc != 0)
1325      PrintOut(LOG_CRIT,"%s %s to %s: failed, exit status %d\n",
1326        newwarn, executable, newadd, rc);
1327    else
1328      PrintOut(LOG_INFO,"%s %s to %s: successful\n", newwarn, executable, newadd);
1329  }
1330
1331#endif // _WIN32
1332
1333  // increment mail sent counter
1334  mail->logged++;
1335}
1336
1337static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...)
1338                               __attribute_format_printf(4, 5);
1339
1340static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...)
1341{
1342  if (!(0 <= which && which < SMARTD_NMAIL))
1343    return;
1344
1345  // Return if no mail sent yet
1346  mailinfo & mi = state.maillog[which];
1347  if (!mi.logged)
1348    return;
1349
1350  // Format & print message
1351  char msg[256];
1352  va_list ap;
1353  va_start(ap, fmt);
1354  vsnprintf(msg, sizeof(msg), fmt, ap);
1355  va_end(ap);
1356
1357  PrintOut(LOG_INFO, "Device: %s, %s, warning condition reset after %d email%s\n", cfg.name.c_str(),
1358           msg, mi.logged, (mi.logged==1 ? "" : "s"));
1359
1360  // Clear mail counter and timestamps
1361  mi = mailinfo();
1362  state.must_write = true;
1363}
1364
1365#ifndef _WIN32
1366
1367// Output multiple lines via separate syslog(3) calls.
1368static void vsyslog_lines(int priority, const char * fmt, va_list ap)
1369{
1370  char buf[512+EBUFLEN]; // enough space for exec cmd output in MailWarning()
1371  vsnprintf(buf, sizeof(buf), fmt, ap);
1372
1373  for (char * p = buf, * q; p && *p; p = q) {
1374    if ((q = strchr(p, '\n')))
1375      *q++ = 0;
1376    if (*p)
1377      syslog(priority, "%s\n", p);
1378  }
1379}
1380
1381#else  // _WIN32
1382// os_win32/syslog_win32.cpp supports multiple lines.
1383#define vsyslog_lines vsyslog
1384#endif // _WIN32
1385
1386// Printing function for watching ataprint commands, or losing them
1387// [From GLIBC Manual: Since the prototype doesn't specify types for
1388// optional arguments, in a call to a variadic function the default
1389// argument promotions are performed on the optional argument
1390// values. This means the objects of type char or short int (whether
1391// signed or not) are promoted to either int or unsigned int, as
1392// appropriate.]
1393void pout(const char *fmt, ...){
1394  va_list ap;
1395
1396  // get the correct time in syslog()
1397  FixGlibcTimeZoneBug();
1398  // initialize variable argument list
1399  va_start(ap,fmt);
1400  // in debugmode==1 mode we will print the output from the ataprint.o functions!
1401  if (debugmode && debugmode != 2) {
1402    FILE * f = stdout;
1403#ifdef _WIN32
1404    if (facility == LOG_LOCAL1) // logging to stdout
1405      f = stderr;
1406#endif
1407    vfprintf(f, fmt, ap);
1408    fflush(f);
1409  }
1410  // in debugmode==2 mode we print output from knowndrives.o functions
1411  else if (debugmode==2 || ata_debugmode || scsi_debugmode) {
1412    openlog("smartd", LOG_PID, facility);
1413    vsyslog_lines(LOG_INFO, fmt, ap);
1414    closelog();
1415  }
1416  va_end(ap);
1417  return;
1418}
1419
1420// This function prints either to stdout or to the syslog as needed.
1421static void PrintOut(int priority, const char *fmt, ...){
1422  va_list ap;
1423 
1424  // get the correct time in syslog()
1425  FixGlibcTimeZoneBug();
1426  // initialize variable argument list
1427  va_start(ap,fmt);
1428  if (debugmode) {
1429    FILE * f = stdout;
1430#ifdef _WIN32
1431    if (facility == LOG_LOCAL1) // logging to stdout
1432      f = stderr;
1433#endif
1434    vfprintf(f, fmt, ap);
1435    fflush(f);
1436  }
1437  else {
1438    openlog("smartd", LOG_PID, facility);
1439    vsyslog_lines(priority, fmt, ap);
1440    closelog();
1441  }
1442  va_end(ap);
1443  return;
1444}
1445
1446// Used to warn users about invalid checksums. Called from atacmds.cpp.
1447void checksumwarning(const char * string)
1448{
1449  pout("Warning! %s error: invalid SMART checksum.\n", string);
1450}
1451
1452#ifndef _WIN32
1453
1454// Wait for the pid file to show up, this makes sure a calling program knows
1455// that the daemon is really up and running and has a pid to kill it
1456static bool WaitForPidFile()
1457{
1458    int waited, max_wait = 10;
1459    struct stat stat_buf;
1460
1461    if (pid_file.empty() || debugmode)
1462        return true;
1463
1464    for(waited = 0; waited < max_wait; ++waited) {
1465        if (!stat(pid_file.c_str(), &stat_buf)) {
1466                return true;
1467        } else
1468                sleep(1);
1469    }
1470    return false;
1471}
1472
1473#endif // _WIN32
1474
1475// Forks new process, closes ALL file descriptors, redirects stdin,
1476// stdout, and stderr.  Not quite daemon().  See
1477// http://www.linuxjournal.com/article/2335
1478// for a good description of why we do things this way.
1479static void DaemonInit()
1480{
1481#ifndef _WIN32
1482  pid_t pid;
1483  int i; 
1484
1485  // flush all buffered streams.  Else we might get two copies of open
1486  // streams since both parent and child get copies of the buffers.
1487  fflush(NULL);
1488
1489  if (do_fork) {
1490    if ((pid=fork()) < 0) {
1491      // unable to fork!
1492      PrintOut(LOG_CRIT,"smartd unable to fork daemon process!\n");
1493      EXIT(EXIT_STARTUP);
1494    }
1495    else if (pid) {
1496      // we are the parent process, wait for pid file, then exit cleanly
1497      if(!WaitForPidFile()) {
1498        PrintOut(LOG_CRIT,"PID file %s didn't show up!\n", pid_file.c_str());
1499        EXIT(EXIT_STARTUP);
1500      } else
1501        EXIT(0);
1502    }
1503 
1504    // from here on, we are the child process.
1505    setsid();
1506
1507    // Fork one more time to avoid any possibility of having terminals
1508    if ((pid=fork()) < 0) {
1509      // unable to fork!
1510      PrintOut(LOG_CRIT,"smartd unable to fork daemon process!\n");
1511      EXIT(EXIT_STARTUP);
1512    }
1513    else if (pid)
1514      // we are the parent process -- exit cleanly
1515      EXIT(0);
1516
1517    // Now we are the child's child...
1518  }
1519
1520  // close any open file descriptors
1521  for (i=getdtablesize();i>=0;--i)
1522    close(i);
1523 
1524#define NO_warn_unused_result(cmd) { if (cmd) {} ; }
1525
1526  // redirect any IO attempts to /dev/null for stdin
1527  i=open("/dev/null",O_RDWR);
1528  if (i>=0) {
1529    // stdout
1530    NO_warn_unused_result(dup(i));
1531    // stderr
1532    NO_warn_unused_result(dup(i));
1533  };
1534  umask(0022);
1535  NO_warn_unused_result(chdir("/"));
1536
1537  if (do_fork)
1538    PrintOut(LOG_INFO, "smartd has fork()ed into background mode. New PID=%d.\n", (int)getpid());
1539
1540#else // _WIN32
1541
1542  // No fork() on native Win32
1543  // Detach this process from console
1544  fflush(NULL);
1545  if (daemon_detach("smartd")) {
1546    PrintOut(LOG_CRIT,"smartd unable to detach from console!\n");
1547    EXIT(EXIT_STARTUP);
1548  }
1549  // stdin/out/err now closed if not redirected
1550
1551#endif // _WIN32
1552  return;
1553}
1554
1555// create a PID file containing the current process id
1556static void WritePidFile()
1557{
1558  if (!pid_file.empty()) {
1559    pid_t pid = getpid();
1560    mode_t old_umask;
1561#ifndef __CYGWIN__
1562    old_umask = umask(0077); // rwx------
1563#else
1564    // Cygwin: smartd service runs on system account, ensure PID file can be read by admins
1565    old_umask = umask(0033); // rwxr--r--
1566#endif
1567
1568    stdio_file f(pid_file.c_str(), "w");
1569    umask(old_umask);
1570    if (!(f && fprintf(f, "%d\n", (int)pid) > 0 && f.close())) {
1571      PrintOut(LOG_CRIT, "unable to write PID file %s - exiting.\n", pid_file.c_str());
1572      EXIT(EXIT_PID);
1573    }
1574    PrintOut(LOG_INFO, "file %s written containing PID %d\n", pid_file.c_str(), (int)pid);
1575  }
1576}
1577
1578// Prints header identifying version of code and home
1579static void PrintHead()
1580{
1581  PrintOut(LOG_INFO, "%s\n", format_version_info("smartd").c_str());
1582}
1583
1584// prints help info for configuration file Directives
1585static void Directives()
1586{
1587  PrintOut(LOG_INFO,
1588           "Configuration file (%s) Directives (after device name):\n"
1589           "  -d TYPE Set the device type: auto, removable,\n"
1590           "          %s\n"
1591           "  -T TYPE Set the tolerance to one of: normal, permissive\n"
1592           "  -o VAL  Enable/disable automatic offline tests (on/off)\n"
1593           "  -S VAL  Enable/disable attribute autosave (on/off)\n"
1594           "  -n MODE No check if: never, sleep[,N][,q], standby[,N][,q], idle[,N][,q]\n"
1595           "  -H      Monitor SMART Health Status, report if failed\n"
1596           "  -s REG  Do Self-Test at time(s) given by regular expression REG\n"
1597           "  -l TYPE Monitor SMART log or self-test status:\n"
1598           "          error, selftest, xerror, offlinests[,ns], selfteststs[,ns]\n"
1599           "  -l scterc,R,W  Set SCT Error Recovery Control\n"
1600           "  -e      Change device setting: aam,[N|off], apm,[N|off], lookahead,[on|off],\n"
1601           "          security-freeze, standby,[N|off], wcache,[on|off]\n"
1602           "  -f      Monitor 'Usage' Attributes, report failures\n"
1603           "  -m ADD  Send email warning to address ADD\n"
1604           "  -M TYPE Modify email warning behavior (see man page)\n"
1605           "  -p      Report changes in 'Prefailure' Attributes\n"
1606           "  -u      Report changes in 'Usage' Attributes\n"
1607           "  -t      Equivalent to -p and -u Directives\n"
1608           "  -r ID   Also report Raw values of Attribute ID with -p, -u or -t\n"
1609           "  -R ID   Track changes in Attribute ID Raw value with -p, -u or -t\n"
1610           "  -i ID   Ignore Attribute ID for -f Directive\n"
1611           "  -I ID   Ignore Attribute ID for -p, -u or -t Directive\n"
1612           "  -C ID[+] Monitor [increases of] Current Pending Sectors in Attribute ID\n"
1613           "  -U ID[+] Monitor [increases of] Offline Uncorrectable Sectors in Attribute ID\n"
1614           "  -W D,I,C Monitor Temperature D)ifference, I)nformal limit, C)ritical limit\n"
1615           "  -v N,ST Modifies labeling of Attribute N (see man page)  \n"
1616           "  -P TYPE Drive-specific presets: use, ignore, show, showall\n"
1617           "  -a      Default: -H -f -t -l error -l selftest -l selfteststs -C 197 -U 198\n"
1618           "  -F TYPE Use firmware bug workaround:\n"
1619           "          %s\n"
1620           "   #      Comment: text after a hash sign is ignored\n"
1621           "   \\      Line continuation character\n"
1622           "Attribute ID is a decimal integer 1 <= ID <= 255\n"
1623           "Use ID = 0 to turn off -C and/or -U Directives\n"
1624           "Example: /dev/sda -a\n",
1625           configfile,
1626           smi()->get_valid_dev_types_str().c_str(),
1627           get_valid_firmwarebug_args());
1628}
1629
1630/* Returns a pointer to a static string containing a formatted list of the valid
1631   arguments to the option opt or NULL on failure. */
1632static const char *GetValidArgList(char opt)
1633{
1634  switch (opt) {
1635  case 'A':
1636  case 's':
1637    return "<PATH_PREFIX>";
1638  case 'c':
1639    return "<FILE_NAME>, -";
1640  case 'l':
1641    return "daemon, local0, local1, local2, local3, local4, local5, local6, local7";
1642  case 'q':
1643    return "nodev, errors, nodevstartup, never, onecheck, showtests";
1644  case 'r':
1645    return "ioctl[,N], ataioctl[,N], scsiioctl[,N]";
1646  case 'B':
1647  case 'p':
1648    return "<FILE_NAME>";
1649  case 'i':
1650    return "<INTEGER_SECONDS>";
1651  default:
1652    return NULL;
1653  }
1654}
1655
1656/* prints help information for command syntax */
1657static void Usage()
1658{
1659  PrintOut(LOG_INFO,"Usage: smartd [options]\n\n");
1660  PrintOut(LOG_INFO,"  -A PREFIX, --attributelog=PREFIX\n");
1661  PrintOut(LOG_INFO,"        Log ATA attribute information to {PREFIX}MODEL-SERIAL.ata.csv\n");
1662#ifdef SMARTMONTOOLS_ATTRIBUTELOG
1663  PrintOut(LOG_INFO,"        [default is "SMARTMONTOOLS_ATTRIBUTELOG"MODEL-SERIAL.ata.csv]\n");
1664#endif
1665  PrintOut(LOG_INFO,"\n");
1666  PrintOut(LOG_INFO,"  -B [+]FILE, --drivedb=[+]FILE\n");
1667  PrintOut(LOG_INFO,"        Read and replace [add] drive database from FILE\n");
1668  PrintOut(LOG_INFO,"        [default is +%s", get_drivedb_path_add());
1669#ifdef SMARTMONTOOLS_DRIVEDBDIR
1670  PrintOut(LOG_INFO,"\n");
1671  PrintOut(LOG_INFO,"         and then    %s", get_drivedb_path_default());
1672#endif
1673  PrintOut(LOG_INFO,"]\n\n");
1674  PrintOut(LOG_INFO,"  -c NAME|-, --configfile=NAME|-\n");
1675  PrintOut(LOG_INFO,"        Read configuration file NAME or stdin\n");
1676  PrintOut(LOG_INFO,"        [default is %s]\n\n", configfile);
1677#ifdef HAVE_LIBCAP_NG
1678  PrintOut(LOG_INFO,"  -C, --capabilities\n");
1679  PrintOut(LOG_INFO,"        Use capabilities.\n"
1680                    "        Warning: Mail notification does not work when used.\n\n");
1681#endif
1682  PrintOut(LOG_INFO,"  -d, --debug\n");
1683  PrintOut(LOG_INFO,"        Start smartd in debug mode\n\n");
1684  PrintOut(LOG_INFO,"  -D, --showdirectives\n");
1685  PrintOut(LOG_INFO,"        Print the configuration file Directives and exit\n\n");
1686  PrintOut(LOG_INFO,"  -h, --help, --usage\n");
1687  PrintOut(LOG_INFO,"        Display this help and exit\n\n");
1688  PrintOut(LOG_INFO,"  -i N, --interval=N\n");
1689  PrintOut(LOG_INFO,"        Set interval between disk checks to N seconds, where N >= 10\n\n");
1690  PrintOut(LOG_INFO,"  -l local[0-7], --logfacility=local[0-7]\n");
1691#ifndef _WIN32
1692  PrintOut(LOG_INFO,"        Use syslog facility local0 - local7 or daemon [default]\n\n");
1693#else
1694  PrintOut(LOG_INFO,"        Log to \"./smartd.log\", stdout, stderr [default is event log]\n\n");
1695#endif
1696#ifndef _WIN32
1697  PrintOut(LOG_INFO,"  -n, --no-fork\n");
1698  PrintOut(LOG_INFO,"        Do not fork into background\n\n");
1699#endif  // _WIN32
1700  PrintOut(LOG_INFO,"  -p NAME, --pidfile=NAME\n");
1701  PrintOut(LOG_INFO,"        Write PID file NAME\n\n");
1702  PrintOut(LOG_INFO,"  -q WHEN, --quit=WHEN\n");
1703  PrintOut(LOG_INFO,"        Quit on one of: %s\n\n", GetValidArgList('q'));
1704  PrintOut(LOG_INFO,"  -r, --report=TYPE\n");
1705  PrintOut(LOG_INFO,"        Report transactions for one of: %s\n\n", GetValidArgList('r'));
1706  PrintOut(LOG_INFO,"  -s PREFIX, --savestates=PREFIX\n");
1707  PrintOut(LOG_INFO,"        Save disk states to {PREFIX}MODEL-SERIAL.TYPE.state\n");
1708#ifdef SMARTMONTOOLS_SAVESTATES
1709  PrintOut(LOG_INFO,"        [default is "SMARTMONTOOLS_SAVESTATES"MODEL-SERIAL.TYPE.state]\n");
1710#endif
1711  PrintOut(LOG_INFO,"\n");
1712#ifdef _WIN32
1713  PrintOut(LOG_INFO,"  --service\n");
1714  PrintOut(LOG_INFO,"        Running as windows service (see man page), install with:\n");
1715  PrintOut(LOG_INFO,"          smartd install [options]\n");
1716  PrintOut(LOG_INFO,"        Remove service with:\n");
1717  PrintOut(LOG_INFO,"          smartd remove\n\n");
1718#endif // _WIN32
1719  PrintOut(LOG_INFO,"  -V, --version, --license, --copyright\n");
1720  PrintOut(LOG_INFO,"        Print License, Copyright, and version information\n");
1721}
1722
1723static int CloseDevice(smart_device * device, const char * name)
1724{
1725  if (!device->close()){
1726    PrintOut(LOG_INFO,"Device: %s, %s, close() failed\n", name, device->get_errmsg());
1727    return 1;
1728  }
1729  // device sucessfully closed
1730  return 0;
1731}
1732
1733// return true if a char is not allowed in a state file name
1734static bool not_allowed_in_filename(char c)
1735{
1736  return !(   ('0' <= c && c <= '9')
1737           || ('A' <= c && c <= 'Z')
1738           || ('a' <= c && c <= 'z'));
1739}
1740
1741// Read error count from Summary or Extended Comprehensive SMART error log
1742// Return -1 on error
1743static int read_ata_error_count(ata_device * device, const char * name,
1744                                firmwarebug_defs firmwarebugs, bool extended)
1745{
1746  if (!extended) {
1747    ata_smart_errorlog log;
1748    if (ataReadErrorLog(device, &log, firmwarebugs)){
1749      PrintOut(LOG_INFO,"Device: %s, Read Summary SMART Error Log failed\n",name);
1750      return -1;
1751    }
1752    return (log.error_log_pointer ? log.ata_error_count : 0);
1753  }
1754  else {
1755    ata_smart_exterrlog logx;
1756    if (!ataReadExtErrorLog(device, &logx, 1 /*first sector only*/, firmwarebugs)) {
1757      PrintOut(LOG_INFO,"Device: %s, Read Extended Comprehensive SMART Error Log failed\n",name);
1758      return -1;
1759    }
1760    // Some disks use the reserved byte as index, see ataprint.cpp.
1761    return (logx.error_log_index || logx.reserved1 ? logx.device_error_count : 0);
1762  }
1763}
1764
1765// returns <0 if problem.  Otherwise, bottom 8 bits are the self test
1766// error count, and top bits are the power-on hours of the last error.
1767static int SelfTestErrorCount(ata_device * device, const char * name,
1768                              firmwarebug_defs firmwarebugs)
1769{
1770  struct ata_smart_selftestlog log;
1771
1772  if (ataReadSelfTestLog(device, &log, firmwarebugs)){
1773    PrintOut(LOG_INFO,"Device: %s, Read SMART Self Test Log Failed\n",name);
1774    return -1;
1775  }
1776 
1777  // return current number of self-test errors
1778  return ataPrintSmartSelfTestlog(&log, false, firmwarebugs);
1779}
1780
1781#define SELFTEST_ERRORCOUNT(x) (x & 0xff)
1782#define SELFTEST_ERRORHOURS(x) ((x >> 8) & 0xffff)
1783
1784// Check offline data collection status
1785static inline bool is_offl_coll_in_progress(unsigned char status)
1786{
1787  return ((status & 0x7f) == 0x03);
1788}
1789
1790// Check self-test execution status
1791static inline bool is_self_test_in_progress(unsigned char status)
1792{
1793  return ((status >> 4) == 0xf);
1794}
1795
1796// Log offline data collection status
1797static void log_offline_data_coll_status(const char * name, unsigned char status)
1798{
1799  const char * msg;
1800  switch (status & 0x7f) {
1801    case 0x00: msg = "was never started"; break;
1802    case 0x02: msg = "was completed without error"; break;
1803    case 0x03: msg = "is in progress"; break;
1804    case 0x04: msg = "was suspended by an interrupting command from host"; break;
1805    case 0x05: msg = "was aborted by an interrupting command from host"; break;
1806    case 0x06: msg = "was aborted by the device with a fatal error"; break;
1807    default:   msg = 0;
1808  }
1809
1810  if (msg)
1811    PrintOut(((status & 0x7f) == 0x06 ? LOG_CRIT : LOG_INFO),
1812             "Device: %s, offline data collection %s%s\n", name, msg,
1813             ((status & 0x80) ? " (auto:on)" : ""));
1814  else
1815    PrintOut(LOG_INFO, "Device: %s, unknown offline data collection status 0x%02x\n",
1816             name, status);
1817}
1818
1819// Log self-test execution status
1820static void log_self_test_exec_status(const char * name, unsigned char status)
1821{
1822  const char * msg;
1823  switch (status >> 4) {
1824    case 0x0: msg = "completed without error"; break;
1825    case 0x1: msg = "was aborted by the host"; break;
1826    case 0x2: msg = "was interrupted by the host with a reset"; break;
1827    case 0x3: msg = "could not complete due to a fatal or unknown error"; break;
1828    case 0x4: msg = "completed with error (unknown test element)"; break;
1829    case 0x5: msg = "completed with error (electrical test element)"; break;
1830    case 0x6: msg = "completed with error (servo/seek test element)"; break;
1831    case 0x7: msg = "completed with error (read test element)"; break;
1832    case 0x8: msg = "completed with error (handling damage?)"; break;
1833    default:  msg = 0;
1834  }
1835
1836  if (msg)
1837    PrintOut(((status >> 4) >= 0x4 ? LOG_CRIT : LOG_INFO),
1838             "Device: %s, previous self-test %s\n", name, msg);
1839  else if ((status >> 4) == 0xf)
1840    PrintOut(LOG_INFO, "Device: %s, self-test in progress, %u0%% remaining\n",
1841             name, status & 0x0f);
1842  else
1843    PrintOut(LOG_INFO, "Device: %s, unknown self-test status 0x%02x\n",
1844             name, status);
1845}
1846
1847// Check pending sector count id (-C, -U directives).
1848static bool check_pending_id(const dev_config & cfg, const dev_state & state,
1849                             unsigned char id, const char * msg)
1850{
1851  // Check attribute index
1852  int i = ata_find_attr_index(id, state.smartval);
1853  if (i < 0) {
1854    PrintOut(LOG_INFO, "Device: %s, can't monitor %s count - no Attribute %d\n",
1855             cfg.name.c_str(), msg, id);
1856    return false;
1857  }
1858
1859  // Check value
1860  uint64_t rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i],
1861    cfg.attribute_defs);
1862  if (rawval >= (state.num_sectors ? state.num_sectors : 0xffffffffULL)) {
1863    PrintOut(LOG_INFO, "Device: %s, ignoring %s count - bogus Attribute %d value %"PRIu64" (0x%"PRIx64")\n",
1864             cfg.name.c_str(), msg, id, rawval, rawval);
1865    return false;
1866  }
1867
1868  return true;
1869}
1870
1871// Called by ATA/SCSIDeviceScan() after successful device check
1872static void finish_device_scan(dev_config & cfg, dev_state & state)
1873{
1874  // Set cfg.emailfreq if user hasn't set it
1875  if ((!cfg.emailaddress.empty() || !cfg.emailcmdline.empty()) && !cfg.emailfreq) {
1876    // Avoid that emails are suppressed forever due to state persistence
1877    if (cfg.state_file.empty())
1878      cfg.emailfreq = 1; // '-M once'
1879    else
1880      cfg.emailfreq = 2; // '-M daily'
1881  }
1882
1883  // Start self-test regex check now if time was not read from state file
1884  if (!cfg.test_regex.empty() && !state.scheduled_test_next_check)
1885    state.scheduled_test_next_check = time(0);
1886}
1887
1888// Common function to format result message for ATA setting
1889static void format_set_result_msg(std::string & msg, const char * name, bool ok,
1890                                  int set_option = 0, bool has_value = false)
1891{
1892  if (!msg.empty())
1893    msg += ", ";
1894  msg += name;
1895  if (!ok)
1896    msg += ":--";
1897  else if (set_option < 0)
1898    msg += ":off";
1899  else if (has_value)
1900    msg += strprintf(":%d", set_option-1);
1901  else if (set_option > 0)
1902    msg += ":on";
1903}
1904
1905
1906// TODO: Add '-F swapid' directive
1907const bool fix_swapped_id = false;
1908
1909// scan to see what ata devices there are, and if they support SMART
1910static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atadev)
1911{
1912  int supported=0;
1913  struct ata_identify_device drive;
1914  const char *name = cfg.name.c_str();
1915  int retid;
1916
1917  // Device must be open
1918
1919  // Get drive identity structure
1920  if ((retid = ata_read_identity(atadev, &drive, fix_swapped_id))) {
1921    if (retid<0)
1922      // Unable to read Identity structure
1923      PrintOut(LOG_INFO,"Device: %s, not ATA, no IDENTIFY DEVICE Structure\n",name);
1924    else
1925      PrintOut(LOG_INFO,"Device: %s, packet devices [this device %s] not SMART capable\n",
1926               name, packetdevicetype(retid-1));
1927    CloseDevice(atadev, name);
1928    return 2; 
1929  }
1930
1931  // Get drive identity, size and rotation rate (HDD/SSD)
1932  char model[40+1], serial[20+1], firmware[8+1];
1933  ata_format_id_string(model, drive.model, sizeof(model)-1);
1934  ata_format_id_string(serial, drive.serial_no, sizeof(serial)-1);
1935  ata_format_id_string(firmware, drive.fw_rev, sizeof(firmware)-1);
1936
1937  ata_size_info sizes;
1938  ata_get_size_info(&drive, sizes);
1939  state.num_sectors = sizes.sectors;
1940  cfg.dev_rpm = ata_get_rotation_rate(&drive);
1941
1942  char wwn[30]; wwn[0] = 0;
1943  unsigned oui = 0; uint64_t unique_id = 0;
1944  int naa = ata_get_wwn(&drive, oui, unique_id);
1945  if (naa >= 0)
1946    snprintf(wwn, sizeof(wwn), "WWN:%x-%06x-%09"PRIx64", ", naa, oui, unique_id);
1947
1948  // Format device id string for warning emails
1949  char cap[32];
1950  cfg.dev_idinfo = strprintf("%s, S/N:%s, %sFW:%s, %s", model, serial, wwn, firmware,
1951                     format_capacity(cap, sizeof(cap), sizes.capacity, "."));
1952
1953  PrintOut(LOG_INFO, "Device: %s, %s\n", name, cfg.dev_idinfo.c_str());
1954
1955  // Show if device in database, and use preset vendor attribute
1956  // options unless user has requested otherwise.
1957  if (cfg.ignorepresets)
1958    PrintOut(LOG_INFO, "Device: %s, smartd database not searched (Directive: -P ignore).\n", name);
1959  else {
1960    // Apply vendor specific presets, print warning if present
1961    const drive_settings * dbentry = lookup_drive_apply_presets(
1962      &drive, cfg.attribute_defs, cfg.firmwarebugs);
1963    if (!dbentry)
1964      PrintOut(LOG_INFO, "Device: %s, not found in smartd database.\n", name);
1965    else {
1966      PrintOut(LOG_INFO, "Device: %s, found in smartd database%s%s\n",
1967        name, (*dbentry->modelfamily ? ": " : "."), (*dbentry->modelfamily ? dbentry->modelfamily : ""));
1968      if (*dbentry->warningmsg)
1969        PrintOut(LOG_CRIT, "Device: %s, WARNING: %s\n", name, dbentry->warningmsg);
1970    }
1971  }
1972
1973  // Set default '-C 197[+]' if no '-C ID' is specified.
1974  if (!cfg.curr_pending_set)
1975    cfg.curr_pending_id = get_unc_attr_id(false, cfg.attribute_defs, cfg.curr_pending_incr);
1976  // Set default '-U 198[+]' if no '-U ID' is specified.
1977  if (!cfg.offl_pending_set)
1978    cfg.offl_pending_id = get_unc_attr_id(true, cfg.attribute_defs, cfg.offl_pending_incr);
1979
1980  // If requested, show which presets would be used for this drive
1981  if (cfg.showpresets) {
1982    int savedebugmode=debugmode;
1983    PrintOut(LOG_INFO, "Device %s: presets are:\n", name);
1984    if (!debugmode)
1985      debugmode=2;
1986    show_presets(&drive);
1987    debugmode=savedebugmode;
1988  }
1989
1990  // see if drive supports SMART
1991  supported=ataSmartSupport(&drive);
1992  if (supported!=1) {
1993    if (supported==0)
1994      // drive does NOT support SMART
1995      PrintOut(LOG_INFO,"Device: %s, lacks SMART capability\n",name);
1996    else
1997      // can't tell if drive supports SMART
1998      PrintOut(LOG_INFO,"Device: %s, ATA IDENTIFY DEVICE words 82-83 don't specify if SMART capable.\n",name);
1999 
2000    // should we proceed anyway?
2001    if (cfg.permissive) {
2002      PrintOut(LOG_INFO,"Device: %s, proceeding since '-T permissive' Directive given.\n",name);
2003    }
2004    else {
2005      PrintOut(LOG_INFO,"Device: %s, to proceed anyway, use '-T permissive' Directive.\n",name);
2006      CloseDevice(atadev, name);
2007      return 2;
2008    }
2009  }
2010 
2011  if (ataEnableSmart(atadev)) {
2012    // Enable SMART command has failed
2013    PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name);
2014    CloseDevice(atadev, name);
2015    return 2; 
2016  }
2017 
2018  // disable device attribute autosave...
2019  if (cfg.autosave==1) {
2020    if (ataDisableAutoSave(atadev))
2021      PrintOut(LOG_INFO,"Device: %s, could not disable SMART Attribute Autosave.\n",name);
2022    else
2023      PrintOut(LOG_INFO,"Device: %s, disabled SMART Attribute Autosave.\n",name);
2024  }
2025
2026  // or enable device attribute autosave
2027  if (cfg.autosave==2) {
2028    if (ataEnableAutoSave(atadev))
2029      PrintOut(LOG_INFO,"Device: %s, could not enable SMART Attribute Autosave.\n",name);
2030    else
2031      PrintOut(LOG_INFO,"Device: %s, enabled SMART Attribute Autosave.\n",name);
2032  }
2033
2034  // capability check: SMART status
2035  if (cfg.smartcheck && ataSmartStatus2(atadev) == -1) {
2036    PrintOut(LOG_INFO,"Device: %s, not capable of SMART Health Status check\n",name);
2037    cfg.smartcheck = false;
2038  }
2039 
2040  // capability check: Read smart values and thresholds.  Note that
2041  // smart values are ALSO needed even if we ONLY want to know if the
2042  // device is self-test log or error-log capable!  After ATA-5, this
2043  // information was ALSO reproduced in the IDENTIFY DEVICE response,
2044  // but sadly not for ATA-5.  Sigh.
2045
2046  // do we need to get SMART data?
2047  bool smart_val_ok = false;
2048  if (   cfg.autoofflinetest || cfg.selftest
2049      || cfg.errorlog        || cfg.xerrorlog
2050      || cfg.offlinests      || cfg.selfteststs
2051      || cfg.usagefailed     || cfg.prefail  || cfg.usage
2052      || cfg.tempdiff        || cfg.tempinfo || cfg.tempcrit
2053      || cfg.curr_pending_id || cfg.offl_pending_id         ) {
2054
2055    if (ataReadSmartValues(atadev, &state.smartval)) {
2056      PrintOut(LOG_INFO, "Device: %s, Read SMART Values failed\n", name);
2057      cfg.usagefailed = cfg.prefail = cfg.usage = false;
2058      cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
2059      cfg.curr_pending_id = cfg.offl_pending_id = 0;
2060    }
2061    else {
2062      smart_val_ok = true;
2063      if (ataReadSmartThresholds(atadev, &state.smartthres)) {
2064        PrintOut(LOG_INFO, "Device: %s, Read SMART Thresholds failed%s\n",
2065                 name, (cfg.usagefailed ? ", ignoring -f Directive" : ""));
2066        cfg.usagefailed = false;
2067        // Let ata_get_attr_state() return ATTRSTATE_NO_THRESHOLD:
2068        memset(&state.smartthres, 0, sizeof(state.smartthres));
2069      }
2070    }
2071
2072    // see if the necessary Attribute is there to monitor offline or
2073    // current pending sectors or temperature
2074    if (   cfg.curr_pending_id
2075        && !check_pending_id(cfg, state, cfg.curr_pending_id,
2076              "Current_Pending_Sector"))
2077      cfg.curr_pending_id = 0;
2078
2079    if (   cfg.offl_pending_id
2080        && !check_pending_id(cfg, state, cfg.offl_pending_id,
2081              "Offline_Uncorrectable"))
2082      cfg.offl_pending_id = 0;
2083
2084    if (   (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
2085        && !ata_return_temperature_value(&state.smartval, cfg.attribute_defs)) {
2086      PrintOut(LOG_INFO, "Device: %s, can't monitor Temperature, ignoring -W %d,%d,%d\n",
2087               name, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit);
2088      cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
2089    }
2090
2091    // Report ignored '-r' or '-R' directives
2092    for (int id = 1; id <= 255; id++) {
2093      if (cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_PRINT)) {
2094        char opt = (!cfg.monitor_attr_flags.is_set(id, MONITOR_RAW) ? 'r' : 'R');
2095        const char * excl = (cfg.monitor_attr_flags.is_set(id,
2096          (opt == 'r' ? MONITOR_AS_CRIT : MONITOR_RAW_AS_CRIT)) ? "!" : "");
2097
2098        int idx = ata_find_attr_index(id, state.smartval);
2099        if (idx < 0)
2100          PrintOut(LOG_INFO,"Device: %s, no Attribute %d, ignoring -%c %d%s\n", name, id, opt, id, excl);
2101        else {
2102          bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(state.smartval.vendor_attributes[idx].flags);
2103          if (!((prefail && cfg.prefail) || (!prefail && cfg.usage)))
2104            PrintOut(LOG_INFO,"Device: %s, not monitoring %s Attributes, ignoring -%c %d%s\n", name,
2105                     (prefail ? "Prefailure" : "Usage"), opt, id, excl);
2106        }
2107      }
2108    }
2109  }
2110 
2111  // enable/disable automatic on-line testing
2112  if (cfg.autoofflinetest) {
2113    // is this an enable or disable request?
2114    const char *what=(cfg.autoofflinetest==1)?"disable":"enable";
2115    if (!smart_val_ok)
2116      PrintOut(LOG_INFO,"Device: %s, could not %s SMART Automatic Offline Testing.\n",name, what);
2117    else {
2118      // if command appears unsupported, issue a warning...
2119      if (!isSupportAutomaticTimer(&state.smartval))
2120        PrintOut(LOG_INFO,"Device: %s, SMART Automatic Offline Testing unsupported...\n",name);
2121      // ... but then try anyway
2122      if ((cfg.autoofflinetest==1)?ataDisableAutoOffline(atadev):ataEnableAutoOffline(atadev))
2123        PrintOut(LOG_INFO,"Device: %s, %s SMART Automatic Offline Testing failed.\n", name, what);
2124      else
2125        PrintOut(LOG_INFO,"Device: %s, %sd SMART Automatic Offline Testing.\n", name, what);
2126    }
2127  }
2128
2129  // Read log directories if required for capability check
2130  ata_smart_log_directory smart_logdir, gp_logdir;
2131  bool smart_logdir_ok = false, gp_logdir_ok = false;
2132
2133  if (   isGeneralPurposeLoggingCapable(&drive)
2134      && (cfg.errorlog || cfg.selftest)
2135      && !cfg.firmwarebugs.is_set(BUG_NOLOGDIR)) {
2136      if (!ataReadLogDirectory(atadev, &smart_logdir, false))
2137        smart_logdir_ok = true;
2138  }
2139
2140  if (cfg.xerrorlog && !cfg.firmwarebugs.is_set(BUG_NOLOGDIR)) {
2141    if (!ataReadLogDirectory(atadev, &gp_logdir, true))
2142      gp_logdir_ok = true;
2143  }
2144
2145  // capability check: self-test-log
2146  state.selflogcount = 0; state.selfloghour = 0;
2147  if (cfg.selftest) {
2148    int retval;
2149    if (!(   cfg.permissive
2150          || ( smart_logdir_ok && smart_logdir.entry[0x06-1].numsectors)
2151          || (!smart_logdir_ok && smart_val_ok && isSmartTestLogCapable(&state.smartval, &drive)))) {
2152      PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest (override with -T permissive)\n", name);
2153      cfg.selftest = false;
2154    }
2155    else if ((retval = SelfTestErrorCount(atadev, name, cfg.firmwarebugs)) < 0) {
2156      PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest\n", name);
2157      cfg.selftest = false;
2158    }
2159    else {
2160      state.selflogcount=SELFTEST_ERRORCOUNT(retval);
2161      state.selfloghour =SELFTEST_ERRORHOURS(retval);
2162    }
2163  }
2164 
2165  // capability check: ATA error log
2166  state.ataerrorcount = 0;
2167  if (cfg.errorlog) {
2168    int errcnt1;
2169    if (!(   cfg.permissive
2170          || ( smart_logdir_ok && smart_logdir.entry[0x01-1].numsectors)
2171          || (!smart_logdir_ok && smart_val_ok && isSmartErrorLogCapable(&state.smartval, &drive)))) {
2172      PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error (override with -T permissive)\n", name);
2173      cfg.errorlog = false;
2174    }
2175    else if ((errcnt1 = read_ata_error_count(atadev, name, cfg.firmwarebugs, false)) < 0) {
2176      PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error\n", name);
2177      cfg.errorlog = false;
2178    }
2179    else
2180      state.ataerrorcount = errcnt1;
2181  }
2182
2183  if (cfg.xerrorlog) {
2184    int errcnt2;
2185    if (!(   cfg.permissive || cfg.firmwarebugs.is_set(BUG_NOLOGDIR)
2186          || (gp_logdir_ok && gp_logdir.entry[0x03-1].numsectors)   )) {
2187      PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror (override with -T permissive)\n",
2188               name);
2189      cfg.xerrorlog = false;
2190    }
2191    else if ((errcnt2 = read_ata_error_count(atadev, name, cfg.firmwarebugs, true)) < 0) {
2192      PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror\n", name);
2193      cfg.xerrorlog = false;
2194    }
2195    else if (cfg.errorlog && state.ataerrorcount != errcnt2) {
2196      PrintOut(LOG_INFO, "Device: %s, SMART Error Logs report different error counts: %d != %d\n",
2197               name, state.ataerrorcount, errcnt2);
2198      // Record max error count
2199      if (errcnt2 > state.ataerrorcount)
2200        state.ataerrorcount = errcnt2;
2201    }
2202    else
2203      state.ataerrorcount = errcnt2;
2204  }
2205
2206  // capability check: self-test and offline data collection status
2207  if (cfg.offlinests || cfg.selfteststs) {
2208    if (!(cfg.permissive || (smart_val_ok && state.smartval.offline_data_collection_capability))) {
2209      if (cfg.offlinests)
2210        PrintOut(LOG_INFO, "Device: %s, no SMART Offline Data Collection capability, ignoring -l offlinests (override with -T permissive)\n", name);
2211      if (cfg.selfteststs)
2212        PrintOut(LOG_INFO, "Device: %s, no SMART Self-test capability, ignoring -l selfteststs (override with -T permissive)\n", name);
2213      cfg.offlinests = cfg.selfteststs = false;
2214    }
2215  }
2216
2217  // capabilities check -- does it support powermode?
2218  if (cfg.powermode) {
2219    int powermode = ataCheckPowerMode(atadev);
2220   
2221    if (-1 == powermode) {
2222      PrintOut(LOG_CRIT, "Device: %s, no ATA CHECK POWER STATUS support, ignoring -n Directive\n", name);
2223      cfg.powermode=0;
2224    } 
2225    else if (powermode!=0 && powermode!=0x80 && powermode!=0xff) {
2226      PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n",
2227               name, powermode);
2228      cfg.powermode=0;
2229    }
2230  }
2231
2232  // Apply ATA settings
2233  std::string msg;
2234
2235  if (cfg.set_aam)
2236    format_set_result_msg(msg, "AAM", (cfg.set_aam > 0 ?
2237      ata_set_features(atadev, ATA_ENABLE_AAM, cfg.set_aam-1) :
2238      ata_set_features(atadev, ATA_DISABLE_AAM)), cfg.set_aam, true);
2239
2240  if (cfg.set_apm)
2241    format_set_result_msg(msg, "APM", (cfg.set_apm > 0 ?
2242      ata_set_features(atadev, ATA_ENABLE_APM, cfg.set_apm-1) :
2243      ata_set_features(atadev, ATA_DISABLE_APM)), cfg.set_apm, true);
2244
2245  if (cfg.set_lookahead)
2246    format_set_result_msg(msg, "Rd-ahead", ata_set_features(atadev,
2247      (cfg.set_lookahead > 0 ? ATA_ENABLE_READ_LOOK_AHEAD : ATA_DISABLE_READ_LOOK_AHEAD)),
2248      cfg.set_lookahead);
2249
2250  if (cfg.set_wcache)
2251    format_set_result_msg(msg, "Wr-cache", ata_set_features(atadev,
2252      (cfg.set_wcache > 0? ATA_ENABLE_WRITE_CACHE : ATA_DISABLE_WRITE_CACHE)), cfg.set_wcache);
2253
2254  if (cfg.set_security_freeze)
2255    format_set_result_msg(msg, "Security freeze",
2256      ata_nodata_command(atadev, ATA_SECURITY_FREEZE_LOCK));
2257
2258  if (cfg.set_standby)
2259    format_set_result_msg(msg, "Standby",
2260      ata_nodata_command(atadev, ATA_IDLE, cfg.set_standby-1), cfg.set_standby, true);
2261
2262  // Report as one log entry
2263  if (!msg.empty())
2264    PrintOut(LOG_INFO, "Device: %s, ATA settings applied: %s\n", name, msg.c_str());
2265
2266  // set SCT Error Recovery Control if requested
2267  if (cfg.sct_erc_set) {
2268    if (!isSCTErrorRecoveryControlCapable(&drive))
2269      PrintOut(LOG_INFO, "Device: %s, no SCT Error Recovery Control support, ignoring -l scterc\n",
2270               name);
2271    else if (   ataSetSCTErrorRecoveryControltime(atadev, 1, cfg.sct_erc_readtime )
2272             || ataSetSCTErrorRecoveryControltime(atadev, 2, cfg.sct_erc_writetime))
2273      PrintOut(LOG_INFO, "Device: %s, set of SCT Error Recovery Control failed\n", name);
2274    else
2275      PrintOut(LOG_INFO, "Device: %s, SCT Error Recovery Control set to: Read: %u, Write: %u\n",
2276               name, cfg.sct_erc_readtime, cfg.sct_erc_writetime);
2277  }
2278
2279  // If no tests available or selected, return
2280  if (!(   cfg.smartcheck  || cfg.selftest
2281        || cfg.errorlog    || cfg.xerrorlog
2282        || cfg.offlinests  || cfg.selfteststs
2283        || cfg.usagefailed || cfg.prefail  || cfg.usage
2284        || cfg.tempdiff    || cfg.tempinfo || cfg.tempcrit)) {
2285    CloseDevice(atadev, name);
2286    return 3;
2287  }
2288 
2289  // tell user we are registering device
2290  PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n",name);
2291 
2292  // close file descriptor
2293  CloseDevice(atadev, name);
2294
2295  if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
2296    // Build file name for state file
2297    std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
2298    std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
2299    if (!state_path_prefix.empty()) {
2300      cfg.state_file = strprintf("%s%s-%s.ata.state", state_path_prefix.c_str(), model, serial);
2301      // Read previous state
2302      if (read_dev_state(cfg.state_file.c_str(), state)) {
2303        PrintOut(LOG_INFO, "Device: %s, state read from %s\n", name, cfg.state_file.c_str());
2304        // Copy ATA attribute values to temp state
2305        state.update_temp_state();
2306      }
2307    }
2308    if (!attrlog_path_prefix.empty())
2309      cfg.attrlog_file = strprintf("%s%s-%s.ata.csv", attrlog_path_prefix.c_str(), model, serial);
2310  }
2311
2312  finish_device_scan(cfg, state);
2313
2314  return 0;
2315}
2316
2317// on success, return 0. On failure, return >0.  Never return <0,
2318// please.
2319static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scsidev)
2320{
2321  int k, err, req_len, avail_len, version, len;
2322  const char *device = cfg.name.c_str();
2323  struct scsi_iec_mode_page iec;
2324  UINT8  tBuf[64];
2325  UINT8  inqBuf[96];
2326  UINT8  vpdBuf[252];
2327  char lu_id[64], serial[32+1], model[40+1];
2328
2329  // Device must be open
2330  memset(inqBuf, 0, 96);
2331  req_len = 36;
2332  if ((err = scsiStdInquiry(scsidev, inqBuf, req_len))) {
2333    /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
2334    req_len = 64;
2335    if ((err = scsiStdInquiry(scsidev, inqBuf, req_len))) {
2336      PrintOut(LOG_INFO, "Device: %s, Both 36 and 64 byte INQUIRY failed; "
2337               "skip device\n", device);
2338      return 2;
2339    }
2340  }
2341  version = inqBuf[2];
2342  avail_len = inqBuf[4] + 5;
2343  len = (avail_len < req_len) ? avail_len : req_len;
2344  if (len < 36) {
2345    PrintOut(LOG_INFO, "Device: %s, INQUIRY response less than 36 bytes; "
2346             "skip device\n", device);
2347    return 2;
2348  }
2349
2350  int pdt = inqBuf[0] & 0x1f;
2351
2352  if (! ((0 == pdt) || (4 == pdt) || (5 == pdt) || (7 == pdt) ||
2353         (0xe == pdt))) {
2354    PrintOut(LOG_INFO, "Device: %s, not a disk like device [PDT=0x%x], "
2355             "skip\n", device, pdt);
2356    return 2;
2357  }
2358  lu_id[0] = '\0';
2359  if ((version >= 0x3) && (version < 0x8)) {
2360    /* SPC to SPC-5 */
2361    if (0 == (err = scsiInquiryVpd(scsidev, 0x83, vpdBuf, sizeof(vpdBuf)))) {
2362      len = vpdBuf[3];
2363      scsi_decode_lu_dev_id(vpdBuf + 4, len, lu_id, sizeof(lu_id), NULL);
2364    }
2365  }
2366 
2367  serial[0] = '\0';
2368  if (0 == (err = scsiInquiryVpd(scsidev, 0x80, vpdBuf, sizeof(vpdBuf)))) {
2369          len = vpdBuf[3];
2370          vpdBuf[4 + len] = '\0';
2371          snprintf(&serial[0], sizeof(serial), "%s", &vpdBuf[4]);
2372  } 
2373
2374  unsigned int lb_size;
2375  char si_str[64];
2376  uint64_t capacity = scsiGetSize(scsidev, &lb_size);
2377
2378  if (capacity)
2379    format_capacity(si_str, sizeof(si_str), capacity);
2380  else
2381    si_str[0] = '\0';
2382
2383  // Format device id string for warning emails
2384  cfg.dev_idinfo = strprintf("[%.8s %.16s %.4s]%s%s%s%s%s%s",
2385                     (char *)&inqBuf[8], (char *)&inqBuf[16], (char *)&inqBuf[32],
2386                     (lu_id[0] ? ", lu id: " : ""), (lu_id[0] ? lu_id : ""),
2387                     (serial[0] ? ", S/N: " : ""), (serial[0] ? serial : ""),
2388                     (si_str[0] ? ", " : ""), (si_str[0] ? si_str : ""));
2389 
2390  // format "model" string
2391  snprintf(&model[0], sizeof(model), "%.8s %.16s %.4s", (char *)&inqBuf[8], 
2392                     (char *)&inqBuf[16], (char *)&inqBuf[32]);
2393
2394  PrintOut(LOG_INFO, "Device: %s, %s\n", device, cfg.dev_idinfo.c_str());
2395
2396  // check that device is ready for commands. IE stores its stuff on
2397  // the media.
2398  if ((err = scsiTestUnitReady(scsidev))) {
2399    if (SIMPLE_ERR_NOT_READY == err)
2400      PrintOut(LOG_INFO, "Device: %s, NOT READY (e.g. spun down); skip device\n", device);
2401    else if (SIMPLE_ERR_NO_MEDIUM == err)
2402      PrintOut(LOG_INFO, "Device: %s, NO MEDIUM present; skip device\n", device);
2403    else if (SIMPLE_ERR_BECOMING_READY == err)
2404      PrintOut(LOG_INFO, "Device: %s, BECOMING (but not yet) READY; skip device\n", device);
2405    else
2406      PrintOut(LOG_CRIT, "Device: %s, failed Test Unit Ready [err=%d]\n", device, err);
2407    CloseDevice(scsidev, device);
2408    return 2; 
2409  }
2410 
2411  // Badly-conforming USB storage devices may fail this check.
2412  // The response to the following IE mode page fetch (current and
2413  // changeable values) is carefully examined. It has been found
2414  // that various USB devices that malform the response will lock up
2415  // if asked for a log page (e.g. temperature) so it is best to
2416  // bail out now.
2417  if (!(err = scsiFetchIECmpage(scsidev, &iec, state.modese_len)))
2418    state.modese_len = iec.modese_len;
2419  else if (SIMPLE_ERR_BAD_FIELD == err)
2420    ;  /* continue since it is reasonable not to support IE mpage */
2421  else { /* any other error (including malformed response) unreasonable */
2422    PrintOut(LOG_INFO, 
2423             "Device: %s, Bad IEC (SMART) mode page, err=%d, skip device\n", 
2424             device, err);
2425    CloseDevice(scsidev, device);
2426    return 3;
2427  }
2428 
2429  // N.B. The following is passive (i.e. it doesn't attempt to turn on
2430  // smart if it is off). This may change to be the same as the ATA side.
2431  if (!scsi_IsExceptionControlEnabled(&iec)) {
2432    PrintOut(LOG_INFO, "Device: %s, IE (SMART) not enabled, skip device\n"
2433                       "Try 'smartctl -s on %s' to turn on SMART features\n", 
2434                        device, device);
2435    CloseDevice(scsidev, device);
2436    return 3;
2437  }
2438 
2439  // Flag that certain log pages are supported (information may be
2440  // available from other sources).
2441  if (0 == scsiLogSense(scsidev, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 0)) {
2442    for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) {
2443      switch (tBuf[k]) { 
2444      case TEMPERATURE_LPAGE:
2445        state.TempPageSupported = 1;
2446        break;
2447      case IE_LPAGE:
2448        state.SmartPageSupported = 1;
2449        break;
2450      default:
2451        break;
2452      }
2453    }   
2454  }
2455 
2456  // Check if scsiCheckIE() is going to work
2457  {
2458    UINT8 asc = 0;
2459    UINT8 ascq = 0;
2460    UINT8 currenttemp = 0;
2461    UINT8 triptemp = 0;
2462   
2463    if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported,
2464                    &asc, &ascq, &currenttemp, &triptemp)) {
2465      PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device);
2466      state.SuppressReport = 1;
2467      if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) {
2468        PrintOut(LOG_INFO, "Device: %s, can't monitor Temperature, ignoring -W %d,%d,%d\n",
2469                 device, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit);
2470        cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
2471      }
2472    }
2473  }
2474 
2475  // capability check: self-test-log
2476  if (cfg.selftest){
2477    int retval = scsiCountFailedSelfTests(scsidev, 0);
2478    if (retval<0) {
2479      // no self-test log, turn off monitoring
2480      PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-Test Log.\n", device);
2481      cfg.selftest = false;
2482      state.selflogcount = 0;
2483      state.selfloghour = 0;
2484    }
2485    else {
2486      // register starting values to watch for changes
2487      state.selflogcount=SELFTEST_ERRORCOUNT(retval);
2488      state.selfloghour =SELFTEST_ERRORHOURS(retval);
2489    }
2490  }
2491 
2492  // disable autosave (set GLTSD bit)
2493  if (cfg.autosave==1){
2494    if (scsiSetControlGLTSD(scsidev, 1, state.modese_len))
2495      PrintOut(LOG_INFO,"Device: %s, could not disable autosave (set GLTSD bit).\n",device);
2496    else
2497      PrintOut(LOG_INFO,"Device: %s, disabled autosave (set GLTSD bit).\n",device);
2498  }
2499
2500  // or enable autosave (clear GLTSD bit)
2501  if (cfg.autosave==2){
2502    if (scsiSetControlGLTSD(scsidev, 0, state.modese_len))
2503      PrintOut(LOG_INFO,"Device: %s, could not enable autosave (clear GLTSD bit).\n",device);
2504    else
2505      PrintOut(LOG_INFO,"Device: %s, enabled autosave (cleared GLTSD bit).\n",device);
2506  }
2507 
2508  // tell user we are registering device
2509  PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding to \"monitor\" list.\n", device);
2510
2511  // Make sure that init_standby_check() ignores SCSI devices
2512  cfg.offlinests_ns = cfg.selfteststs_ns = false;
2513
2514  // close file descriptor
2515  CloseDevice(scsidev, device);
2516
2517  if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
2518    // Build file name for state file
2519    std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
2520    std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
2521    if (!state_path_prefix.empty()) {
2522      cfg.state_file = strprintf("%s%s-%s.scsi.state", state_path_prefix.c_str(), model, serial);
2523      // Read previous state
2524      if (read_dev_state(cfg.state_file.c_str(), state)) {
2525        PrintOut(LOG_INFO, "Device: %s, state read from %s\n", device, cfg.state_file.c_str());
2526        // Copy ATA attribute values to temp state
2527        state.update_temp_state();
2528      }
2529    }
2530    if (!attrlog_path_prefix.empty())
2531      cfg.attrlog_file = strprintf("%s%s-%s.scsi.csv", attrlog_path_prefix.c_str(), model, serial);
2532  }
2533
2534  finish_device_scan(cfg, state);
2535
2536  return 0;
2537}
2538
2539// If the self-test log has got more self-test errors (or more recent
2540// self-test errors) recorded, then notify user.
2541static void CheckSelfTestLogs(const dev_config & cfg, dev_state & state, int newi)
2542{
2543  const char * name = cfg.name.c_str();
2544
2545  if (newi<0)
2546    // command failed
2547    MailWarning(cfg, state, 8, "Device: %s, Read SMART Self-Test Log Failed", name);
2548  else {
2549    reset_warning_mail(cfg, state, 8, "Read SMART Self-Test Log worked again");
2550
2551    // old and new error counts
2552    int oldc=state.selflogcount;
2553    int newc=SELFTEST_ERRORCOUNT(newi);
2554   
2555    // old and new error timestamps in hours
2556    int oldh=state.selfloghour;
2557    int newh=SELFTEST_ERRORHOURS(newi);
2558   
2559    if (oldc<newc) {
2560      // increase in error count
2561      PrintOut(LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
2562               name, oldc, newc);
2563      MailWarning(cfg, state, 3, "Device: %s, Self-Test Log error count increased from %d to %d",
2564                   name, oldc, newc);
2565      state.must_write = true;
2566    }
2567    else if (newc > 0 && oldh != newh) {
2568      // more recent error
2569      // a 'more recent' error might actually be a smaller hour number,
2570      // if the hour number has wrapped.
2571      // There's still a bug here.  You might just happen to run a new test
2572      // exactly 32768 hours after the previous failure, and have run exactly
2573      // 20 tests between the two, in which case smartd will miss the
2574      // new failure.
2575      PrintOut(LOG_CRIT, "Device: %s, new Self-Test Log error at hour timestamp %d\n",
2576               name, newh);
2577      MailWarning(cfg, state, 3, "Device: %s, new Self-Test Log error at hour timestamp %d\n",
2578                   name, newh);
2579      state.must_write = true;
2580    }
2581
2582    // Print info if error entries have disappeared
2583    // or newer successful successful extended self-test exits
2584    if (oldc > newc) {
2585      PrintOut(LOG_INFO, "Device: %s, Self-Test Log error count decreased from %d to %d\n",
2586               name, oldc, newc);
2587      if (newc == 0)
2588        reset_warning_mail(cfg, state, 3, "Self-Test Log does no longer report errors");
2589    }
2590
2591    // Needed since self-test error count may DECREASE.  Hour might
2592    // also have changed.
2593    state.selflogcount= newc;
2594    state.selfloghour = newh;
2595  }
2596  return;
2597}
2598
2599// Test types, ordered by priority.
2600static const char test_type_chars[] = "LncrSCO";
2601static const unsigned num_test_types = sizeof(test_type_chars)-1;
2602
2603// returns test type if time to do test of type testtype,
2604// 0 if not time to do test.
2605static char next_scheduled_test(const dev_config & cfg, dev_state & state, bool scsi, time_t usetime = 0)
2606{
2607  // check that self-testing has been requested
2608  if (cfg.test_regex.empty())
2609    return 0;
2610
2611  // Exit if drive not capable of any test
2612  if ( state.not_cap_long && state.not_cap_short &&
2613      (scsi || (state.not_cap_conveyance && state.not_cap_offline)))
2614    return 0;
2615
2616  // since we are about to call localtime(), be sure glibc is informed
2617  // of any timezone changes we make.
2618  if (!usetime)
2619    FixGlibcTimeZoneBug();
2620 
2621  // Is it time for next check?
2622  time_t now = (!usetime ? time(0) : usetime);
2623  if (now < state.scheduled_test_next_check)
2624    return 0;
2625
2626  // Limit time check interval to 90 days
2627  if (state.scheduled_test_next_check + (3600L*24*90) < now)
2628    state.scheduled_test_next_check = now - (3600L*24*90);
2629
2630  // Check interval [state.scheduled_test_next_check, now] for scheduled tests
2631  char testtype = 0;
2632  time_t testtime = 0; int testhour = 0;
2633  int maxtest = num_test_types-1;
2634
2635  for (time_t t = state.scheduled_test_next_check; ; ) {
2636    struct tm * tms = localtime(&t);
2637    // tm_wday is 0 (Sunday) to 6 (Saturday).  We use 1 (Monday) to 7 (Sunday).
2638    int weekday = (tms->tm_wday ? tms->tm_wday : 7);
2639    for (int i = 0; i <= maxtest; i++) {
2640      // Skip if drive not capable of this test
2641      switch (test_type_chars[i]) {
2642        case 'L': if (state.not_cap_long)       continue; break;
2643        case 'S': if (state.not_cap_short)      continue; break;
2644        case 'C': if (scsi || state.not_cap_conveyance) continue; break;
2645        case 'O': if (scsi || state.not_cap_offline)    continue; break;
2646        case 'c': case 'n':
2647        case 'r': if (scsi || state.not_cap_selective)  continue; break;
2648        default: continue;
2649      }
2650      // Try match of "T/MM/DD/d/HH"
2651      char pattern[16];
2652      snprintf(pattern, sizeof(pattern), "%c/%02d/%02d/%1d/%02d",
2653        test_type_chars[i], tms->tm_mon+1, tms->tm_mday, weekday, tms->tm_hour);
2654      if (cfg.test_regex.full_match(pattern)) {
2655        // Test found
2656        testtype = pattern[0];
2657        testtime = t; testhour = tms->tm_hour;
2658        // Limit further matches to higher priority self-tests
2659        maxtest = i-1;
2660        break;
2661      }
2662    }
2663    // Exit if no tests left or current time reached
2664    if (maxtest < 0)
2665      break;
2666    if (t >= now)
2667      break;
2668    // Check next hour
2669    if ((t += 3600) > now)
2670      t = now;
2671  }
2672 
2673  // Do next check not before next hour.
2674  struct tm * tmnow = localtime(&now);
2675  state.scheduled_test_next_check = now + (3600 - tmnow->tm_min*60 - tmnow->tm_sec);
2676
2677  if (testtype) {
2678    state.must_write = true;
2679    // Tell user if an old test was found.
2680    if (!usetime && !(testhour == tmnow->tm_hour && testtime + 3600 > now)) {
2681      char datebuf[DATEANDEPOCHLEN]; dateandtimezoneepoch(datebuf, testtime);
2682      PrintOut(LOG_INFO, "Device: %s, old test of type %c not run at %s, starting now.\n",
2683        cfg.name.c_str(), testtype, datebuf);
2684    }
2685  }
2686
2687  return testtype;
2688}
2689
2690// Print a list of future tests.
2691static void PrintTestSchedule(const dev_config_vector & configs, dev_state_vector & states, const smart_device_list & devices)
2692{
2693  unsigned numdev = configs.size();
2694  if (!numdev)
2695    return;
2696  std::vector<int> testcnts(numdev * num_test_types, 0);
2697
2698  PrintOut(LOG_INFO, "\nNext scheduled self tests (at most 5 of each type per device):\n");
2699
2700  // FixGlibcTimeZoneBug(); // done in PrintOut()
2701  time_t now = time(0);
2702  char datenow[DATEANDEPOCHLEN], date[DATEANDEPOCHLEN];
2703  dateandtimezoneepoch(datenow, now);
2704
2705  long seconds;
2706  for (seconds=checktime; seconds<3600L*24*90; seconds+=checktime) {
2707    // Check for each device whether a test will be run
2708    time_t testtime = now + seconds;
2709    for (unsigned i = 0; i < numdev; i++) {
2710      const dev_config & cfg = configs.at(i);
2711      dev_state & state = states.at(i);
2712      const char * p;
2713      char testtype = next_scheduled_test(cfg, state, devices.at(i)->is_scsi(), testtime);
2714      if (testtype && (p = strchr(test_type_chars, testtype))) {
2715        unsigned t = (p - test_type_chars);
2716        // Report at most 5 tests of each type
2717        if (++testcnts[i*num_test_types + t] <= 5) {
2718          dateandtimezoneepoch(date, testtime);
2719          PrintOut(LOG_INFO, "Device: %s, will do test %d of type %c at %s\n", cfg.name.c_str(),
2720            testcnts[i*num_test_types + t], testtype, date);
2721        }
2722      }
2723    }
2724  }
2725
2726  // Report totals
2727  dateandtimezoneepoch(date, now+seconds);
2728  PrintOut(LOG_INFO, "\nTotals [%s - %s]:\n", datenow, date);
2729  for (unsigned i = 0; i < numdev; i++) {
2730    const dev_config & cfg = configs.at(i);
2731    bool scsi = devices.at(i)->is_scsi();
2732    for (unsigned t = 0; t < num_test_types; t++) {
2733      int cnt = testcnts[i*num_test_types + t];
2734      if (cnt == 0 && !strchr((scsi ? "LS" : "LSCO"), test_type_chars[t]))
2735        continue;
2736      PrintOut(LOG_INFO, "Device: %s, will do %3d test%s of type %c\n", cfg.name.c_str(),
2737        cnt, (cnt==1?"":"s"), test_type_chars[t]);
2738    }
2739  }
2740
2741}
2742
2743// Return zero on success, nonzero on failure. Perform offline (background)
2744// short or long (extended) self test on given scsi device.
2745static int DoSCSISelfTest(const dev_config & cfg, dev_state & state, scsi_device * device, char testtype)
2746{
2747  int retval = 0;
2748  const char *testname = 0;
2749  const char *name = cfg.name.c_str();
2750  int inProgress;
2751
2752  if (scsiSelfTestInProgress(device, &inProgress)) {
2753    PrintOut(LOG_CRIT, "Device: %s, does not support Self-Tests\n", name);
2754    state.not_cap_short = state.not_cap_long = true;
2755    return 1;
2756  }
2757
2758  if (1 == inProgress) {
2759    PrintOut(LOG_INFO, "Device: %s, skip since Self-Test already in "
2760             "progress.\n", name);
2761    return 1;
2762  }
2763
2764  switch (testtype) {
2765  case 'S':
2766    testname = "Short Self";
2767    retval = scsiSmartShortSelfTest(device);
2768    break;
2769  case 'L':
2770    testname = "Long Self";
2771    retval = scsiSmartExtendSelfTest(device);
2772    break;
2773  }
2774  // If we can't do the test, exit
2775  if (NULL == testname) {
2776    PrintOut(LOG_CRIT, "Device: %s, not capable of %c Self-Test\n", name, 
2777             testtype);
2778    return 1;
2779  }
2780  if (retval) {
2781    if ((SIMPLE_ERR_BAD_OPCODE == retval) || 
2782        (SIMPLE_ERR_BAD_FIELD == retval)) {
2783      PrintOut(LOG_CRIT, "Device: %s, not capable of %s-Test\n", name, 
2784               testname);
2785      if ('L'==testtype)
2786        state.not_cap_long = true;
2787      else
2788        state.not_cap_short = true;
2789     
2790      return 1;
2791    }
2792    PrintOut(LOG_CRIT, "Device: %s, execute %s-Test failed (err: %d)\n", name, 
2793             testname, retval);
2794    return 1;
2795  }
2796 
2797  PrintOut(LOG_INFO, "Device: %s, starting scheduled %s-Test.\n", name, testname);
2798 
2799  return 0;
2800}
2801
2802// Do an offline immediate or self-test.  Return zero on success,
2803// nonzero on failure.
2804static int DoATASelfTest(const dev_config & cfg, dev_state & state, ata_device * device, char testtype)
2805{
2806  const char *name = cfg.name.c_str();
2807
2808  // Read current smart data and check status/capability
2809  struct ata_smart_values data;
2810  if (ataReadSmartValues(device, &data) || !(data.offline_data_collection_capability)) {
2811    PrintOut(LOG_CRIT, "Device: %s, not capable of Offline or Self-Testing.\n", name);
2812    return 1;
2813  }
2814 
2815  // Check for capability to do the test
2816  int dotest = -1, mode = 0;
2817  const char *testname = 0;
2818  switch (testtype) {
2819  case 'O':
2820    testname="Offline Immediate ";
2821    if (isSupportExecuteOfflineImmediate(&data))
2822      dotest=OFFLINE_FULL_SCAN;
2823    else
2824      state.not_cap_offline = true;
2825    break;
2826  case 'C':
2827    testname="Conveyance Self-";
2828    if (isSupportConveyanceSelfTest(&data))
2829      dotest=CONVEYANCE_SELF_TEST;
2830    else
2831      state.not_cap_conveyance = true;
2832    break;
2833  case 'S':
2834    testname="Short Self-";
2835    if (isSupportSelfTest(&data))
2836      dotest=SHORT_SELF_TEST;
2837    else
2838      state.not_cap_short = true;
2839    break;
2840  case 'L':
2841    testname="Long Self-";
2842    if (isSupportSelfTest(&data))
2843      dotest=EXTEND_SELF_TEST;
2844    else
2845      state.not_cap_long = true;
2846    break;
2847
2848  case 'c': case 'n': case 'r':
2849    testname = "Selective Self-";
2850    if (isSupportSelectiveSelfTest(&data)) {
2851      dotest = SELECTIVE_SELF_TEST;
2852      switch (testtype) {
2853        case 'c': mode = SEL_CONT; break;
2854        case 'n': mode = SEL_NEXT; break;
2855        case 'r': mode = SEL_REDO; break;
2856      }
2857    }
2858    else
2859      state.not_cap_selective = true;
2860    break;
2861  }
2862 
2863  // If we can't do the test, exit
2864  if (dotest<0) {
2865    PrintOut(LOG_CRIT, "Device: %s, not capable of %sTest\n", name, testname);
2866    return 1;
2867  }
2868 
2869  // If currently running a self-test, do not interrupt it to start another.
2870  if (15==(data.self_test_exec_status >> 4)) {
2871    if (cfg.firmwarebugs.is_set(BUG_SAMSUNG3) && data.self_test_exec_status == 0xf0) {
2872      PrintOut(LOG_INFO, "Device: %s, will not skip scheduled %sTest "
2873               "despite unclear Self-Test byte (SAMSUNG Firmware bug).\n", name, testname);
2874    } else {
2875      PrintOut(LOG_INFO, "Device: %s, skip scheduled %sTest; %1d0%% remaining of current Self-Test.\n",
2876               name, testname, (int)(data.self_test_exec_status & 0x0f));
2877      return 1;
2878    }
2879  }
2880
2881  if (dotest == SELECTIVE_SELF_TEST) {
2882    // Set test span
2883    ata_selective_selftest_args selargs, prev_args;
2884    selargs.num_spans = 1;
2885    selargs.span[0].mode = mode;
2886    prev_args.num_spans = 1;
2887    prev_args.span[0].start = state.selective_test_last_start;
2888    prev_args.span[0].end   = state.selective_test_last_end;
2889    if (ataWriteSelectiveSelfTestLog(device, selargs, &data, state.num_sectors, &prev_args)) {
2890      PrintOut(LOG_CRIT, "Device: %s, prepare %sTest failed\n", name, testname);
2891      return 1;
2892    }
2893    uint64_t start = selargs.span[0].start, end = selargs.span[0].end;
2894    PrintOut(LOG_INFO, "Device: %s, %s test span at LBA %"PRIu64" - %"PRIu64" (%"PRIu64" sectors, %u%% - %u%% of disk).\n",
2895      name, (selargs.span[0].mode == SEL_NEXT ? "next" : "redo"),
2896      start, end, end - start + 1,
2897      (unsigned)((100 * start + state.num_sectors/2) / state.num_sectors),
2898      (unsigned)((100 * end   + state.num_sectors/2) / state.num_sectors));
2899    state.selective_test_last_start = start;
2900    state.selective_test_last_end = end;
2901  }
2902
2903  // execute the test, and return status
2904  int retval = smartcommandhandler(device, IMMEDIATE_OFFLINE, dotest, NULL);
2905  if (retval) {
2906    PrintOut(LOG_CRIT, "Device: %s, execute %sTest failed.\n", name, testname);
2907    return retval;
2908  }
2909
2910  // Report recent test start to do_disable_standby_check()
2911  // and force log of next test status
2912  if (testtype == 'O')
2913    state.offline_started = true;
2914  else
2915    state.selftest_started = true;
2916
2917  PrintOut(LOG_INFO, "Device: %s, starting scheduled %sTest.\n", name, testname);
2918  return 0;
2919}
2920
2921// Check pending sector count attribute values (-C, -U directives).
2922static void check_pending(const dev_config & cfg, dev_state & state,
2923                          unsigned char id, bool increase_only,
2924                          const ata_smart_values & smartval,
2925                          int mailtype, const char * msg)
2926{
2927  // Find attribute index
2928  int i = ata_find_attr_index(id, smartval);
2929  if (!(i >= 0 && ata_find_attr_index(id, state.smartval) == i))
2930    return;
2931
2932  // No report if no sectors pending.
2933  uint64_t rawval = ata_get_attr_raw_value(smartval.vendor_attributes[i], cfg.attribute_defs);
2934  if (rawval == 0) {
2935    reset_warning_mail(cfg, state, mailtype, "No more %s", msg);
2936    return;
2937  }
2938
2939  // If attribute is not reset, report only sector count increases.
2940  uint64_t prev_rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs);
2941  if (!(!increase_only || prev_rawval < rawval))
2942    return;
2943
2944  // Format message.
2945  std::string s = strprintf("Device: %s, %"PRId64" %s", cfg.name.c_str(), rawval, msg);
2946  if (prev_rawval > 0 && rawval != prev_rawval)
2947    s += strprintf(" (changed %+"PRId64")", rawval - prev_rawval);
2948
2949  PrintOut(LOG_CRIT, "%s\n", s.c_str());
2950  MailWarning(cfg, state, mailtype, "%s\n", s.c_str());
2951  state.must_write = true;
2952}
2953
2954// Format Temperature value
2955static const char * fmt_temp(unsigned char x, char * buf)
2956{
2957  if (!x) // unset
2958    strcpy(buf, "??");
2959  else
2960    sprintf(buf, "%u", x);
2961  return buf;
2962}
2963
2964// Check Temperature limits
2965static void CheckTemperature(const dev_config & cfg, dev_state & state, unsigned char currtemp, unsigned char triptemp)
2966{
2967  if (!(0 < currtemp && currtemp < 255)) {
2968    PrintOut(LOG_INFO, "Device: %s, failed to read Temperature\n", cfg.name.c_str());
2969    return;
2970  }
2971
2972  // Update Max Temperature
2973  const char * minchg = "", * maxchg = "";
2974  if (currtemp > state.tempmax) {
2975    if (state.tempmax)
2976      maxchg = "!";
2977    state.tempmax = currtemp;
2978    state.must_write = true;
2979  }
2980
2981  char buf[20];
2982  if (!state.temperature) {
2983    // First check
2984    if (!state.tempmin || currtemp < state.tempmin)
2985        // Delay Min Temperature update by ~ 30 minutes.
2986        state.tempmin_delay = time(0) + CHECKTIME - 60;
2987    PrintOut(LOG_INFO, "Device: %s, initial Temperature is %d Celsius (Min/Max %s/%u%s)\n",
2988      cfg.name.c_str(), (int)currtemp, fmt_temp(state.tempmin, buf), state.tempmax, maxchg);
2989    if (triptemp)
2990      PrintOut(LOG_INFO, "    [trip Temperature is %d Celsius]\n", (int)triptemp);
2991    state.temperature = currtemp;
2992  }
2993  else {
2994    if (state.tempmin_delay) {
2995      // End Min Temperature update delay if ...
2996      if (   (state.tempmin && currtemp > state.tempmin) // current temp exceeds recorded min,
2997          || (state.tempmin_delay <= time(0))) {         // or delay time is over.
2998        state.tempmin_delay = 0;
2999        if (!state.tempmin)
3000          state.tempmin = 255;
3001      }
3002    }
3003
3004    // Update Min Temperature
3005    if (!state.tempmin_delay && currtemp < state.tempmin) {
3006      state.tempmin = currtemp;
3007      state.must_write = true;
3008      if (currtemp != state.temperature)
3009        minchg = "!";
3010    }
3011
3012    // Track changes
3013    if (cfg.tempdiff && (*minchg || *maxchg || abs((int)currtemp - (int)state.temperature) >= cfg.tempdiff)) {
3014      PrintOut(LOG_INFO, "Device: %s, Temperature changed %+d Celsius to %u Celsius (Min/Max %s%s/%u%s)\n",
3015        cfg.name.c_str(), (int)currtemp-(int)state.temperature, currtemp, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
3016      state.temperature = currtemp;
3017    }
3018  }
3019
3020  // Check limits
3021  if (cfg.tempcrit && currtemp >= cfg.tempcrit) {
3022    PrintOut(LOG_CRIT, "Device: %s, Temperature %u Celsius reached critical limit of %u Celsius (Min/Max %s%s/%u%s)\n",
3023      cfg.name.c_str(), currtemp, cfg.tempcrit, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
3024    MailWarning(cfg, state, 12, "Device: %s, Temperature %d Celsius reached critical limit of %u Celsius (Min/Max %s%s/%u%s)\n",
3025      cfg.name.c_str(), currtemp, cfg.tempcrit, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
3026  }
3027  else if (cfg.tempinfo && currtemp >= cfg.tempinfo) {
3028    PrintOut(LOG_INFO, "Device: %s, Temperature %u Celsius reached limit of %u Celsius (Min/Max %s%s/%u%s)\n",
3029      cfg.name.c_str(), currtemp, cfg.tempinfo, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
3030  }
3031  else if (cfg.tempcrit) {
3032    unsigned char limit = (cfg.tempinfo ? cfg.tempinfo : cfg.tempcrit-5);
3033    if (currtemp < limit)
3034      reset_warning_mail(cfg, state, 12, "Temperature %u Celsius dropped below %u Celsius", currtemp, limit);
3035  }
3036}
3037
3038// Check normalized and raw attribute values.
3039static void check_attribute(const dev_config & cfg, dev_state & state,
3040                            const ata_smart_attribute & attr,
3041                            const ata_smart_attribute & prev,
3042                            int attridx,
3043                            const ata_smart_threshold_entry * thresholds)
3044{
3045  // Check attribute and threshold
3046  ata_attr_state attrstate = ata_get_attr_state(attr, attridx, thresholds, cfg.attribute_defs);
3047  if (attrstate == ATTRSTATE_NON_EXISTING)
3048    return;
3049
3050  // If requested, check for usage attributes that have failed.
3051  if (   cfg.usagefailed && attrstate == ATTRSTATE_FAILED_NOW
3052      && !cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGN_FAILUSE)) {
3053    std::string attrname = ata_get_smart_attr_name(attr.id, cfg.attribute_defs, cfg.dev_rpm);
3054    PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %d %s.\n", cfg.name.c_str(), attr.id, attrname.c_str());
3055    MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %d %s.", cfg.name.c_str(), attr.id, attrname.c_str());
3056    state.must_write = true;
3057  }
3058
3059  // Return if we're not tracking this type of attribute
3060  bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(attr.flags);
3061  if (!(   ( prefail && cfg.prefail)
3062        || (!prefail && cfg.usage  )))
3063    return;
3064
3065  // Return if '-I ID' was specified
3066  if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGNORE))
3067    return;
3068
3069  // Issue warning if they don't have the same ID in all structures.
3070  if (attr.id != prev.id) {
3071    PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d\n",
3072             cfg.name.c_str(), attr.id, prev.id);
3073    return;
3074  }
3075
3076  // Compare normalized values if valid.
3077  bool valchanged = false;
3078  if (attrstate > ATTRSTATE_NO_NORMVAL) {
3079    if (attr.current != prev.current)
3080      valchanged = true;
3081  }
3082
3083  // Compare raw values if requested.
3084  bool rawchanged = false;
3085  if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW)) {
3086    if (   ata_get_attr_raw_value(attr, cfg.attribute_defs)
3087        != ata_get_attr_raw_value(prev, cfg.attribute_defs))
3088      rawchanged = true;
3089  }
3090
3091  // Return if no change
3092  if (!(valchanged || rawchanged))
3093    return;
3094
3095  // Format value strings
3096  std::string currstr, prevstr;
3097  if (attrstate == ATTRSTATE_NO_NORMVAL) {
3098    // Print raw values only
3099    currstr = strprintf("%s (Raw)",
3100      ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
3101    prevstr = strprintf("%s (Raw)",
3102      ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
3103  }
3104  else if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_PRINT)) {
3105    // Print normalized and raw values
3106    currstr = strprintf("%d [Raw %s]", attr.current,
3107      ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
3108    prevstr = strprintf("%d [Raw %s]", prev.current,
3109      ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
3110  }
3111  else {
3112    // Print normalized values only
3113    currstr = strprintf("%d", attr.current);
3114    prevstr = strprintf("%d", prev.current);
3115  }
3116
3117  // Format message
3118  std::string msg = strprintf("Device: %s, SMART %s Attribute: %d %s changed from %s to %s",
3119                              cfg.name.c_str(), (prefail ? "Prefailure" : "Usage"), attr.id,
3120                              ata_get_smart_attr_name(attr.id, cfg.attribute_defs, cfg.dev_rpm).c_str(),
3121                              prevstr.c_str(), currstr.c_str());
3122
3123  // Report this change as critical ?
3124  if (   (valchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_AS_CRIT))
3125      || (rawchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_AS_CRIT))) {
3126    PrintOut(LOG_CRIT, "%s\n", msg.c_str());
3127    MailWarning(cfg, state, 2, "%s", msg.c_str());
3128  }
3129  else {
3130    PrintOut(LOG_INFO, "%s\n", msg.c_str());
3131  }
3132  state.must_write = true;
3133}
3134
3135
3136static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device * atadev,
3137                          bool firstpass, bool allow_selftests)
3138{
3139  const char * name = cfg.name.c_str();
3140
3141  // If user has asked, test the email warning system
3142  if (cfg.emailtest)
3143    MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name);
3144
3145  // if we can't open device, fail gracefully rather than hard --
3146  // perhaps the next time around we'll be able to open it.  ATAPI
3147  // cd/dvd devices will hang awaiting media if O_NONBLOCK is not
3148  // given (see linux cdrom driver).
3149  if (!atadev->open()) {
3150    PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", name, atadev->get_errmsg());
3151    MailWarning(cfg, state, 9, "Device: %s, unable to open device", name);
3152    return 1;
3153  }
3154  if (debugmode)
3155    PrintOut(LOG_INFO,"Device: %s, opened ATA device\n", name);
3156  reset_warning_mail(cfg, state, 9, "open device worked again");
3157
3158  // user may have requested (with the -n Directive) to leave the disk
3159  // alone if it is in idle or sleeping mode.  In this case check the
3160  // power mode and exit without check if needed
3161  if (cfg.powermode && !state.powermodefail) {
3162    int dontcheck=0, powermode=ataCheckPowerMode(atadev);
3163    const char * mode = 0;
3164    if (0 <= powermode && powermode < 0xff) {
3165      // wait for possible spin up and check again
3166      int powermode2;
3167      sleep(5);
3168      powermode2 = ataCheckPowerMode(atadev);
3169      if (powermode2 > powermode)
3170        PrintOut(LOG_INFO, "Device: %s, CHECK POWER STATUS spins up disk (0x%02x -> 0x%02x)\n", name, powermode, powermode2);
3171      powermode = powermode2;
3172    }
3173       
3174    switch (powermode){
3175    case -1:
3176      // SLEEP
3177      mode="SLEEP";
3178      if (cfg.powermode>=1)
3179        dontcheck=1;
3180      break;
3181    case 0:
3182      // STANDBY
3183      mode="STANDBY";
3184      if (cfg.powermode>=2)
3185        dontcheck=1;
3186      break;
3187    case 0x80:
3188      // IDLE
3189      mode="IDLE";
3190      if (cfg.powermode>=3)
3191        dontcheck=1;
3192      break;
3193    case 0xff:
3194      // ACTIVE/IDLE
3195      mode="ACTIVE or IDLE";
3196      break;
3197    default:
3198      // UNKNOWN
3199      PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n",
3200        name, powermode);
3201      state.powermodefail = true;
3202      break;
3203    }
3204
3205    // if we are going to skip a check, return now
3206    if (dontcheck){
3207      // skip at most powerskipmax checks
3208      if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) {
3209        CloseDevice(atadev, name);
3210        if (!state.powerskipcnt && !cfg.powerquiet) // report first only and avoid waking up system disk
3211          PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, mode);
3212        state.powerskipcnt++;
3213        return 0;
3214      }
3215      else {
3216        PrintOut(LOG_INFO, "Device: %s, %s mode ignored due to reached limit of skipped checks (%d check%s skipped)\n",
3217          name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s"));
3218      }
3219      state.powerskipcnt = 0;
3220      state.tempmin_delay = time(0) + CHECKTIME - 60; // Delay Min Temperature update
3221    }
3222    else if (state.powerskipcnt) {
3223      PrintOut(LOG_INFO, "Device: %s, is back in %s mode, resuming checks (%d check%s skipped)\n",
3224        name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s"));
3225      state.powerskipcnt = 0;
3226      state.tempmin_delay = time(0) + CHECKTIME - 60; // Delay Min Temperature update
3227    }
3228  }
3229
3230  // check smart status
3231  if (cfg.smartcheck) {
3232    int status=ataSmartStatus2(atadev);
3233    if (status==-1){
3234      PrintOut(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name);
3235      MailWarning(cfg, state, 5, "Device: %s, not capable of SMART self-check", name);
3236      state.must_write = true;
3237    }
3238    else if (status==1){
3239      PrintOut(LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name);
3240      MailWarning(cfg, state, 1, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!", name);
3241      state.must_write = true;
3242    }
3243  }
3244 
3245  // Check everything that depends upon SMART Data (eg, Attribute values)
3246  if (   cfg.usagefailed || cfg.prefail || cfg.usage
3247      || cfg.curr_pending_id || cfg.offl_pending_id
3248      || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit
3249      || cfg.selftest ||  cfg.offlinests || cfg.selfteststs) {
3250
3251    // Read current attribute values.
3252    ata_smart_values curval;
3253    if (ataReadSmartValues(atadev, &curval)){
3254      PrintOut(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name);
3255      MailWarning(cfg, state, 6, "Device: %s, failed to read SMART Attribute Data", name);
3256      state.must_write = true;
3257    }
3258    else {
3259      reset_warning_mail(cfg, state, 6, "read SMART Attribute Data worked again");
3260
3261      // look for current or offline pending sectors
3262      if (cfg.curr_pending_id)
3263        check_pending(cfg, state, cfg.curr_pending_id, cfg.curr_pending_incr, curval, 10,
3264                      (!cfg.curr_pending_incr ? "Currently unreadable (pending) sectors"
3265                                              : "Total unreadable (pending) sectors"    ));
3266
3267      if (cfg.offl_pending_id)
3268        check_pending(cfg, state, cfg.offl_pending_id, cfg.offl_pending_incr, curval, 11,
3269                      (!cfg.offl_pending_incr ? "Offline uncorrectable sectors"
3270                                              : "Total offline uncorrectable sectors"));
3271
3272      // check temperature limits
3273      if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
3274        CheckTemperature(cfg, state, ata_return_temperature_value(&curval, cfg.attribute_defs), 0);
3275
3276      // look for failed usage attributes, or track usage or prefail attributes
3277      if (cfg.usagefailed || cfg.prefail || cfg.usage) {
3278        for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
3279          check_attribute(cfg, state,
3280                          curval.vendor_attributes[i],
3281                          state.smartval.vendor_attributes[i],
3282                          i, state.smartthres.thres_entries);
3283        }
3284      }
3285
3286      // Log changes of offline data collection status
3287      if (cfg.offlinests) {
3288        if (   curval.offline_data_collection_status
3289                != state.smartval.offline_data_collection_status
3290            || state.offline_started // test was started in previous call
3291            || (firstpass && (debugmode || (curval.offline_data_collection_status & 0x7d))))
3292          log_offline_data_coll_status(name, curval.offline_data_collection_status);
3293      }
3294
3295      // Log changes of self-test execution status
3296      if (cfg.selfteststs) {
3297        if (   curval.self_test_exec_status != state.smartval.self_test_exec_status
3298            || state.selftest_started // test was started in previous call
3299            || (firstpass && (debugmode || curval.self_test_exec_status != 0x00)))
3300          log_self_test_exec_status(name, curval.self_test_exec_status);
3301      }
3302
3303      // Save the new values for the next time around
3304      state.smartval = curval;
3305    }
3306  }
3307  state.offline_started = state.selftest_started = false;
3308 
3309  // check if number of selftest errors has increased (note: may also DECREASE)
3310  if (cfg.selftest)
3311    CheckSelfTestLogs(cfg, state, SelfTestErrorCount(atadev, name, cfg.firmwarebugs));
3312
3313  // check if number of ATA errors has increased
3314  if (cfg.errorlog || cfg.xerrorlog) {
3315
3316    int errcnt1 = -1, errcnt2 = -1;
3317    if (cfg.errorlog)
3318      errcnt1 = read_ata_error_count(atadev, name, cfg.firmwarebugs, false);
3319    if (cfg.xerrorlog)
3320      errcnt2 = read_ata_error_count(atadev, name, cfg.firmwarebugs, true);
3321
3322    // new number of errors is max of both logs
3323    int newc = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2);
3324
3325    // did command fail?
3326    if (newc<0)
3327      // lack of PrintOut here is INTENTIONAL
3328      MailWarning(cfg, state, 7, "Device: %s, Read SMART Error Log Failed", name);
3329
3330    // has error count increased?
3331    int oldc = state.ataerrorcount;
3332    if (newc>oldc){
3333      PrintOut(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
3334               name, oldc, newc);
3335      MailWarning(cfg, state, 4, "Device: %s, ATA error count increased from %d to %d",
3336                   name, oldc, newc);
3337      state.must_write = true;
3338    }
3339
3340    if (newc>=0)
3341      state.ataerrorcount=newc;
3342  }
3343
3344  // if the user has asked, and device is capable (or we're not yet
3345  // sure) check whether a self test should be done now.
3346  if (allow_selftests && !cfg.test_regex.empty()) {
3347    char testtype = next_scheduled_test(cfg, state, false/*!scsi*/);
3348    if (testtype)
3349      DoATASelfTest(cfg, state, atadev, testtype);
3350  }
3351
3352  // Don't leave device open -- the OS/user may want to access it
3353  // before the next smartd cycle!
3354  CloseDevice(atadev, name);
3355
3356  // Copy ATA attribute values to persistent state
3357  state.update_persistent_state();
3358
3359  return 0;
3360}
3361
3362static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_device * scsidev, bool allow_selftests)
3363{
3364    UINT8 asc, ascq;
3365    UINT8 currenttemp;
3366    UINT8 triptemp;
3367    const char * name = cfg.name.c_str();
3368    const char *cp;
3369
3370    // If the user has asked for it, test the email warning system
3371    if (cfg.emailtest)
3372      MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name);
3373
3374    // if we can't open device, fail gracefully rather than hard --
3375    // perhaps the next time around we'll be able to open it
3376    if (!scsidev->open()) {
3377      PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", name, scsidev->get_errmsg());
3378      MailWarning(cfg, state, 9, "Device: %s, unable to open device", name);
3379      return 1;
3380    } else if (debugmode)
3381        PrintOut(LOG_INFO,"Device: %s, opened SCSI device\n", name);
3382    currenttemp = 0;
3383    asc = 0;
3384    ascq = 0;
3385    if (!state.SuppressReport) {
3386        if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported,
3387                        &asc, &ascq, &currenttemp, &triptemp)) {
3388            PrintOut(LOG_INFO, "Device: %s, failed to read SMART values\n",
3389                      name);
3390            MailWarning(cfg, state, 6, "Device: %s, failed to read SMART values", name);
3391            state.SuppressReport = 1;
3392        }
3393    }
3394    if (asc > 0) {
3395        cp = scsiGetIEString(asc, ascq);
3396        if (cp) {
3397            PrintOut(LOG_CRIT, "Device: %s, SMART Failure: %s\n", name, cp);
3398            MailWarning(cfg, state, 1,"Device: %s, SMART Failure: %s", name, cp);
3399        } else if (debugmode)
3400            PrintOut(LOG_INFO,"Device: %s, non-SMART asc,ascq: %d,%d\n",
3401                     name, (int)asc, (int)ascq); 
3402    } else if (debugmode)
3403        PrintOut(LOG_INFO,"Device: %s, SMART health: passed\n", name); 
3404
3405    // check temperature limits
3406    if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
3407      CheckTemperature(cfg, state, currenttemp, triptemp);
3408
3409    // check if number of selftest errors has increased (note: may also DECREASE)
3410    if (cfg.selftest)
3411      CheckSelfTestLogs(cfg, state, scsiCountFailedSelfTests(scsidev, 0));
3412   
3413    if (allow_selftests && !cfg.test_regex.empty()) {
3414      char testtype = next_scheduled_test(cfg, state, true/*scsi*/);
3415      if (testtype)
3416        DoSCSISelfTest(cfg, state, scsidev, testtype);
3417    }
3418    CloseDevice(scsidev, name);
3419    return 0;
3420}
3421
3422// 0=not used, 1=not disabled, 2=disable rejected by OS, 3=disabled
3423static int standby_disable_state = 0;
3424
3425static void init_disable_standby_check(dev_config_vector & configs)
3426{
3427  // Check for '-l offlinests,ns' or '-l selfteststs,ns' directives
3428  bool sts1 = false, sts2 = false;
3429  for (unsigned i = 0; i < configs.size() && !(sts1 || sts2); i++) {
3430    const dev_config & cfg = configs.at(i);
3431    if (cfg.offlinests_ns)
3432      sts1 = true;
3433    if (cfg.selfteststs_ns)
3434      sts2 = true;
3435  }
3436
3437  // Check for support of disable auto standby
3438  // Reenable standby if smartd.conf was reread
3439  if (sts1 || sts2 || standby_disable_state == 3) {
3440   if (!smi()->disable_system_auto_standby(false)) {
3441      if (standby_disable_state == 3)
3442        PrintOut(LOG_CRIT, "System auto standby enable failed: %s\n", smi()->get_errmsg());
3443      if (sts1 || sts2) {
3444        PrintOut(LOG_INFO, "Disable auto standby not supported, ignoring ',ns' from %s%s%s\n",
3445          (sts1 ? "-l offlinests,ns" : ""), (sts1 && sts2 ? " and " : ""), (sts2 ? "-l selfteststs,ns" : ""));
3446        sts1 = sts2 = false;
3447      }
3448    }
3449  }
3450
3451  standby_disable_state = (sts1 || sts2 ? 1 : 0);
3452}
3453
3454static void do_disable_standby_check(const dev_config_vector & configs, const dev_state_vector & states)
3455{
3456  if (!standby_disable_state)
3457    return;
3458
3459  // Check for just started or still running self-tests
3460  bool running = false;
3461  for (unsigned i = 0; i < configs.size() && !running; i++) {
3462    const dev_config & cfg = configs.at(i); const dev_state & state = states.at(i);
3463
3464    if (   (   cfg.offlinests_ns
3465            && (state.offline_started ||
3466                is_offl_coll_in_progress(state.smartval.offline_data_collection_status)))
3467        || (   cfg.selfteststs_ns
3468            && (state.selftest_started ||
3469                is_self_test_in_progress(state.smartval.self_test_exec_status)))         )
3470      running = true;
3471    // state.offline/selftest_started will be reset after next logging of test status
3472  }
3473
3474  // Disable/enable auto standby and log state changes
3475  if (!running) {
3476    if (standby_disable_state != 1) {
3477      if (!smi()->disable_system_auto_standby(false))
3478        PrintOut(LOG_CRIT, "Self-test(s) completed, system auto standby enable failed: %s\n",
3479                 smi()->get_errmsg());
3480      else
3481        PrintOut(LOG_INFO, "Self-test(s) completed, system auto standby enabled\n");
3482      standby_disable_state = 1;
3483    }
3484  }
3485  else if (!smi()->disable_system_auto_standby(true)) {
3486    if (standby_disable_state != 2) {
3487      PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disable rejected: %s\n",
3488               smi()->get_errmsg());
3489      standby_disable_state = 2;
3490    }
3491  }
3492  else {
3493    if (standby_disable_state != 3) {
3494      PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disabled\n");
3495      standby_disable_state = 3;
3496    }
3497  }
3498}
3499
3500// Checks the SMART status of all ATA and SCSI devices
3501static void CheckDevicesOnce(const dev_config_vector & configs, dev_state_vector & states,
3502                             smart_device_list & devices, bool firstpass, bool allow_selftests)
3503{
3504  for (unsigned i = 0; i < configs.size(); i++) {
3505    const dev_config & cfg = configs.at(i);
3506    dev_state & state = states.at(i);
3507    smart_device * dev = devices.at(i);
3508    if (dev->is_ata())
3509      ATACheckDevice(cfg, state, dev->to_ata(), firstpass, allow_selftests);
3510    else if (dev->is_scsi())
3511      SCSICheckDevice(cfg, state, dev->to_scsi(), allow_selftests);
3512  }
3513
3514  do_disable_standby_check(configs, states);
3515}
3516
3517// Set if Initialize() was called
3518static bool is_initialized = false;
3519
3520// Does initialization right after fork to daemon mode
3521static void Initialize(time_t *wakeuptime)
3522{
3523  // Call Goodbye() on exit
3524  is_initialized = true;
3525 
3526  // write PID file
3527  if (!debugmode)
3528    WritePidFile();
3529 
3530  // install signal handlers.  On Solaris, can't use signal() because
3531  // it resets the handler to SIG_DFL after each call.  So use sigset()
3532  // instead.  So SIGNALFN()==signal() or SIGNALFN()==sigset().
3533 
3534  // normal and abnormal exit
3535  if (SIGNALFN(SIGTERM, sighandler)==SIG_IGN)
3536    SIGNALFN(SIGTERM, SIG_IGN);
3537  if (SIGNALFN(SIGQUIT, sighandler)==SIG_IGN)
3538    SIGNALFN(SIGQUIT, SIG_IGN);
3539 
3540  // in debug mode, <CONTROL-C> ==> HUP
3541  if (SIGNALFN(SIGINT, debugmode?HUPhandler:sighandler)==SIG_IGN)
3542    SIGNALFN(SIGINT, SIG_IGN);
3543 
3544  // Catch HUP and USR1
3545  if (SIGNALFN(SIGHUP, HUPhandler)==SIG_IGN)
3546    SIGNALFN(SIGHUP, SIG_IGN);
3547  if (SIGNALFN(SIGUSR1, USR1handler)==SIG_IGN)
3548    SIGNALFN(SIGUSR1, SIG_IGN);
3549#ifdef _WIN32
3550  if (SIGNALFN(SIGUSR2, USR2handler)==SIG_IGN)
3551    SIGNALFN(SIGUSR2, SIG_IGN);
3552#endif
3553
3554  // initialize wakeup time to CURRENT time
3555  *wakeuptime=time(NULL);
3556 
3557  return;
3558}
3559
3560#ifdef _WIN32
3561// Toggle debug mode implemented for native windows only
3562// (there is no easy way to reopen tty on *nix)
3563static void ToggleDebugMode()
3564{
3565  if (!debugmode) {
3566    PrintOut(LOG_INFO,"Signal USR2 - enabling debug mode\n");
3567    if (!daemon_enable_console("smartd [Debug]")) {
3568      debugmode = 1;
3569      daemon_signal(SIGINT, HUPhandler);
3570      PrintOut(LOG_INFO,"smartd debug mode enabled, PID=%d\n", getpid());
3571    }
3572    else
3573      PrintOut(LOG_INFO,"enable console failed\n");
3574  }
3575  else if (debugmode == 1) {
3576    daemon_disable_console();
3577    debugmode = 0;
3578    daemon_signal(SIGINT, sighandler);
3579    PrintOut(LOG_INFO,"Signal USR2 - debug mode disabled\n");
3580  }
3581  else
3582    PrintOut(LOG_INFO,"Signal USR2 - debug mode %d not changed\n", debugmode);
3583}
3584#endif
3585
3586static time_t dosleep(time_t wakeuptime, bool & sigwakeup)
3587{
3588  // If past wake-up-time, compute next wake-up-time
3589  time_t timenow=time(NULL);
3590  while (wakeuptime<=timenow){
3591    int intervals=1+(timenow-wakeuptime)/checktime;
3592    wakeuptime+=intervals*checktime;
3593  }
3594 
3595  // sleep until we catch SIGUSR1 or have completed sleeping
3596  int addtime = 0;
3597  while (timenow < wakeuptime+addtime && !caughtsigUSR1 && !caughtsigHUP && !caughtsigEXIT) {
3598   
3599    // protect user again system clock being adjusted backwards
3600    if (wakeuptime>timenow+checktime){
3601      PrintOut(LOG_CRIT, "System clock time adjusted to the past. Resetting next wakeup time.\n");
3602      wakeuptime=timenow+checktime;
3603    }
3604   
3605    // Exit sleep when time interval has expired or a signal is received
3606    sleep(wakeuptime+addtime-timenow);
3607
3608#ifdef _WIN32
3609    // toggle debug mode?
3610    if (caughtsigUSR2) {
3611      ToggleDebugMode();
3612      caughtsigUSR2 = 0;
3613    }
3614#endif
3615
3616    timenow=time(NULL);
3617
3618    // Actual sleep time too long?
3619    if (!addtime && timenow > wakeuptime+60) {
3620      if (debugmode)
3621        PrintOut(LOG_INFO, "Sleep time was %d seconds too long, assuming wakeup from standby mode.\n",
3622          (int)(timenow-wakeuptime));
3623      // Wait another 20 seconds to avoid I/O errors during disk spin-up
3624      addtime = timenow-wakeuptime+20;
3625      // Use next wake-up-time if close
3626      int nextcheck = checktime - addtime % checktime;
3627      if (nextcheck <= 20)
3628        addtime += nextcheck;
3629    }
3630  }
3631 
3632  // if we caught a SIGUSR1 then print message and clear signal
3633  if (caughtsigUSR1){
3634    PrintOut(LOG_INFO,"Signal USR1 - checking devices now rather than in %d seconds.\n",
3635             wakeuptime-timenow>0?(int)(wakeuptime-timenow):0);
3636    caughtsigUSR1=0;
3637    sigwakeup = true;
3638  }
3639 
3640  // return adjusted wakeuptime
3641  return wakeuptime;
3642}
3643
3644// Print out a list of valid arguments for the Directive d
3645static void printoutvaliddirectiveargs(int priority, char d)
3646{
3647  switch (d) {
3648  case 'n':
3649    PrintOut(priority, "never[,N][,q], sleep[,N][,q], standby[,N][,q], idle[,N][,q]");
3650    break;
3651  case 's':
3652    PrintOut(priority, "valid_regular_expression");
3653    break;
3654  case 'd':
3655    PrintOut(priority, "%s", smi()->get_valid_dev_types_str().c_str());
3656    break;
3657  case 'T':
3658    PrintOut(priority, "normal, permissive");
3659    break;
3660  case 'o':
3661  case 'S':
3662    PrintOut(priority, "on, off");
3663    break;
3664  case 'l':
3665    PrintOut(priority, "error, selftest");
3666    break;
3667  case 'M':
3668    PrintOut(priority, "\"once\", \"daily\", \"diminishing\", \"test\", \"exec\"");
3669    break;
3670  case 'v':
3671    PrintOut(priority, "\n%s\n", create_vendor_attribute_arg_list().c_str());
3672    break;
3673  case 'P':
3674    PrintOut(priority, "use, ignore, show, showall");
3675    break;
3676  case 'F':
3677    PrintOut(priority, "%s", get_valid_firmwarebug_args());
3678    break;
3679  case 'e':
3680    PrintOut(priority, "aam,[N|off], apm,[N|off], lookahead,[on|off], "
3681                       "security-freeze, standby,[N|off], wcache,[on|off]");
3682    break;
3683  }
3684}
3685
3686// exits with an error message, or returns integer value of token
3687static int GetInteger(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile,
3688               int min, int max, char * suffix = 0)
3689{
3690  // make sure argument is there
3691  if (!arg) {
3692    PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes integer argument from %d to %d.\n",
3693             cfgfile, lineno, name, token, min, max);
3694    return -1;
3695  }
3696 
3697  // get argument value (base 10), check that it's integer, and in-range
3698  char *endptr;
3699  int val = strtol(arg,&endptr,10);
3700
3701  // optional suffix present?
3702  if (suffix) {
3703    if (!strcmp(endptr, suffix))
3704      endptr += strlen(suffix);
3705    else
3706      *suffix = 0;
3707  }
3708
3709  if (!(!*endptr && min <= val && val <= max)) {
3710    PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n",
3711             cfgfile, lineno, name, token, arg, min, max);
3712    return -1;
3713  }
3714
3715  // all is well; return value
3716  return val;
3717}
3718
3719
3720// Get 1-3 small integer(s) for '-W' directive
3721static int Get3Integers(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile,
3722                 unsigned char *val1, unsigned char *val2, unsigned char *val3)
3723{
3724  unsigned v1 = 0, v2 = 0, v3 = 0;
3725  int n1 = -1, n2 = -1, n3 = -1, len;
3726  if (!arg) {
3727    PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes 1-3 integer argument(s) from 0 to 255.\n",
3728             cfgfile, lineno, name, token);
3729    return -1;
3730  }
3731
3732  len = strlen(arg);
3733  if (!(   sscanf(arg, "%u%n,%u%n,%u%n", &v1, &n1, &v2, &n2, &v3, &n3) >= 1
3734        && (n1 == len || n2 == len || n3 == len) && v1 <= 255 && v2 <= 255 && v3 <= 255)) {
3735    PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs 1-3 integer(s) from 0 to 255.\n",
3736             cfgfile, lineno, name, token, arg);
3737    return -1;
3738  }
3739  *val1 = (unsigned char)v1; *val2 = (unsigned char)v2; *val3 = (unsigned char)v3;
3740  return 0;
3741}
3742
3743
3744#ifdef _WIN32
3745
3746// Concatenate strtok() results if quoted with "..."
3747static const char * strtok_dequote(const char * delimiters)
3748{
3749  const char * t = strtok(0, delimiters);
3750  if (!t || t[0] != '"')
3751    return t;
3752
3753  static std::string token;
3754  token = t+1;
3755  for (;;) {
3756    t = strtok(0, delimiters);
3757    if (!t || !*t)
3758      return "\"";
3759    token += ' ';
3760    int len = strlen(t);
3761    if (t[len-1] == '"') {
3762      token += std::string(t, len-1);
3763      break;
3764    }
3765    token += t;
3766  }
3767  return token.c_str();
3768}
3769
3770#endif // _WIN32
3771
3772
3773// This function returns 1 if it has correctly parsed one token (and
3774// any arguments), else zero if no tokens remain.  It returns -1 if an
3775// error was encountered.
3776static int ParseToken(char * token, dev_config & cfg)
3777{
3778  char sym;
3779  const char * name = cfg.name.c_str();
3780  int lineno=cfg.lineno;
3781  const char *delim = " \n\t";
3782  int badarg = 0;
3783  int missingarg = 0;
3784  const char *arg = 0;
3785
3786  // is the rest of the line a comment
3787  if (*token=='#')
3788    return 1;
3789 
3790  // is the token not recognized?
3791  if (*token!='-' || strlen(token)!=2) {
3792    PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
3793             configfile, lineno, name, token);
3794    PrintOut(LOG_CRIT, "Run smartd -D to print a list of valid Directives.\n");
3795    return -1;
3796  }
3797 
3798  // token we will be parsing:
3799  sym=token[1];
3800
3801  // parse the token and swallow its argument
3802  int val;
3803  char plus[] = "+", excl[] = "!";
3804
3805  switch (sym) {
3806  case 'C':
3807    // monitor current pending sector count (default 197)
3808    if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255, plus)) < 0)
3809      return -1;
3810    cfg.curr_pending_id = (unsigned char)val;
3811    cfg.curr_pending_incr = (*plus == '+');
3812    cfg.curr_pending_set = true;
3813    break;
3814  case 'U':
3815    // monitor offline uncorrectable sectors (default 198)
3816    if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255, plus)) < 0)
3817      return -1;
3818    cfg.offl_pending_id = (unsigned char)val;
3819    cfg.offl_pending_incr = (*plus == '+');
3820    cfg.offl_pending_set = true;
3821    break;
3822  case 'T':
3823    // Set tolerance level for SMART command failures
3824    if ((arg = strtok(NULL, delim)) == NULL) {
3825      missingarg = 1;
3826    } else if (!strcmp(arg, "normal")) {
3827      // Normal mode: exit on failure of a mandatory S.M.A.R.T. command, but
3828      // not on failure of an optional S.M.A.R.T. command.
3829      // This is the default so we don't need to actually do anything here.
3830      cfg.permissive = false;
3831    } else if (!strcmp(arg, "permissive")) {
3832      // Permissive mode; ignore errors from Mandatory SMART commands
3833      cfg.permissive = true;
3834    } else {
3835      badarg = 1;
3836    }
3837    break;
3838  case 'd':
3839    // specify the device type
3840    if ((arg = strtok(NULL, delim)) == NULL) {
3841      missingarg = 1;
3842    } else if (!strcmp(arg, "removable")) {
3843      cfg.removable = true;
3844    } else if (!strcmp(arg, "auto")) {
3845      cfg.dev_type = "";
3846    } else {
3847      cfg.dev_type = arg;
3848    }
3849    break;
3850  case 'F':
3851    // fix firmware bug
3852    if (!(arg = strtok(0, delim)))
3853      missingarg = 1;
3854    else if (!parse_firmwarebug_def(arg, cfg.firmwarebugs))
3855      badarg = 1;
3856    break;
3857  case 'H':
3858    // check SMART status
3859    cfg.smartcheck = true;
3860    break;
3861  case 'f':
3862    // check for failure of usage attributes
3863    cfg.usagefailed = true;
3864    break;
3865  case 't':
3866    // track changes in all vendor attributes
3867    cfg.prefail = true;
3868    cfg.usage = true;
3869    break;
3870  case 'p':
3871    // track changes in prefail vendor attributes
3872    cfg.prefail = true;
3873    break;
3874  case 'u':
3875    //  track changes in usage vendor attributes
3876    cfg.usage = true;
3877    break;
3878  case 'l':
3879    // track changes in SMART logs
3880    if ((arg = strtok(NULL, delim)) == NULL) {
3881      missingarg = 1;
3882    } else if (!strcmp(arg, "selftest")) {
3883      // track changes in self-test log
3884      cfg.selftest = true;
3885    } else if (!strcmp(arg, "error")) {
3886      // track changes in ATA error log
3887      cfg.errorlog = true;
3888    } else if (!strcmp(arg, "xerror")) {
3889      // track changes in Extended Comprehensive SMART error log
3890      cfg.xerrorlog = true;
3891    } else if (!strcmp(arg, "offlinests")) {
3892      // track changes in offline data collection status
3893      cfg.offlinests = true;
3894    } else if (!strcmp(arg, "offlinests,ns")) {
3895      // track changes in offline data collection status, disable auto standby
3896      cfg.offlinests = cfg.offlinests_ns = true;
3897    } else if (!strcmp(arg, "selfteststs")) {
3898      // track changes in self-test execution status
3899      cfg.selfteststs = true;
3900    } else if (!strcmp(arg, "selfteststs,ns")) {
3901      // track changes in self-test execution status, disable auto standby
3902      cfg.selfteststs = cfg.selfteststs_ns = true;
3903    } else if (!strncmp(arg, "scterc,", sizeof("scterc,")-1)) {
3904        // set SCT Error Recovery Control
3905        unsigned rt = ~0, wt = ~0; int nc = -1;
3906        sscanf(arg,"scterc,%u,%u%n", &rt, &wt, &nc);
3907        if (nc == (int)strlen(arg) && rt <= 999 && wt <= 999) {
3908          cfg.sct_erc_set = true;
3909          cfg.sct_erc_readtime = rt;
3910          cfg.sct_erc_writetime = wt;
3911        }
3912        else
3913          badarg = 1;
3914    } else {
3915      badarg = 1;
3916    }
3917    break;
3918  case 'a':
3919    // monitor everything
3920    cfg.smartcheck = true;
3921    cfg.prefail = true;
3922    cfg.usagefailed = true;
3923    cfg.usage = true;
3924    cfg.selftest = true;
3925    cfg.errorlog = true;
3926    cfg.selfteststs = true;
3927    break;
3928  case 'o':
3929    // automatic offline testing enable/disable
3930    if ((arg = strtok(NULL, delim)) == NULL) {
3931      missingarg = 1;
3932    } else if (!strcmp(arg, "on")) {
3933      cfg.autoofflinetest = 2;
3934    } else if (!strcmp(arg, "off")) {
3935      cfg.autoofflinetest = 1;
3936    } else {
3937      badarg = 1;
3938    }
3939    break;
3940  case 'n':
3941    // skip disk check if in idle or standby mode
3942    if (!(arg = strtok(NULL, delim)))
3943      missingarg = 1;
3944    else {
3945      char *endptr = NULL;
3946      char *next = strchr(const_cast<char*>(arg), ',');
3947
3948      cfg.powerquiet = false;
3949      cfg.powerskipmax = 0;
3950
3951      if (next!=NULL) *next='\0';
3952      if (!strcmp(arg, "never"))
3953        cfg.powermode = 0;
3954      else if (!strcmp(arg, "sleep"))
3955        cfg.powermode = 1;
3956      else if (!strcmp(arg, "standby"))
3957        cfg.powermode = 2;
3958      else if (!strcmp(arg, "idle"))
3959        cfg.powermode = 3;
3960      else
3961        badarg = 1;
3962
3963      // if optional arguments are present
3964      if (!badarg && next!=NULL) {
3965        next++;
3966        cfg.powerskipmax = strtol(next, &endptr, 10);
3967        if (endptr == next)
3968          cfg.powerskipmax = 0;
3969        else {
3970          next = endptr + (*endptr != '\0');
3971          if (cfg.powerskipmax <= 0)
3972            badarg = 1;
3973        }
3974        if (*next != '\0') {
3975          if (!strcmp("q", next))
3976            cfg.powerquiet = true;
3977          else {
3978            badarg = 1;
3979          }
3980        }
3981      }
3982    }
3983    break;
3984  case 'S':
3985    // automatic attribute autosave enable/disable
3986    if ((arg = strtok(NULL, delim)) == NULL) {
3987      missingarg = 1;
3988    } else if (!strcmp(arg, "on")) {
3989      cfg.autosave = 2;
3990    } else if (!strcmp(arg, "off")) {
3991      cfg.autosave = 1;
3992    } else {
3993      badarg = 1;
3994    }
3995    break;
3996  case 's':
3997    // warn user, and delete any previously given -s REGEXP Directives
3998    if (!cfg.test_regex.empty()){
3999      PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Test Directive -s %s\n",
4000               configfile, lineno, name, cfg.test_regex.get_pattern());
4001      cfg.test_regex = regular_expression();
4002    }
4003    // check for missing argument
4004    if (!(arg = strtok(NULL, delim))) {
4005      missingarg = 1;
4006    }
4007    // Compile regex
4008    else {
4009      if (!cfg.test_regex.compile(arg, REG_EXTENDED)) {
4010        // not a valid regular expression!
4011        PrintOut(LOG_CRIT, "File %s line %d (drive %s): -s argument \"%s\" is INVALID extended regular expression. %s.\n",
4012                 configfile, lineno, name, arg, cfg.test_regex.get_errmsg());
4013        return -1;
4014      }
4015    }
4016    // Do a bit of sanity checking and warn user if we think that
4017    // their regexp is "strange". User probably confused about shell
4018    // glob(3) syntax versus regular expression syntax regexp(7).
4019    if (arg[(val = strspn(arg, "0123456789/.-+*|()?^$[]SLCOcnr"))])
4020      PrintOut(LOG_INFO,  "File %s line %d (drive %s): warning, character %d (%c) looks odd in extended regular expression %s\n",
4021               configfile, lineno, name, val+1, arg[val], arg);
4022    break;
4023  case 'm':
4024    // send email to address that follows
4025    if (!(arg = strtok(NULL,delim)))
4026      missingarg = 1;
4027    else {
4028      if (!cfg.emailaddress.empty())
4029        PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Address Directive -m %s\n",
4030                 configfile, lineno, name, cfg.emailaddress.c_str());
4031#ifdef _WIN32
4032      if (   !strcmp(arg, "msgbox")          || !strcmp(arg, "sysmsgbox")
4033          || str_starts_with(arg, "msgbox,") || str_starts_with(arg, "sysmsgbox,")) {
4034        cfg.emailaddress = "console";
4035        const char * arg2 = strchr(arg, ',');
4036        if (arg2)
4037          cfg.emailaddress += arg2;
4038        PrintOut(LOG_INFO, "File %s line %d (drive %s): Deprecated -m %s changed to -m %s\n",
4039                 configfile, lineno, name, arg, cfg.emailaddress.c_str());
4040      }
4041      else
4042#endif
4043      cfg.emailaddress = arg;
4044    }
4045    break;
4046  case 'M':
4047    // email warning options
4048    if (!(arg = strtok(NULL, delim)))
4049      missingarg = 1;
4050    else if (!strcmp(arg, "once"))
4051      cfg.emailfreq = 1;
4052    else if (!strcmp(arg, "daily"))
4053      cfg.emailfreq = 2;
4054    else if (!strcmp(arg, "diminishing"))
4055      cfg.emailfreq = 3;
4056    else if (!strcmp(arg, "test"))
4057      cfg.emailtest = 1;
4058    else if (!strcmp(arg, "exec")) {
4059      // Get the next argument (the command line)
4060#ifdef _WIN32
4061      // Allow "/path name/with spaces/..." on Windows
4062      arg = strtok_dequote(delim);
4063      if (arg && arg[0] == '"') {
4064        PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive %s 'exec' argument: missing closing quote\n",
4065                 configfile, lineno, name, token);
4066        return -1;
4067      }
4068#else
4069      arg = strtok(0, delim);
4070#endif
4071      if (!arg) {
4072        PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive %s 'exec' argument must be followed by executable path.\n",
4073                 configfile, lineno, name, token);
4074        return -1;
4075      }
4076      // Free the last cmd line given if any, and copy new one
4077      if (!cfg.emailcmdline.empty())
4078        PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous mail Directive -M exec %s\n",
4079                 configfile, lineno, name, cfg.emailcmdline.c_str());
4080      cfg.emailcmdline = arg;
4081    } 
4082    else
4083      badarg = 1;
4084    break;
4085  case 'i':
4086    // ignore failure of usage attribute
4087    if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0)
4088      return -1;
4089    cfg.monitor_attr_flags.set(val, MONITOR_IGN_FAILUSE);
4090    break;
4091  case 'I':
4092    // ignore attribute for tracking purposes
4093    if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0)
4094      return -1;
4095    cfg.monitor_attr_flags.set(val, MONITOR_IGNORE);
4096    break;
4097  case 'r':
4098    // print raw value when tracking
4099    if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255, excl)) < 0)
4100      return -1;
4101    cfg.monitor_attr_flags.set(val, MONITOR_RAW_PRINT);
4102    if (*excl == '!') // attribute change is critical
4103      cfg.monitor_attr_flags.set(val, MONITOR_AS_CRIT);
4104    break;
4105  case 'R':
4106    // track changes in raw value (forces printing of raw value)
4107    if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255, excl)) < 0)
4108      return -1;
4109    cfg.monitor_attr_flags.set(val, MONITOR_RAW_PRINT|MONITOR_RAW);
4110    if (*excl == '!') // raw value change is critical
4111      cfg.monitor_attr_flags.set(val, MONITOR_RAW_AS_CRIT);
4112    break;
4113  case 'W':
4114    // track Temperature
4115    if ((val=Get3Integers(arg=strtok(NULL,delim), name, token, lineno, configfile,
4116                          &cfg.tempdiff, &cfg.tempinfo, &cfg.tempcrit))<0)
4117      return -1;
4118    break;
4119  case 'v':
4120    // non-default vendor-specific attribute meaning
4121    if (!(arg=strtok(NULL,delim))) {
4122      missingarg = 1;
4123    } else if (!parse_attribute_def(arg, cfg.attribute_defs, PRIOR_USER)) {
4124      badarg = 1;
4125    }
4126    break;
4127  case 'P':
4128    // Define use of drive-specific presets.
4129    if (!(arg = strtok(NULL, delim))) {
4130      missingarg = 1;
4131    } else if (!strcmp(arg, "use")) {
4132      cfg.ignorepresets = false;
4133    } else if (!strcmp(arg, "ignore")) {
4134      cfg.ignorepresets = true;
4135    } else if (!strcmp(arg, "show")) {
4136      cfg.showpresets = true;
4137    } else if (!strcmp(arg, "showall")) {
4138      showallpresets();
4139    } else {
4140      badarg = 1;
4141    }
4142    break;
4143
4144  case 'e':
4145    // Various ATA settings
4146    if (!(arg = strtok(NULL, delim))) {
4147      missingarg = true;
4148    }
4149    else {
4150      char arg2[16+1]; unsigned val;
4151      int n1 = -1, n2 = -1, n3 = -1, len = strlen(arg);
4152      if (sscanf(arg, "%16[^,=]%n%*[,=]%n%u%n", arg2, &n1, &n2, &val, &n3) >= 1
4153          && (n1 == len || n2 > 0)) {
4154        bool on  = (n2 > 0 && !strcmp(arg+n2, "on"));
4155        bool off = (n2 > 0 && !strcmp(arg+n2, "off"));
4156        if (n3 != len)
4157          val = ~0U;
4158
4159        if (!strcmp(arg2, "aam")) {
4160          if (off)
4161            cfg.set_aam = -1;
4162          else if (val <= 254)
4163            cfg.set_aam = val + 1;
4164          else
4165            badarg = true;
4166        }
4167        else if (!strcmp(arg2, "apm")) {
4168          if (off)
4169            cfg.set_apm = -1;
4170          else if (1 <= val && val <= 254)
4171            cfg.set_apm = val + 1;
4172          else
4173            badarg = true;
4174        }
4175        else if (!strcmp(arg2, "lookahead")) {
4176          if (off)
4177            cfg.set_lookahead = -1;
4178          else if (on)
4179            cfg.set_lookahead = 1;
4180          else
4181            badarg = true;
4182        }
4183        else if (!strcmp(arg, "security-freeze")) {
4184          cfg.set_security_freeze = true;
4185        }
4186        else if (!strcmp(arg2, "standby")) {
4187          if (off)
4188            cfg.set_standby = 0 + 1;
4189          else if (val <= 255)
4190            cfg.set_standby = val + 1;
4191          else
4192            badarg = true;
4193        }
4194        else if (!strcmp(arg2, "wcache")) {
4195          if (off)
4196            cfg.set_wcache = -1;
4197          else if (on)
4198            cfg.set_wcache = 1;
4199          else
4200            badarg = true;
4201        }
4202        else
4203          badarg = true;
4204      }
4205      else
4206        badarg = true;
4207    }
4208    break;
4209
4210  default:
4211    // Directive not recognized
4212    PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
4213             configfile, lineno, name, token);
4214    Directives();
4215    return -1;
4216  }
4217  if (missingarg) {
4218    PrintOut(LOG_CRIT, "File %s line %d (drive %s): Missing argument to %s Directive\n",
4219             configfile, lineno, name, token);
4220  }
4221  if (badarg) {
4222    PrintOut(LOG_CRIT, "File %s line %d (drive %s): Invalid argument to %s Directive: %s\n",
4223             configfile, lineno, name, token, arg);
4224  }
4225  if (missingarg || badarg) {
4226    PrintOut(LOG_CRIT, "Valid arguments to %s Directive are: ", token);
4227    printoutvaliddirectiveargs(LOG_CRIT, sym);
4228    PrintOut(LOG_CRIT, "\n");
4229    return -1;
4230  }
4231
4232  return 1;
4233}
4234
4235// Scan directive for configuration file
4236#define SCANDIRECTIVE "DEVICESCAN"
4237
4238// This is the routine that adds things to the conf_entries list.
4239//
4240// Return values are:
4241//  1: parsed a normal line
4242//  0: found DEFAULT setting or comment or blank line
4243// -1: found SCANDIRECTIVE line
4244// -2: found an error
4245//
4246// Note: this routine modifies *line from the caller!
4247static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & default_conf, int lineno, /*const*/ char * line)
4248{
4249  const char *delim = " \n\t";
4250
4251  // get first token: device name. If a comment, skip line
4252  const char * name = strtok(line, delim);
4253  if (!name || *name == '#')
4254    return 0;
4255
4256  // Check device name for DEFAULT or DEVICESCAN
4257  int retval;
4258  if (!strcmp("DEFAULT", name)) {
4259    retval = 0;
4260    // Restart with empty defaults
4261    default_conf = dev_config();
4262  }
4263  else {
4264    retval = (!strcmp(SCANDIRECTIVE, name) ? -1 : 1);
4265    // Init new entry with current defaults
4266    conf_entries.push_back(default_conf);
4267  }
4268  dev_config & cfg = (retval ? conf_entries.back() : default_conf);
4269
4270  cfg.name = name; // Later replaced by dev->get_info().info_name
4271  cfg.dev_name = name; // If DEVICESCAN later replaced by get->dev_info().dev_name
4272  cfg.lineno = lineno;
4273
4274  // parse tokens one at a time from the file.
4275  while (char * token = strtok(0, delim)) {
4276    int rc = ParseToken(token, cfg);
4277    if (rc < 0)
4278      // error found on the line
4279      return -2;
4280
4281    if (rc == 0)
4282      // No tokens left
4283      break;
4284
4285    // PrintOut(LOG_INFO,"Parsed token %s\n",token);
4286  }
4287
4288  // Don't perform checks below for DEFAULT entries
4289  if (retval == 0)
4290    return retval;
4291
4292  // If NO monitoring directives are set, then set all of them.
4293  if (!(   cfg.smartcheck  || cfg.selftest
4294        || cfg.errorlog    || cfg.xerrorlog
4295        || cfg.offlinests  || cfg.selfteststs
4296        || cfg.usagefailed || cfg.prefail  || cfg.usage
4297        || cfg.tempdiff    || cfg.tempinfo || cfg.tempcrit)) {
4298   
4299    PrintOut(LOG_INFO,"Drive: %s, implied '-a' Directive on line %d of file %s\n",
4300             cfg.name.c_str(), cfg.lineno, configfile);
4301   
4302    cfg.smartcheck = true;
4303    cfg.usagefailed = true;
4304    cfg.prefail = true;
4305    cfg.usage = true;
4306    cfg.selftest = true;
4307    cfg.errorlog = true;
4308    cfg.selfteststs = true;
4309  }
4310 
4311  // additional sanity check. Has user set -M options without -m?
4312  if (cfg.emailaddress.empty() && (!cfg.emailcmdline.empty() || cfg.emailfreq || cfg.emailtest)){
4313    PrintOut(LOG_CRIT,"Drive: %s, -M Directive(s) on line %d of file %s need -m ADDRESS Directive\n",
4314             cfg.name.c_str(), cfg.lineno, configfile);
4315    return -2;
4316  }
4317 
4318  // has the user has set <nomailer>?
4319  if (cfg.emailaddress == "<nomailer>") {
4320    // check that -M exec is also set
4321    if (cfg.emailcmdline.empty()){
4322      PrintOut(LOG_CRIT,"Drive: %s, -m <nomailer> Directive on line %d of file %s needs -M exec Directive\n",
4323               cfg.name.c_str(), cfg.lineno, configfile);
4324      return -2;
4325    }
4326    // From here on the sign of <nomailer> is cfg.emailaddress.empty() and !cfg.emailcmdline.empty()
4327    cfg.emailaddress.clear();
4328  }
4329
4330  return retval;
4331}
4332
4333// Parses a configuration file.  Return values are:
4334//  N=>0: found N entries
4335// -1:    syntax error in config file
4336// -2:    config file does not exist
4337// -3:    config file exists but cannot be read
4338//
4339// In the case where the return value is 0, there are three
4340// possiblities:
4341// Empty configuration file ==> conf_entries.empty()
4342// No configuration file    ==> conf_entries[0].lineno == 0
4343// SCANDIRECTIVE found      ==> conf_entries.back().lineno != 0 (size >= 1)
4344static int ParseConfigFile(dev_config_vector & conf_entries)
4345{
4346  // maximum line length in configuration file
4347  const int MAXLINELEN = 256;
4348  // maximum length of a continued line in configuration file
4349  const int MAXCONTLINE = 1023;
4350
4351  stdio_file f;
4352  // Open config file, if it exists and is not <stdin>
4353  if (!(configfile == configfile_stdin)) { // pointer comparison ok here
4354    if (!f.open(configfile,"r") && (errno!=ENOENT || !configfile_alt.empty())) {
4355      // file exists but we can't read it or it should exist due to '-c' option
4356      int ret = (errno!=ENOENT ? -3 : -2);
4357      PrintOut(LOG_CRIT,"%s: Unable to open configuration file %s\n",
4358               strerror(errno),configfile);
4359      return ret;
4360    }
4361  }
4362  else // read from stdin ('-c -' option)
4363    f.open(stdin);
4364
4365  // Start with empty defaults
4366  dev_config default_conf;
4367
4368  // No configuration file found -- use fake one
4369  int entry = 0;
4370  if (!f) {
4371    char fakeconfig[] = SCANDIRECTIVE" -a"; // TODO: Remove this hack, build cfg_entry.
4372
4373    if (ParseConfigLine(conf_entries, default_conf, 0, fakeconfig) != -1)
4374      throw std::logic_error("Internal error parsing "SCANDIRECTIVE);
4375    return 0;
4376  }
4377
4378#ifdef __CYGWIN__
4379  setmode(fileno(f), O_TEXT); // Allow files with \r\n
4380#endif
4381
4382  // configuration file exists
4383  PrintOut(LOG_INFO,"Opened configuration file %s\n",configfile);
4384
4385  // parse config file line by line
4386  int lineno = 1, cont = 0, contlineno = 0;
4387  char line[MAXLINELEN+2];
4388  char fullline[MAXCONTLINE+1];
4389
4390  for (;;) {
4391    int len=0,scandevice;
4392    char *lastslash;
4393    char *comment;
4394    char *code;
4395
4396    // make debugging simpler
4397    memset(line,0,sizeof(line));
4398
4399    // get a line
4400    code=fgets(line, MAXLINELEN+2, f);
4401   
4402    // are we at the end of the file?
4403    if (!code){
4404      if (cont) {
4405        scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline);
4406        // See if we found a SCANDIRECTIVE directive
4407        if (scandevice==-1)
4408          return 0;
4409        // did we find a syntax error
4410        if (scandevice==-2)
4411          return -1;
4412        // the final line is part of a continuation line
4413        cont=0;
4414        entry+=scandevice;
4415      }
4416      break;
4417    }
4418
4419    // input file line number
4420    contlineno++;
4421   
4422    // See if line is too long
4423    len=strlen(line);
4424    if (len>MAXLINELEN){
4425      const char *warn;
4426      if (line[len-1]=='\n')
4427        warn="(including newline!) ";
4428      else
4429        warn="";
4430      PrintOut(LOG_CRIT,"Error: line %d of file %s %sis more than MAXLINELEN=%d characters.\n",
4431               (int)contlineno,configfile,warn,(int)MAXLINELEN);
4432      return -1;
4433    }
4434
4435    // Ignore anything after comment symbol
4436    if ((comment=strchr(line,'#'))){
4437      *comment='\0';
4438      len=strlen(line);
4439    }
4440
4441    // is the total line (made of all continuation lines) too long?
4442    if (cont+len>MAXCONTLINE){
4443      PrintOut(LOG_CRIT,"Error: continued line %d (actual line %d) of file %s is more than MAXCONTLINE=%d characters.\n",
4444               lineno, (int)contlineno, configfile, (int)MAXCONTLINE);
4445      return -1;
4446    }
4447   
4448    // copy string so far into fullline, and increment length
4449    strcpy(fullline+cont,line);
4450    cont+=len;
4451
4452    // is this a continuation line.  If so, replace \ by space and look at next line
4453    if ( (lastslash=strrchr(line,'\\')) && !strtok(lastslash+1," \n\t")){
4454      *(fullline+(cont-len)+(lastslash-line))=' ';
4455      continue;
4456    }
4457
4458    // Not a continuation line. Parse it
4459    scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline);
4460
4461    // did we find a scandevice directive?
4462    if (scandevice==-1)
4463      return 0;
4464    // did we find a syntax error
4465    if (scandevice==-2)
4466      return -1;
4467
4468    entry+=scandevice;
4469    lineno++;
4470    cont=0;
4471  }
4472
4473  // note -- may be zero if syntax of file OK, but no valid entries!
4474  return entry;
4475}
4476
4477/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST>  <=======\n", where
4478   <LIST> is the list of valid arguments for option opt. */
4479static void PrintValidArgs(char opt)
4480{
4481  const char *s;
4482
4483  PrintOut(LOG_CRIT, "=======> VALID ARGUMENTS ARE: ");
4484  if (!(s = GetValidArgList(opt)))
4485    PrintOut(LOG_CRIT, "Error constructing argument list for option %c", opt);
4486  else
4487    PrintOut(LOG_CRIT, "%s", (char *)s);
4488  PrintOut(LOG_CRIT, " <=======\n");
4489}
4490
4491#ifndef _WIN32
4492// Report error and exit if specified path is not absolute.
4493static void check_abs_path(char option, const std::string & path)
4494{
4495  if (path.empty() || path[0] == '/')
4496    return;
4497
4498  debugmode = 1;
4499  PrintHead();
4500  PrintOut(LOG_CRIT, "=======> INVALID ARGUMENT TO -%c: %s <=======\n\n", option, path.c_str());
4501  PrintOut(LOG_CRIT, "Error: relative path names are not allowed\n\n");
4502  EXIT(EXIT_BADCMD);
4503}
4504#endif // !_WIN32
4505
4506// Parses input line, prints usage message and
4507// version/license/copyright messages
4508static void ParseOpts(int argc, char **argv)
4509{
4510  // Init default configfile path
4511#ifndef _WIN32
4512  configfile = SMARTMONTOOLS_SYSCONFDIR"/smartd.conf";
4513#else
4514  static std::string configfile_str = get_exe_dir() + "/smartd.conf";
4515  configfile = configfile_str.c_str();
4516#endif
4517
4518  // Please update GetValidArgList() if you edit shortopts
4519  static const char shortopts[] = "c:l:q:dDni:p:r:s:A:B:Vh?"
4520#ifdef HAVE_LIBCAP_NG
4521                                                          "C"
4522#endif
4523                                                             ;
4524  // Please update GetValidArgList() if you edit longopts
4525  struct option longopts[] = {
4526    { "configfile",     required_argument, 0, 'c' },
4527    { "logfacility",    required_argument, 0, 'l' },
4528    { "quit",           required_argument, 0, 'q' },
4529    { "debug",          no_argument,       0, 'd' },
4530    { "showdirectives", no_argument,       0, 'D' },
4531    { "interval",       required_argument, 0, 'i' },
4532#ifndef _WIN32
4533    { "no-fork",        no_argument,       0, 'n' },
4534#else
4535    { "service",        no_argument,       0, 'n' },
4536#endif
4537    { "pidfile",        required_argument, 0, 'p' },
4538    { "report",         required_argument, 0, 'r' },
4539    { "savestates",     required_argument, 0, 's' },
4540    { "attributelog",   required_argument, 0, 'A' },
4541    { "drivedb",        required_argument, 0, 'B' },
4542    { "version",        no_argument,       0, 'V' },
4543    { "license",        no_argument,       0, 'V' },
4544    { "copyright",      no_argument,       0, 'V' },
4545    { "help",           no_argument,       0, 'h' },
4546    { "usage",          no_argument,       0, 'h' },
4547#ifdef HAVE_LIBCAP_NG
4548    { "capabilities",   no_argument,       0, 'C' },
4549#endif
4550    { 0,                0,                 0, 0   }
4551  };
4552
4553  opterr=optopt=0;
4554  bool badarg = false;
4555  bool no_defaultdb = false; // set true on '-B FILE'
4556
4557  // Parse input options.
4558  int optchar;
4559  while ((optchar = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
4560    char *arg;
4561    char *tailptr;
4562    long lchecktime;
4563
4564    switch(optchar) {
4565    case 'q':
4566      // when to quit
4567      if (!(strcmp(optarg,"nodev"))) {
4568        quit=0;
4569      } else if (!(strcmp(optarg,"nodevstartup"))) {
4570        quit=1;
4571      } else if (!(strcmp(optarg,"never"))) {
4572        quit=2;
4573      } else if (!(strcmp(optarg,"onecheck"))) {
4574        quit=3;
4575        debugmode=1;
4576      } else if (!(strcmp(optarg,"showtests"))) {
4577        quit=4;
4578        debugmode=1;
4579      } else if (!(strcmp(optarg,"errors"))) {
4580        quit=5;
4581      } else {
4582        badarg = true;
4583      }
4584      break;
4585    case 'l':
4586      // set the log facility level
4587      if (!strcmp(optarg, "daemon"))
4588        facility=LOG_DAEMON;
4589      else if (!strcmp(optarg, "local0"))
4590        facility=LOG_LOCAL0;
4591      else if (!strcmp(optarg, "local1"))
4592        facility=LOG_LOCAL1;
4593      else if (!strcmp(optarg, "local2"))
4594        facility=LOG_LOCAL2;
4595      else if (!strcmp(optarg, "local3"))
4596        facility=LOG_LOCAL3;
4597      else if (!strcmp(optarg, "local4"))
4598        facility=LOG_LOCAL4;
4599      else if (!strcmp(optarg, "local5"))
4600        facility=LOG_LOCAL5;
4601      else if (!strcmp(optarg, "local6"))
4602        facility=LOG_LOCAL6;
4603      else if (!strcmp(optarg, "local7"))
4604        facility=LOG_LOCAL7;
4605      else
4606        badarg = true;
4607      break;
4608    case 'd':
4609      // enable debug mode
4610      debugmode = 1;
4611      break;
4612    case 'n':
4613      // don't fork()
4614#ifndef _WIN32 // On Windows, --service is already handled by daemon_main()
4615      do_fork = false;
4616#endif
4617      break;
4618    case 'D':
4619      // print summary of all valid directives
4620      debugmode = 1;
4621      Directives();
4622      EXIT(0);
4623      break;
4624    case 'i':
4625      // Period (time interval) for checking
4626      // strtol will set errno in the event of overflow, so we'll check it.
4627      errno = 0;
4628      lchecktime = strtol(optarg, &tailptr, 10);
4629      if (*tailptr != '\0' || lchecktime < 10 || lchecktime > INT_MAX || errno) {
4630        debugmode=1;
4631        PrintHead();
4632        PrintOut(LOG_CRIT, "======> INVALID INTERVAL: %s <=======\n", optarg);
4633        PrintOut(LOG_CRIT, "======> INTERVAL MUST BE INTEGER BETWEEN %d AND %d <=======\n", 10, INT_MAX);
4634        PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
4635        EXIT(EXIT_BADCMD);
4636      }
4637      checktime = (int)lchecktime;
4638      break;
4639    case 'r':
4640      // report IOCTL transactions
4641      {
4642        int i;
4643        char *s;
4644
4645        // split_report_arg() may modify its first argument string, so use a
4646        // copy of optarg in case we want optarg for an error message.
4647        if (!(s = strdup(optarg))) {
4648          PrintOut(LOG_CRIT, "No memory to process -r option - exiting\n");
4649          EXIT(EXIT_NOMEM);
4650        }
4651        if (split_report_arg(s, &i)) {
4652          badarg = true;
4653        } else if (i<1 || i>3) {
4654          debugmode=1;
4655          PrintHead();
4656          PrintOut(LOG_CRIT, "======> INVALID REPORT LEVEL: %s <=======\n", optarg);
4657          PrintOut(LOG_CRIT, "======> LEVEL MUST BE INTEGER BETWEEN 1 AND 3<=======\n");
4658          EXIT(EXIT_BADCMD);
4659        } else if (!strcmp(s,"ioctl")) {
4660          ata_debugmode = scsi_debugmode = i;
4661        } else if (!strcmp(s,"ataioctl")) {
4662          ata_debugmode = i;
4663        } else if (!strcmp(s,"scsiioctl")) {
4664          scsi_debugmode = i;
4665        } else {
4666          badarg = true;
4667        }
4668        free(s);  // TODO: use std::string
4669      }
4670      break;
4671    case 'c':
4672      // alternate configuration file
4673      if (strcmp(optarg,"-"))
4674        configfile = (configfile_alt = optarg).c_str();
4675      else // read from stdin
4676        configfile=configfile_stdin;
4677      break;
4678    case 'p':
4679      // output file with PID number
4680      pid_file = optarg;
4681      break;
4682    case 's':
4683      // path prefix of persistent state file
4684      state_path_prefix = optarg;
4685      break;
4686    case 'A':
4687      // path prefix of attribute log file
4688      attrlog_path_prefix = optarg;
4689      break;
4690    case 'B':
4691      {
4692        const char * path = optarg;
4693        if (*path == '+' && path[1])
4694          path++;
4695        else
4696          no_defaultdb = true;
4697        unsigned char savedebug = debugmode; debugmode = 1;
4698        if (!read_drive_database(path))
4699          EXIT(EXIT_BADCMD);
4700        debugmode = savedebug;
4701      }
4702      break;
4703    case 'V':
4704      // print version and CVS info
4705      debugmode = 1;
4706      PrintOut(LOG_INFO, "%s", format_version_info("smartd", true /*full*/).c_str());
4707      EXIT(0);
4708      break;
4709#ifdef HAVE_LIBCAP_NG
4710    case 'C':
4711      // enable capabilities
4712      enable_capabilities = true;
4713      break;
4714#endif
4715    case 'h':
4716      // help: print summary of command-line options
4717      debugmode=1;
4718      PrintHead();
4719      Usage();
4720      EXIT(0);
4721      break;
4722    case '?':
4723    default:
4724      // unrecognized option
4725      debugmode=1;
4726      PrintHead();
4727      // Point arg to the argument in which this option was found.
4728      arg = argv[optind-1];
4729      // Check whether the option is a long option that doesn't map to -h.
4730      if (arg[1] == '-' && optchar != 'h') {
4731        // Iff optopt holds a valid option then argument must be missing.
4732        if (optopt && (strchr(shortopts, optopt) != NULL)) {
4733          PrintOut(LOG_CRIT, "=======> ARGUMENT REQUIRED FOR OPTION: %s <=======\n",arg+2);
4734          PrintValidArgs(optopt);
4735        } else {
4736          PrintOut(LOG_CRIT, "=======> UNRECOGNIZED OPTION: %s <=======\n\n",arg+2);
4737        }
4738        PrintOut(LOG_CRIT, "\nUse smartd --help to get a usage summary\n\n");
4739        EXIT(EXIT_BADCMD);
4740      }
4741      if (optopt) {
4742        // Iff optopt holds a valid option then argument must be missing.
4743        if (strchr(shortopts, optopt) != NULL){
4744          PrintOut(LOG_CRIT, "=======> ARGUMENT REQUIRED FOR OPTION: %c <=======\n",optopt);
4745          PrintValidArgs(optopt);
4746        } else {
4747          PrintOut(LOG_CRIT, "=======> UNRECOGNIZED OPTION: %c <=======\n\n",optopt);
4748        }
4749        PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
4750        EXIT(EXIT_BADCMD);
4751      }
4752      Usage();
4753      EXIT(0);
4754    }
4755
4756    // Check to see if option had an unrecognized or incorrect argument.
4757    if (badarg) {
4758      debugmode=1;
4759      PrintHead();
4760      // It would be nice to print the actual option name given by the user
4761      // here, but we just print the short form.  Please fix this if you know
4762      // a clean way to do it.
4763      PrintOut(LOG_CRIT, "=======> INVALID ARGUMENT TO -%c: %s <======= \n", optchar, optarg);
4764      PrintValidArgs(optchar);
4765      PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
4766      EXIT(EXIT_BADCMD);
4767    }
4768  }
4769
4770  // non-option arguments are not allowed
4771  if (argc > optind) {
4772    debugmode=1;
4773    PrintHead();
4774    PrintOut(LOG_CRIT, "=======> UNRECOGNIZED ARGUMENT: %s <=======\n\n", argv[optind]);
4775    PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
4776    EXIT(EXIT_BADCMD);
4777  }
4778
4779  // no pidfile in debug mode
4780  if (debugmode && !pid_file.empty()) {
4781    debugmode=1;
4782    PrintHead();
4783    PrintOut(LOG_CRIT, "=======> INVALID CHOICE OF OPTIONS: -d and -p <======= \n\n");
4784    PrintOut(LOG_CRIT, "Error: pid file %s not written in debug (-d) mode\n\n", pid_file.c_str());
4785    EXIT(EXIT_BADCMD);
4786  }
4787
4788#ifndef _WIN32
4789  if (!debugmode) {
4790    // absolute path names are required due to chdir('/') after fork().
4791    check_abs_path('p', pid_file);
4792    check_abs_path('s', state_path_prefix);
4793    check_abs_path('A', attrlog_path_prefix);
4794  }
4795#endif
4796
4797  // Read or init drive database
4798  if (!no_defaultdb) {
4799    unsigned char savedebug = debugmode; debugmode = 1;
4800    if (!read_default_drive_databases())
4801        EXIT(EXIT_BADCMD);
4802    debugmode = savedebug;
4803  }
4804
4805  // print header
4806  PrintHead();
4807}
4808
4809// Function we call if no configuration file was found or if the
4810// SCANDIRECTIVE Directive was found.  It makes entries for device
4811// names returned by scan_smart_devices() in os_OSNAME.cpp
4812static int MakeConfigEntries(const dev_config & base_cfg,
4813  dev_config_vector & conf_entries, smart_device_list & scanned_devs, const char * type)
4814{
4815  // make list of devices
4816  smart_device_list devlist;
4817  if (!smi()->scan_smart_devices(devlist, (*type ? type : 0)))
4818    PrintOut(LOG_CRIT,"Problem creating device name scan list\n");
4819 
4820  // if no devices, or error constructing list, return
4821  if (devlist.size() <= 0)
4822    return 0;
4823
4824  // add empty device slots for existing config entries
4825  while (scanned_devs.size() < conf_entries.size())
4826    scanned_devs.push_back((smart_device *)0);
4827
4828  // loop over entries to create
4829  for (unsigned i = 0; i < devlist.size(); i++) {
4830    // Move device pointer
4831    smart_device * dev = devlist.release(i);
4832    scanned_devs.push_back(dev);
4833
4834    // Copy configuration, update device and type name
4835    conf_entries.push_back(base_cfg);
4836    dev_config & cfg = conf_entries.back();
4837    cfg.name = dev->get_info().info_name;
4838    cfg.dev_name = dev->get_info().dev_name;
4839    cfg.dev_type = type;
4840  }
4841 
4842  return devlist.size();
4843}
4844 
4845static void CanNotRegister(const char *name, const char *type, int line, bool scandirective)
4846{
4847  if (!debugmode && scandirective)
4848    return;
4849  if (line)
4850    PrintOut(scandirective?LOG_INFO:LOG_CRIT,
4851             "Unable to register %s device %s at line %d of file %s\n",
4852             type, name, line, configfile);
4853  else
4854    PrintOut(LOG_INFO,"Unable to register %s device %s\n",
4855             type, name);
4856  return;
4857}
4858
4859// Returns negative value (see ParseConfigFile()) if config file
4860// had errors, else number of entries which may be zero or positive.
4861static int ReadOrMakeConfigEntries(dev_config_vector & conf_entries, smart_device_list & scanned_devs)
4862{
4863  // parse configuration file configfile (normally /etc/smartd.conf) 
4864  int entries = ParseConfigFile(conf_entries);
4865
4866  if (entries < 0) {
4867    // There was an error reading the configuration file.
4868    conf_entries.clear();
4869    if (entries == -1)
4870      PrintOut(LOG_CRIT, "Configuration file %s has fatal syntax errors.\n", configfile);
4871    return entries;
4872  }
4873
4874  // no error parsing config file.
4875  if (entries) {
4876    // we did not find a SCANDIRECTIVE and did find valid entries
4877    PrintOut(LOG_INFO, "Configuration file %s parsed.\n", configfile);
4878  }
4879  else if (!conf_entries.empty()) {
4880    // we found a SCANDIRECTIVE or there was no configuration file so
4881    // scan.  Configuration file's last entry contains all options
4882    // that were set
4883    dev_config first = conf_entries.back();
4884    conf_entries.pop_back();
4885
4886    if (first.lineno)
4887      PrintOut(LOG_INFO,"Configuration file %s was parsed, found %s, scanning devices\n", configfile, SCANDIRECTIVE);
4888    else
4889      PrintOut(LOG_INFO,"No configuration file %s found, scanning devices\n", configfile);
4890   
4891    // make config list of devices to search for
4892    MakeConfigEntries(first, conf_entries, scanned_devs, first.dev_type.c_str());
4893
4894    // warn user if scan table found no devices
4895    if (conf_entries.empty())
4896      PrintOut(LOG_CRIT,"In the system's table of devices NO devices found to scan\n");
4897  } 
4898  else
4899    PrintOut(LOG_CRIT,"Configuration file %s parsed but has no entries (like /dev/hda)\n",configfile);
4900 
4901  return conf_entries.size();
4902}
4903
4904
4905// This function tries devices from conf_entries.  Each one that can be
4906// registered is moved onto the [ata|scsi]devices lists and removed
4907// from the conf_entries list.
4908static void RegisterDevices(const dev_config_vector & conf_entries, smart_device_list & scanned_devs,
4909                            dev_config_vector & configs, dev_state_vector & states, smart_device_list & devices)
4910{
4911  // start by clearing lists/memory of ALL existing devices
4912  configs.clear();
4913  devices.clear();
4914  states.clear();
4915
4916  // Register entries
4917  for (unsigned i = 0; i < conf_entries.size(); i++){
4918
4919    dev_config cfg = conf_entries[i];
4920
4921    // get device of appropriate type
4922    smart_device_auto_ptr dev;
4923    bool scanning = false;
4924
4925    // Device may already be detected during devicescan
4926    if (i < scanned_devs.size()) {
4927      dev = scanned_devs.release(i);
4928      if (dev)
4929        scanning = true;
4930    }
4931
4932    if (!dev) {
4933      dev = smi()->get_smart_device(cfg.name.c_str(), cfg.dev_type.c_str());
4934      if (!dev) {
4935        if (cfg.dev_type.empty())
4936          PrintOut(LOG_INFO,"Device: %s, unable to autodetect device type\n", cfg.name.c_str());
4937        else
4938          PrintOut(LOG_INFO,"Device: %s, unsupported device type '%s'\n", cfg.name.c_str(), cfg.dev_type.c_str());
4939        continue;
4940      }
4941    }
4942
4943    // Save old info
4944    smart_device::device_info oldinfo = dev->get_info();
4945
4946    // Open with autodetect support, may return 'better' device
4947    dev.replace( dev->autodetect_open() );
4948
4949    // Report if type has changed
4950    if (oldinfo.dev_type != dev->get_dev_type())
4951      PrintOut(LOG_INFO,"Device: %s, type changed from '%s' to '%s'\n",
4952        cfg.name.c_str(), oldinfo.dev_type.c_str(), dev->get_dev_type());
4953
4954    if (!dev->is_open()) {
4955      // For linux+devfs, a nonexistent device gives a strange error
4956      // message.  This makes the error message a bit more sensible.
4957      // If no debug and scanning - don't print errors
4958      if (debugmode || !scanning)
4959        PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", dev->get_info_name(), dev->get_errmsg());
4960      continue;
4961    }
4962
4963    // Update informal name
4964    cfg.name = dev->get_info().info_name;
4965    PrintOut(LOG_INFO, "Device: %s, opened\n", cfg.name.c_str());
4966
4967    // Prepare initial state
4968    dev_state state;
4969
4970    // register ATA devices
4971    if (dev->is_ata()){
4972      if (ATADeviceScan(cfg, state, dev->to_ata())) {
4973        CanNotRegister(cfg.name.c_str(), "ATA", cfg.lineno, scanning);
4974        dev.reset();
4975      }
4976    }
4977    // or register SCSI devices
4978    else if (dev->is_scsi()){
4979      if (SCSIDeviceScan(cfg, state, dev->to_scsi())) {
4980        CanNotRegister(cfg.name.c_str(), "SCSI", cfg.lineno, scanning);
4981        dev.reset();
4982      }
4983    }
4984    else {
4985      PrintOut(LOG_INFO, "Device: %s, neither ATA nor SCSI device\n", cfg.name.c_str());
4986      dev.reset();
4987    }
4988
4989    if (dev) {
4990      // move onto the list of devices
4991      configs.push_back(cfg);
4992      states.push_back(state);
4993      devices.push_back(dev);
4994    }
4995    // if device is explictly listed and we can't register it, then
4996    // exit unless the user has specified that the device is removable
4997    else if (!scanning) {
4998      if (cfg.removable || quit==2)
4999        PrintOut(LOG_INFO, "Device %s not available\n", cfg.name.c_str());
5000      else {
5001        PrintOut(LOG_CRIT, "Unable to register device %s (no Directive -d removable). Exiting.\n", cfg.name.c_str());
5002        EXIT(EXIT_BADDEV);
5003      }
5004    }
5005  }
5006
5007  init_disable_standby_check(configs);
5008}
5009
5010
5011// Main program without exception handling
5012static int main_worker(int argc, char **argv)
5013{
5014  // Initialize interface
5015  smart_interface::init();
5016  if (!smi())
5017    return 1;
5018
5019  // is it our first pass through?
5020  bool firstpass = true;
5021
5022  // next time to wake up
5023  time_t wakeuptime = 0;
5024
5025  // parse input and print header and usage info if needed
5026  ParseOpts(argc,argv);
5027 
5028  // Configuration for each device
5029  dev_config_vector configs;
5030  // Device states
5031  dev_state_vector states;
5032  // Devices to monitor
5033  smart_device_list devices;
5034
5035  bool write_states_always = true;
5036
5037#ifdef HAVE_LIBCAP_NG
5038  // Drop capabilities
5039  if (enable_capabilities) {
5040    capng_clear(CAPNG_SELECT_BOTH);
5041    capng_updatev(CAPNG_ADD, (capng_type_t)(CAPNG_EFFECTIVE|CAPNG_PERMITTED),
5042                  CAP_SYS_ADMIN, CAP_MKNOD, CAP_SYS_RAWIO, -1);
5043    capng_apply(CAPNG_SELECT_BOTH);
5044  }
5045#endif
5046
5047  // the main loop of the code
5048  for (;;) {
5049
5050    // are we exiting from a signal?
5051    if (caughtsigEXIT) {
5052      // are we exiting with SIGTERM?
5053      int isterm=(caughtsigEXIT==SIGTERM);
5054      int isquit=(caughtsigEXIT==SIGQUIT);
5055      int isok=debugmode?isterm || isquit:isterm;
5056     
5057      PrintOut(isok?LOG_INFO:LOG_CRIT, "smartd received signal %d: %s\n",
5058               caughtsigEXIT, strsignal(caughtsigEXIT));
5059
5060      if (!isok)
5061        return EXIT_SIGNAL;
5062
5063      // Write state files
5064      if (!state_path_prefix.empty())
5065        write_all_dev_states(configs, states);
5066
5067      return 0;
5068    }
5069
5070    // Should we (re)read the config file?
5071    if (firstpass || caughtsigHUP){
5072      if (!firstpass) {
5073        // Write state files
5074        if (!state_path_prefix.empty())
5075          write_all_dev_states(configs, states);
5076
5077        PrintOut(LOG_INFO,
5078                 caughtsigHUP==1?
5079                 "Signal HUP - rereading configuration file %s\n":
5080                 "\a\nSignal INT - rereading configuration file %s ("SIGQUIT_KEYNAME" quits)\n\n",
5081                 configfile);
5082      }
5083
5084      {
5085        dev_config_vector conf_entries; // Entries read from smartd.conf
5086        smart_device_list scanned_devs; // Devices found during scan
5087        // (re)reads config file, makes >=0 entries
5088        int entries = ReadOrMakeConfigEntries(conf_entries, scanned_devs);
5089
5090        if (entries>=0) {
5091          // checks devices, then moves onto ata/scsi list or deallocates.
5092          RegisterDevices(conf_entries, scanned_devs, configs, states, devices);
5093          if (!(configs.size() == devices.size() && configs.size() == states.size()))
5094            throw std::logic_error("Invalid result from RegisterDevices");
5095        }
5096        else if (quit==2 || ((quit==0 || quit==1) && !firstpass)) {
5097          // user has asked to continue on error in configuration file
5098          if (!firstpass)
5099            PrintOut(LOG_INFO,"Reusing previous configuration\n");
5100        }
5101        else {
5102          // exit with configuration file error status
5103          return (entries==-3 ? EXIT_READCONF : entries==-2 ? EXIT_NOCONF : EXIT_BADCONF);
5104        }
5105      }
5106
5107      // Log number of devices we are monitoring...
5108      if (devices.size() > 0 || quit==2 || (quit==1 && !firstpass)) {
5109        int numata = 0;
5110        for (unsigned i = 0; i < devices.size(); i++) {
5111          if (devices.at(i)->is_ata())
5112            numata++;
5113        }
5114        PrintOut(LOG_INFO,"Monitoring %d ATA and %d SCSI devices\n",
5115                 numata, devices.size() - numata);
5116      }
5117      else {
5118        PrintOut(LOG_INFO,"Unable to monitor any SMART enabled devices. Try debug (-d) option. Exiting...\n");
5119        return EXIT_NODEV;
5120      }
5121
5122      if (quit==4) {
5123        // user has asked to print test schedule
5124        PrintTestSchedule(configs, states, devices);
5125        return 0;
5126      }
5127
5128#ifdef HAVE_LIBCAP_NG
5129      if (enable_capabilities) {
5130        for (unsigned i = 0; i < configs.size(); i++) {
5131          if (!configs[i].emailaddress.empty() || !configs[i].emailcmdline.empty()) {
5132            PrintOut(LOG_WARNING, "Mail can't be enabled together with --capabilities. All mail will be suppressed.\n");
5133            break;
5134          }
5135        }
5136      }
5137#endif
5138
5139      // reset signal
5140      caughtsigHUP=0;
5141
5142      // Always write state files after (re)configuration
5143      write_states_always = true;
5144    }
5145
5146    // check all devices once,
5147    // self tests are not started in first pass unless '-q onecheck' is specified
5148    CheckDevicesOnce(configs, states, devices, firstpass, (!firstpass || quit==3));
5149
5150     // Write state files
5151    if (!state_path_prefix.empty())
5152      write_all_dev_states(configs, states, write_states_always);
5153    write_states_always = false;
5154
5155    // Write attribute logs
5156    if (!attrlog_path_prefix.empty())
5157      write_all_dev_attrlogs(configs, states);
5158
5159    // user has asked us to exit after first check
5160    if (quit==3) {
5161      PrintOut(LOG_INFO,"Started with '-q onecheck' option. All devices sucessfully checked once.\n"
5162               "smartd is exiting (exit status 0)\n");
5163      return 0;
5164    }
5165   
5166    // fork into background if needed
5167    if (firstpass && !debugmode) {
5168      DaemonInit();
5169    }
5170
5171    // set exit and signal handlers, write PID file, set wake-up time
5172    if (firstpass){
5173      Initialize(&wakeuptime);
5174      firstpass = false;
5175    }
5176   
5177    // sleep until next check time, or a signal arrives
5178    wakeuptime = dosleep(wakeuptime, write_states_always);
5179  }
5180}
5181
5182
5183#ifndef _WIN32
5184// Main program
5185int main(int argc, char **argv)
5186#else
5187// Windows: internal main function started direct or by service control manager
5188static int smartd_main(int argc, char **argv)
5189#endif
5190{
5191  int status;
5192  try {
5193    // Do the real work ...
5194    status = main_worker(argc, argv);
5195  }
5196  catch (int ex) {
5197    // EXIT(status) arrives here
5198    status = ex;
5199  }
5200  catch (const std::bad_alloc & /*ex*/) {
5201    // Memory allocation failed (also thrown by std::operator new)
5202    PrintOut(LOG_CRIT, "Smartd: Out of memory\n");
5203    status = EXIT_NOMEM;
5204  }
5205  catch (const std::exception & ex) {
5206    // Other fatal errors
5207    PrintOut(LOG_CRIT, "Smartd: Exception: %s\n", ex.what());
5208    status = EXIT_BADCODE;
5209  }
5210
5211  if (is_initialized)
5212    status = Goodbye(status);
5213
5214#ifdef _WIN32
5215  daemon_winsvc_exitcode = status;
5216#endif
5217  return status;
5218}
5219
5220
5221#ifdef _WIN32
5222// Main function for Windows
5223int main(int argc, char **argv){
5224  // Options for smartd windows service
5225  static const daemon_winsvc_options svc_opts = {
5226    "--service", // cmd_opt
5227    "smartd", "SmartD Service", // servicename, displayname
5228    // description
5229    "Controls and monitors storage devices using the Self-Monitoring, "
5230    "Analysis and Reporting Technology System (S.M.A.R.T.) "
5231    "built into ATA and SCSI Hard Drives. "
5232    PACKAGE_HOMEPAGE
5233  };
5234  // daemon_main() handles daemon and service specific commands
5235  // and starts smartd_main() direct, from a new process,
5236  // or via service control manager
5237  return daemon_main("smartd", &svc_opts , smartd_main, argc, argv);
5238}
5239#endif
Note: See TracBrowser for help on using the browser.