root/trunk/smartmontools/smartd.cpp @ 3580

Revision 3580, 170.0 KB (checked in by chrfranke, 21 months ago)

smartd.cpp: Add fflush() to support redirection of debug output
(Debian bug 681349).

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