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