]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - smartd.cpp
Enhance dh_clean to clean up better
[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>
293b5ab8 7 * Copyright (C) 2008-15 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
293b5ab8 109const char * smartd_cpp_cvsid = "$Id: smartd.cpp 4059 2015-04-18 17:01:31Z 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");
293b5ab8 1510 PrintOut(LOG_INFO," Drop unneeded Linux process 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;
293b5ab8 1594 if (!ataReadExtErrorLog(device, &logx, 0, 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);
293b5ab8
JD
1852
1853 if (ataIsSmartEnabled(&drive) <= 0) {
1854 CloseDevice(atadev, name);
1855 return 2;
1856 }
1857 PrintOut(LOG_INFO, "Device: %s, proceeding since SMART is already enabled\n", name);
832b75ed
GG
1858 }
1859
1860 // disable device attribute autosave...
2127e193
GI
1861 if (cfg.autosave==1) {
1862 if (ataDisableAutoSave(atadev))
832b75ed
GG
1863 PrintOut(LOG_INFO,"Device: %s, could not disable SMART Attribute Autosave.\n",name);
1864 else
1865 PrintOut(LOG_INFO,"Device: %s, disabled SMART Attribute Autosave.\n",name);
1866 }
1867
1868 // or enable device attribute autosave
2127e193
GI
1869 if (cfg.autosave==2) {
1870 if (ataEnableAutoSave(atadev))
832b75ed
GG
1871 PrintOut(LOG_INFO,"Device: %s, could not enable SMART Attribute Autosave.\n",name);
1872 else
1873 PrintOut(LOG_INFO,"Device: %s, enabled SMART Attribute Autosave.\n",name);
1874 }
1875
1876 // capability check: SMART status
2127e193 1877 if (cfg.smartcheck && ataSmartStatus2(atadev) == -1) {
832b75ed 1878 PrintOut(LOG_INFO,"Device: %s, not capable of SMART Health Status check\n",name);
2127e193 1879 cfg.smartcheck = false;
832b75ed
GG
1880 }
1881
1882 // capability check: Read smart values and thresholds. Note that
1883 // smart values are ALSO needed even if we ONLY want to know if the
1884 // device is self-test log or error-log capable! After ATA-5, this
1885 // information was ALSO reproduced in the IDENTIFY DEVICE response,
1886 // but sadly not for ATA-5. Sigh.
1887
832b75ed 1888 // do we need to get SMART data?
2127e193 1889 bool smart_val_ok = false;
e9583e0c
GI
1890 if ( cfg.autoofflinetest || cfg.selftest
1891 || cfg.errorlog || cfg.xerrorlog
d008864d 1892 || cfg.offlinests || cfg.selfteststs
a23d5117
GI
1893 || cfg.usagefailed || cfg.prefail || cfg.usage
1894 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit
1895 || cfg.curr_pending_id || cfg.offl_pending_id ) {
1896
1897 if (ataReadSmartValues(atadev, &state.smartval)) {
1898 PrintOut(LOG_INFO, "Device: %s, Read SMART Values failed\n", name);
1899 cfg.usagefailed = cfg.prefail = cfg.usage = false;
2127e193
GI
1900 cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
1901 cfg.curr_pending_id = cfg.offl_pending_id = 0;
832b75ed 1902 }
a23d5117 1903 else {
2127e193 1904 smart_val_ok = true;
a23d5117
GI
1905 if (ataReadSmartThresholds(atadev, &state.smartthres)) {
1906 PrintOut(LOG_INFO, "Device: %s, Read SMART Thresholds failed%s\n",
1907 name, (cfg.usagefailed ? ", ignoring -f Directive" : ""));
1908 cfg.usagefailed = false;
1909 // Let ata_get_attr_state() return ATTRSTATE_NO_THRESHOLD:
1910 memset(&state.smartthres, 0, sizeof(state.smartthres));
1911 }
1912 }
2127e193 1913
832b75ed 1914 // see if the necessary Attribute is there to monitor offline or
4d59bff9 1915 // current pending sectors or temperature
cfbba5b9
GI
1916 if ( cfg.curr_pending_id
1917 && !check_pending_id(cfg, state, cfg.curr_pending_id,
1918 "Current_Pending_Sector"))
2127e193 1919 cfg.curr_pending_id = 0;
cfbba5b9
GI
1920
1921 if ( cfg.offl_pending_id
1922 && !check_pending_id(cfg, state, cfg.offl_pending_id,
1923 "Offline_Uncorrectable"))
2127e193 1924 cfg.offl_pending_id = 0;
4d59bff9 1925
2127e193 1926 if ( (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
bed94269 1927 && !ata_return_temperature_value(&state.smartval, cfg.attribute_defs)) {
ee38a438
GI
1928 PrintOut(LOG_INFO, "Device: %s, can't monitor Temperature, ignoring -W %d,%d,%d\n",
1929 name, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit);
2127e193 1930 cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
4d59bff9 1931 }
d008864d
GI
1932
1933 // Report ignored '-r' or '-R' directives
1934 for (int id = 1; id <= 255; id++) {
1935 if (cfg.monitor_attr_flags.is_set(id, MONITOR_RAW_PRINT)) {
1936 char opt = (!cfg.monitor_attr_flags.is_set(id, MONITOR_RAW) ? 'r' : 'R');
1937 const char * excl = (cfg.monitor_attr_flags.is_set(id,
1938 (opt == 'r' ? MONITOR_AS_CRIT : MONITOR_RAW_AS_CRIT)) ? "!" : "");
1939
1940 int idx = ata_find_attr_index(id, state.smartval);
1941 if (idx < 0)
1942 PrintOut(LOG_INFO,"Device: %s, no Attribute %d, ignoring -%c %d%s\n", name, id, opt, id, excl);
1943 else {
1944 bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(state.smartval.vendor_attributes[idx].flags);
1945 if (!((prefail && cfg.prefail) || (!prefail && cfg.usage)))
1946 PrintOut(LOG_INFO,"Device: %s, not monitoring %s Attributes, ignoring -%c %d%s\n", name,
1947 (prefail ? "Prefailure" : "Usage"), opt, id, excl);
1948 }
1949 }
1950 }
832b75ed
GG
1951 }
1952
1953 // enable/disable automatic on-line testing
2127e193 1954 if (cfg.autoofflinetest) {
832b75ed 1955 // is this an enable or disable request?
2127e193
GI
1956 const char *what=(cfg.autoofflinetest==1)?"disable":"enable";
1957 if (!smart_val_ok)
832b75ed
GG
1958 PrintOut(LOG_INFO,"Device: %s, could not %s SMART Automatic Offline Testing.\n",name, what);
1959 else {
1960 // if command appears unsupported, issue a warning...
2127e193 1961 if (!isSupportAutomaticTimer(&state.smartval))
832b75ed
GG
1962 PrintOut(LOG_INFO,"Device: %s, SMART Automatic Offline Testing unsupported...\n",name);
1963 // ... but then try anyway
2127e193 1964 if ((cfg.autoofflinetest==1)?ataDisableAutoOffline(atadev):ataEnableAutoOffline(atadev))
832b75ed
GG
1965 PrintOut(LOG_INFO,"Device: %s, %s SMART Automatic Offline Testing failed.\n", name, what);
1966 else
1967 PrintOut(LOG_INFO,"Device: %s, %sd SMART Automatic Offline Testing.\n", name, what);
1968 }
1969 }
cfbba5b9
GI
1970
1971 // Read log directories if required for capability check
1972 ata_smart_log_directory smart_logdir, gp_logdir;
1973 bool smart_logdir_ok = false, gp_logdir_ok = false;
1974
1975 if ( isGeneralPurposeLoggingCapable(&drive)
ee38a438
GI
1976 && (cfg.errorlog || cfg.selftest)
1977 && !cfg.firmwarebugs.is_set(BUG_NOLOGDIR)) {
cfbba5b9
GI
1978 if (!ataReadLogDirectory(atadev, &smart_logdir, false))
1979 smart_logdir_ok = true;
1980 }
1981
ee38a438 1982 if (cfg.xerrorlog && !cfg.firmwarebugs.is_set(BUG_NOLOGDIR)) {
cfbba5b9
GI
1983 if (!ataReadLogDirectory(atadev, &gp_logdir, true))
1984 gp_logdir_ok = true;
1985 }
1986
832b75ed 1987 // capability check: self-test-log
cfbba5b9 1988 state.selflogcount = 0; state.selfloghour = 0;
2127e193 1989 if (cfg.selftest) {
832b75ed 1990 int retval;
cfbba5b9
GI
1991 if (!( cfg.permissive
1992 || ( smart_logdir_ok && smart_logdir.entry[0x06-1].numsectors)
1993 || (!smart_logdir_ok && smart_val_ok && isSmartTestLogCapable(&state.smartval, &drive)))) {
1994 PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest (override with -T permissive)\n", name);
1995 cfg.selftest = false;
1996 }
ee38a438 1997 else if ((retval = SelfTestErrorCount(atadev, name, cfg.firmwarebugs)) < 0) {
cfbba5b9
GI
1998 PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest\n", name);
1999 cfg.selftest = false;
2000 }
832b75ed 2001 else {
2127e193
GI
2002 state.selflogcount=SELFTEST_ERRORCOUNT(retval);
2003 state.selfloghour =SELFTEST_ERRORHOURS(retval);
832b75ed
GG
2004 }
2005 }
2006
2007 // capability check: ATA error log
cfbba5b9
GI
2008 state.ataerrorcount = 0;
2009 if (cfg.errorlog) {
2010 int errcnt1;
2011 if (!( cfg.permissive
2012 || ( smart_logdir_ok && smart_logdir.entry[0x01-1].numsectors)
2013 || (!smart_logdir_ok && smart_val_ok && isSmartErrorLogCapable(&state.smartval, &drive)))) {
2014 PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error (override with -T permissive)\n", name);
2015 cfg.errorlog = false;
2016 }
ee38a438 2017 else if ((errcnt1 = read_ata_error_count(atadev, name, cfg.firmwarebugs, false)) < 0) {
cfbba5b9
GI
2018 PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error\n", name);
2019 cfg.errorlog = false;
2020 }
2021 else
2022 state.ataerrorcount = errcnt1;
2023 }
832b75ed 2024
cfbba5b9
GI
2025 if (cfg.xerrorlog) {
2026 int errcnt2;
ee38a438
GI
2027 if (!( cfg.permissive || cfg.firmwarebugs.is_set(BUG_NOLOGDIR)
2028 || (gp_logdir_ok && gp_logdir.entry[0x03-1].numsectors) )) {
cfbba5b9
GI
2029 PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror (override with -T permissive)\n",
2030 name);
2031 cfg.xerrorlog = false;
e9583e0c 2032 }
ee38a438 2033 else if ((errcnt2 = read_ata_error_count(atadev, name, cfg.firmwarebugs, true)) < 0) {
cfbba5b9
GI
2034 PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror\n", name);
2035 cfg.xerrorlog = false;
832b75ed 2036 }
cfbba5b9
GI
2037 else if (cfg.errorlog && state.ataerrorcount != errcnt2) {
2038 PrintOut(LOG_INFO, "Device: %s, SMART Error Logs report different error counts: %d != %d\n",
2039 name, state.ataerrorcount, errcnt2);
2040 // Record max error count
2041 if (errcnt2 > state.ataerrorcount)
2042 state.ataerrorcount = errcnt2;
2043 }
2044 else
2045 state.ataerrorcount = errcnt2;
832b75ed 2046 }
d008864d
GI
2047
2048 // capability check: self-test and offline data collection status
2049 if (cfg.offlinests || cfg.selfteststs) {
2050 if (!(cfg.permissive || (smart_val_ok && state.smartval.offline_data_collection_capability))) {
2051 if (cfg.offlinests)
2052 PrintOut(LOG_INFO, "Device: %s, no SMART Offline Data Collection capability, ignoring -l offlinests (override with -T permissive)\n", name);
2053 if (cfg.selfteststs)
2054 PrintOut(LOG_INFO, "Device: %s, no SMART Self-test capability, ignoring -l selfteststs (override with -T permissive)\n", name);
2055 cfg.offlinests = cfg.selfteststs = false;
2056 }
2057 }
2058
832b75ed 2059 // capabilities check -- does it support powermode?
2127e193
GI
2060 if (cfg.powermode) {
2061 int powermode = ataCheckPowerMode(atadev);
832b75ed
GG
2062
2063 if (-1 == powermode) {
2064 PrintOut(LOG_CRIT, "Device: %s, no ATA CHECK POWER STATUS support, ignoring -n Directive\n", name);
2127e193 2065 cfg.powermode=0;
832b75ed
GG
2066 }
2067 else if (powermode!=0 && powermode!=0x80 && powermode!=0xff) {
2068 PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n",
2069 name, powermode);
2127e193 2070 cfg.powermode=0;
832b75ed
GG
2071 }
2072 }
2073
d008864d
GI
2074 // Apply ATA settings
2075 std::string msg;
2076
2077 if (cfg.set_aam)
2078 format_set_result_msg(msg, "AAM", (cfg.set_aam > 0 ?
2079 ata_set_features(atadev, ATA_ENABLE_AAM, cfg.set_aam-1) :
2080 ata_set_features(atadev, ATA_DISABLE_AAM)), cfg.set_aam, true);
2081
2082 if (cfg.set_apm)
2083 format_set_result_msg(msg, "APM", (cfg.set_apm > 0 ?
2084 ata_set_features(atadev, ATA_ENABLE_APM, cfg.set_apm-1) :
2085 ata_set_features(atadev, ATA_DISABLE_APM)), cfg.set_apm, true);
2086
2087 if (cfg.set_lookahead)
2088 format_set_result_msg(msg, "Rd-ahead", ata_set_features(atadev,
2089 (cfg.set_lookahead > 0 ? ATA_ENABLE_READ_LOOK_AHEAD : ATA_DISABLE_READ_LOOK_AHEAD)),
2090 cfg.set_lookahead);
2091
2092 if (cfg.set_wcache)
2093 format_set_result_msg(msg, "Wr-cache", ata_set_features(atadev,
2094 (cfg.set_wcache > 0? ATA_ENABLE_WRITE_CACHE : ATA_DISABLE_WRITE_CACHE)), cfg.set_wcache);
2095
2096 if (cfg.set_security_freeze)
2097 format_set_result_msg(msg, "Security freeze",
2098 ata_nodata_command(atadev, ATA_SECURITY_FREEZE_LOCK));
2099
2100 if (cfg.set_standby)
2101 format_set_result_msg(msg, "Standby",
2102 ata_nodata_command(atadev, ATA_IDLE, cfg.set_standby-1), cfg.set_standby, true);
2103
2104 // Report as one log entry
2105 if (!msg.empty())
2106 PrintOut(LOG_INFO, "Device: %s, ATA settings applied: %s\n", name, msg.c_str());
2107
cfbba5b9
GI
2108 // set SCT Error Recovery Control if requested
2109 if (cfg.sct_erc_set) {
2110 if (!isSCTErrorRecoveryControlCapable(&drive))
2111 PrintOut(LOG_INFO, "Device: %s, no SCT Error Recovery Control support, ignoring -l scterc\n",
2112 name);
2113 else if ( ataSetSCTErrorRecoveryControltime(atadev, 1, cfg.sct_erc_readtime )
2114 || ataSetSCTErrorRecoveryControltime(atadev, 2, cfg.sct_erc_writetime))
2115 PrintOut(LOG_INFO, "Device: %s, set of SCT Error Recovery Control failed\n", name);
2116 else
2117 PrintOut(LOG_INFO, "Device: %s, SCT Error Recovery Control set to: Read: %u, Write: %u\n",
2118 name, cfg.sct_erc_readtime, cfg.sct_erc_writetime);
2119 }
2120
832b75ed 2121 // If no tests available or selected, return
e9583e0c
GI
2122 if (!( cfg.smartcheck || cfg.selftest
2123 || cfg.errorlog || cfg.xerrorlog
d008864d 2124 || cfg.offlinests || cfg.selfteststs
e9583e0c
GI
2125 || cfg.usagefailed || cfg.prefail || cfg.usage
2126 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) {
2127e193 2127 CloseDevice(atadev, name);
832b75ed
GG
2128 return 3;
2129 }
2130
2127e193 2131 // tell user we are registering device
832b75ed
GG
2132 PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n",name);
2133
832b75ed 2134 // close file descriptor
2127e193
GI
2135 CloseDevice(atadev, name);
2136
2137 if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
2138 // Build file name for state file
2127e193
GI
2139 std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
2140 std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
2141 if (!state_path_prefix.empty()) {
2142 cfg.state_file = strprintf("%s%s-%s.ata.state", state_path_prefix.c_str(), model, serial);
2143 // Read previous state
2144 if (read_dev_state(cfg.state_file.c_str(), state)) {
2145 PrintOut(LOG_INFO, "Device: %s, state read from %s\n", name, cfg.state_file.c_str());
2146 // Copy ATA attribute values to temp state
2147 state.update_temp_state();
2148 }
832b75ed 2149 }
2127e193
GI
2150 if (!attrlog_path_prefix.empty())
2151 cfg.attrlog_file = strprintf("%s%s-%s.ata.csv", attrlog_path_prefix.c_str(), model, serial);
832b75ed 2152 }
2127e193 2153
cfbba5b9 2154 finish_device_scan(cfg, state);
2127e193
GI
2155
2156 return 0;
832b75ed
GG
2157}
2158
2159// on success, return 0. On failure, return >0. Never return <0,
2160// please.
2127e193
GI
2161static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scsidev)
2162{
d008864d 2163 int k, err, req_len, avail_len, version, len;
2127e193 2164 const char *device = cfg.name.c_str();
832b75ed
GG
2165 struct scsi_iec_mode_page iec;
2166 UINT8 tBuf[64];
d008864d
GI
2167 UINT8 inqBuf[96];
2168 UINT8 vpdBuf[252];
ee38a438 2169 char lu_id[64], serial[256], vendor[40], model[40];
832b75ed 2170
2127e193 2171 // Device must be open
d008864d
GI
2172 memset(inqBuf, 0, 96);
2173 req_len = 36;
2174 if ((err = scsiStdInquiry(scsidev, inqBuf, req_len))) {
2175 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
2176 req_len = 64;
2177 if ((err = scsiStdInquiry(scsidev, inqBuf, req_len))) {
2178 PrintOut(LOG_INFO, "Device: %s, Both 36 and 64 byte INQUIRY failed; "
2179 "skip device\n", device);
2180 return 2;
2181 }
2182 }
ee38a438
GI
2183 version = (inqBuf[2] & 0x7f); /* Accept old ISO/IEC 9316:1995 variants */
2184
d008864d
GI
2185 avail_len = inqBuf[4] + 5;
2186 len = (avail_len < req_len) ? avail_len : req_len;
2187 if (len < 36) {
2188 PrintOut(LOG_INFO, "Device: %s, INQUIRY response less than 36 bytes; "
2189 "skip device\n", device);
2190 return 2;
2191 }
2192
2193 int pdt = inqBuf[0] & 0x1f;
2194
2195 if (! ((0 == pdt) || (4 == pdt) || (5 == pdt) || (7 == pdt) ||
2196 (0xe == pdt))) {
2197 PrintOut(LOG_INFO, "Device: %s, not a disk like device [PDT=0x%x], "
2198 "skip\n", device, pdt);
2199 return 2;
2200 }
ee38a438
GI
2201
2202 if (supported_vpd_pages_p) {
2203 delete supported_vpd_pages_p;
2204 supported_vpd_pages_p = NULL;
2205 }
2206 supported_vpd_pages_p = new supported_vpd_pages(scsidev);
2207
d008864d 2208 lu_id[0] = '\0';
ee38a438
GI
2209 if ((version >= 0x3) && (version < 0x8)) {
2210 /* SPC to SPC-5 */
2211 if (0 == scsiInquiryVpd(scsidev, SCSI_VPD_DEVICE_IDENTIFICATION,
2212 vpdBuf, sizeof(vpdBuf))) {
d008864d
GI
2213 len = vpdBuf[3];
2214 scsi_decode_lu_dev_id(vpdBuf + 4, len, lu_id, sizeof(lu_id), NULL);
2215 }
ee38a438
GI
2216 }
2217 serial[0] = '\0';
2218 if (0 == scsiInquiryVpd(scsidev, SCSI_VPD_UNIT_SERIAL_NUMBER,
2219 vpdBuf, sizeof(vpdBuf))) {
2220 len = vpdBuf[3];
2221 vpdBuf[4 + len] = '\0';
2222 scsi_format_id_string(serial, (const unsigned char *)&vpdBuf[4], len);
2223 }
d008864d
GI
2224
2225 unsigned int lb_size;
2226 char si_str[64];
ee38a438 2227 uint64_t capacity = scsiGetSize(scsidev, &lb_size, NULL);
d008864d
GI
2228
2229 if (capacity)
2230 format_capacity(si_str, sizeof(si_str), capacity);
2231 else
2232 si_str[0] = '\0';
ee38a438
GI
2233
2234 // Format device id string for warning emails
2235 cfg.dev_idinfo = strprintf("[%.8s %.16s %.4s]%s%s%s%s%s%s",
2236 (char *)&inqBuf[8], (char *)&inqBuf[16], (char *)&inqBuf[32],
2237 (lu_id[0] ? ", lu id: " : ""), (lu_id[0] ? lu_id : ""),
2238 (serial[0] ? ", S/N: " : ""), (serial[0] ? serial : ""),
2239 (si_str[0] ? ", " : ""), (si_str[0] ? si_str : ""));
2240
2241 // format "model" string
2242 scsi_format_id_string(vendor, (const unsigned char *)&inqBuf[8], 8);
2243 scsi_format_id_string(model, (const unsigned char *)&inqBuf[16], 16);
2244 PrintOut(LOG_INFO, "Device: %s, %s\n", device, cfg.dev_idinfo.c_str());
34ad0c5f 2245
832b75ed
GG
2246 // check that device is ready for commands. IE stores its stuff on
2247 // the media.
2127e193 2248 if ((err = scsiTestUnitReady(scsidev))) {
832b75ed
GG
2249 if (SIMPLE_ERR_NOT_READY == err)
2250 PrintOut(LOG_INFO, "Device: %s, NOT READY (e.g. spun down); skip device\n", device);
2251 else if (SIMPLE_ERR_NO_MEDIUM == err)
2252 PrintOut(LOG_INFO, "Device: %s, NO MEDIUM present; skip device\n", device);
2253 else if (SIMPLE_ERR_BECOMING_READY == err)
2254 PrintOut(LOG_INFO, "Device: %s, BECOMING (but not yet) READY; skip device\n", device);
2255 else
2256 PrintOut(LOG_CRIT, "Device: %s, failed Test Unit Ready [err=%d]\n", device, err);
2127e193 2257 CloseDevice(scsidev, device);
832b75ed
GG
2258 return 2;
2259 }
2260
2261 // Badly-conforming USB storage devices may fail this check.
2262 // The response to the following IE mode page fetch (current and
2263 // changeable values) is carefully examined. It has been found
2264 // that various USB devices that malform the response will lock up
2265 // if asked for a log page (e.g. temperature) so it is best to
2266 // bail out now.
2127e193
GI
2267 if (!(err = scsiFetchIECmpage(scsidev, &iec, state.modese_len)))
2268 state.modese_len = iec.modese_len;
832b75ed
GG
2269 else if (SIMPLE_ERR_BAD_FIELD == err)
2270 ; /* continue since it is reasonable not to support IE mpage */
2271 else { /* any other error (including malformed response) unreasonable */
2272 PrintOut(LOG_INFO,
2273 "Device: %s, Bad IEC (SMART) mode page, err=%d, skip device\n",
2274 device, err);
2127e193 2275 CloseDevice(scsidev, device);
832b75ed
GG
2276 return 3;
2277 }
2278
2279 // N.B. The following is passive (i.e. it doesn't attempt to turn on
2280 // smart if it is off). This may change to be the same as the ATA side.
2281 if (!scsi_IsExceptionControlEnabled(&iec)) {
2282 PrintOut(LOG_INFO, "Device: %s, IE (SMART) not enabled, skip device\n"
2283 "Try 'smartctl -s on %s' to turn on SMART features\n",
2284 device, device);
2127e193 2285 CloseDevice(scsidev, device);
832b75ed
GG
2286 return 3;
2287 }
2288
832b75ed
GG
2289 // Flag that certain log pages are supported (information may be
2290 // available from other sources).
2127e193 2291 if (0 == scsiLogSense(scsidev, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 0)) {
832b75ed
GG
2292 for (k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) {
2293 switch (tBuf[k]) {
2294 case TEMPERATURE_LPAGE:
2127e193 2295 state.TempPageSupported = 1;
832b75ed
GG
2296 break;
2297 case IE_LPAGE:
2127e193 2298 state.SmartPageSupported = 1;
832b75ed 2299 break;
ee38a438
GI
2300 case READ_ERROR_COUNTER_LPAGE:
2301 state.ReadECounterPageSupported = 1;
2302 break;
2303 case WRITE_ERROR_COUNTER_LPAGE:
2304 state.WriteECounterPageSupported = 1;
2305 break;
2306 case VERIFY_ERROR_COUNTER_LPAGE:
2307 state.VerifyECounterPageSupported = 1;
2308 break;
2309 case NON_MEDIUM_ERROR_LPAGE:
2310 state.NonMediumErrorPageSupported = 1;
2311 break;
832b75ed
GG
2312 default:
2313 break;
2314 }
2315 }
2316 }
2317
832b75ed
GG
2318 // Check if scsiCheckIE() is going to work
2319 {
2320 UINT8 asc = 0;
2321 UINT8 ascq = 0;
2322 UINT8 currenttemp = 0;
2323 UINT8 triptemp = 0;
2324
2127e193 2325 if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported,
832b75ed
GG
2326 &asc, &ascq, &currenttemp, &triptemp)) {
2327 PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device);
2127e193
GI
2328 state.SuppressReport = 1;
2329 if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) {
ee38a438
GI
2330 PrintOut(LOG_INFO, "Device: %s, can't monitor Temperature, ignoring -W %d,%d,%d\n",
2331 device, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit);
2127e193 2332 cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
4d59bff9 2333 }
832b75ed
GG
2334 }
2335 }
2336
2337 // capability check: self-test-log
2127e193
GI
2338 if (cfg.selftest){
2339 int retval = scsiCountFailedSelfTests(scsidev, 0);
832b75ed
GG
2340 if (retval<0) {
2341 // no self-test log, turn off monitoring
2342 PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-Test Log.\n", device);
2127e193
GI
2343 cfg.selftest = false;
2344 state.selflogcount = 0;
2345 state.selfloghour = 0;
832b75ed
GG
2346 }
2347 else {
2348 // register starting values to watch for changes
2127e193
GI
2349 state.selflogcount=SELFTEST_ERRORCOUNT(retval);
2350 state.selfloghour =SELFTEST_ERRORHOURS(retval);
832b75ed
GG
2351 }
2352 }
2353
2354 // disable autosave (set GLTSD bit)
2127e193
GI
2355 if (cfg.autosave==1){
2356 if (scsiSetControlGLTSD(scsidev, 1, state.modese_len))
832b75ed
GG
2357 PrintOut(LOG_INFO,"Device: %s, could not disable autosave (set GLTSD bit).\n",device);
2358 else
2359 PrintOut(LOG_INFO,"Device: %s, disabled autosave (set GLTSD bit).\n",device);
2360 }
2361
2362 // or enable autosave (clear GLTSD bit)
2127e193
GI
2363 if (cfg.autosave==2){
2364 if (scsiSetControlGLTSD(scsidev, 0, state.modese_len))
832b75ed
GG
2365 PrintOut(LOG_INFO,"Device: %s, could not enable autosave (clear GLTSD bit).\n",device);
2366 else
2367 PrintOut(LOG_INFO,"Device: %s, enabled autosave (cleared GLTSD bit).\n",device);
2368 }
2369
2370 // tell user we are registering device
2371 PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding to \"monitor\" list.\n", device);
832b75ed 2372
d008864d
GI
2373 // Make sure that init_standby_check() ignores SCSI devices
2374 cfg.offlinests_ns = cfg.selfteststs_ns = false;
2375
2127e193
GI
2376 // close file descriptor
2377 CloseDevice(scsidev, device);
2378
ee38a438
GI
2379 if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
2380 // Build file name for state file
2381 std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
2382 std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
2383 if (!state_path_prefix.empty()) {
2384 cfg.state_file = strprintf("%s%s-%s-%s.scsi.state", state_path_prefix.c_str(), vendor, model, serial);
2385 // Read previous state
2386 if (read_dev_state(cfg.state_file.c_str(), state)) {
2387 PrintOut(LOG_INFO, "Device: %s, state read from %s\n", device, cfg.state_file.c_str());
2388 // Copy ATA attribute values to temp state
2389 state.update_temp_state();
2390 }
2391 }
2392 if (!attrlog_path_prefix.empty())
2393 cfg.attrlog_file = strprintf("%s%s-%s-%s.scsi.csv", attrlog_path_prefix.c_str(), vendor, model, serial);
2394 }
2395
cfbba5b9 2396 finish_device_scan(cfg, state);
2127e193
GI
2397
2398 return 0;
34ad0c5f
GG
2399}
2400
832b75ed
GG
2401// If the self-test log has got more self-test errors (or more recent
2402// self-test errors) recorded, then notify user.
2127e193
GI
2403static void CheckSelfTestLogs(const dev_config & cfg, dev_state & state, int newi)
2404{
2405 const char * name = cfg.name.c_str();
832b75ed 2406
4d59bff9 2407 if (newi<0)
832b75ed 2408 // command failed
2127e193 2409 MailWarning(cfg, state, 8, "Device: %s, Read SMART Self-Test Log Failed", name);
d008864d
GI
2410 else {
2411 reset_warning_mail(cfg, state, 8, "Read SMART Self-Test Log worked again");
2412
832b75ed 2413 // old and new error counts
2127e193 2414 int oldc=state.selflogcount;
4d59bff9 2415 int newc=SELFTEST_ERRORCOUNT(newi);
832b75ed
GG
2416
2417 // old and new error timestamps in hours
2127e193 2418 int oldh=state.selfloghour;
4d59bff9 2419 int newh=SELFTEST_ERRORHOURS(newi);
832b75ed
GG
2420
2421 if (oldc<newc) {
2422 // increase in error count
2423 PrintOut(LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
2424 name, oldc, newc);
2127e193 2425 MailWarning(cfg, state, 3, "Device: %s, Self-Test Log error count increased from %d to %d",
832b75ed 2426 name, oldc, newc);
2127e193 2427 state.must_write = true;
e9583e0c
GI
2428 }
2429 else if (newc > 0 && oldh != newh) {
832b75ed
GG
2430 // more recent error
2431 // a 'more recent' error might actually be a smaller hour number,
2432 // if the hour number has wrapped.
2433 // There's still a bug here. You might just happen to run a new test
2434 // exactly 32768 hours after the previous failure, and have run exactly
2435 // 20 tests between the two, in which case smartd will miss the
2436 // new failure.
2437 PrintOut(LOG_CRIT, "Device: %s, new Self-Test Log error at hour timestamp %d\n",
2438 name, newh);
ee38a438 2439 MailWarning(cfg, state, 3, "Device: %s, new Self-Test Log error at hour timestamp %d",
832b75ed 2440 name, newh);
2127e193 2441 state.must_write = true;
832b75ed 2442 }
e9583e0c
GI
2443
2444 // Print info if error entries have disappeared
d008864d
GI
2445 // or newer successful successful extended self-test exits
2446 if (oldc > newc) {
e9583e0c
GI
2447 PrintOut(LOG_INFO, "Device: %s, Self-Test Log error count decreased from %d to %d\n",
2448 name, oldc, newc);
d008864d
GI
2449 if (newc == 0)
2450 reset_warning_mail(cfg, state, 3, "Self-Test Log does no longer report errors");
2451 }
e9583e0c 2452
832b75ed
GG
2453 // Needed since self-test error count may DECREASE. Hour might
2454 // also have changed.
2127e193
GI
2455 state.selflogcount= newc;
2456 state.selfloghour = newh;
832b75ed
GG
2457 }
2458 return;
2459}
2460
2127e193
GI
2461// Test types, ordered by priority.
2462static const char test_type_chars[] = "LncrSCO";
cfbba5b9 2463static const unsigned num_test_types = sizeof(test_type_chars)-1;
832b75ed 2464
2127e193
GI
2465// returns test type if time to do test of type testtype,
2466// 0 if not time to do test.
2467static char next_scheduled_test(const dev_config & cfg, dev_state & state, bool scsi, time_t usetime = 0)
2468{
832b75ed 2469 // check that self-testing has been requested
2127e193 2470 if (cfg.test_regex.empty())
832b75ed 2471 return 0;
2127e193
GI
2472
2473 // Exit if drive not capable of any test
2474 if ( state.not_cap_long && state.not_cap_short &&
2475 (scsi || (state.not_cap_conveyance && state.not_cap_offline)))
2476 return 0;
2477
832b75ed
GG
2478 // since we are about to call localtime(), be sure glibc is informed
2479 // of any timezone changes we make.
2127e193 2480 if (!usetime)
832b75ed
GG
2481 FixGlibcTimeZoneBug();
2482
2127e193
GI
2483 // Is it time for next check?
2484 time_t now = (!usetime ? time(0) : usetime);
2485 if (now < state.scheduled_test_next_check)
832b75ed 2486 return 0;
2127e193
GI
2487
2488 // Limit time check interval to 90 days
2489 if (state.scheduled_test_next_check + (3600L*24*90) < now)
2490 state.scheduled_test_next_check = now - (3600L*24*90);
2491
2492 // Check interval [state.scheduled_test_next_check, now] for scheduled tests
2493 char testtype = 0;
2494 time_t testtime = 0; int testhour = 0;
2495 int maxtest = num_test_types-1;
2496
2497 for (time_t t = state.scheduled_test_next_check; ; ) {
2498 struct tm * tms = localtime(&t);
2499 // tm_wday is 0 (Sunday) to 6 (Saturday). We use 1 (Monday) to 7 (Sunday).
2500 int weekday = (tms->tm_wday ? tms->tm_wday : 7);
2501 for (int i = 0; i <= maxtest; i++) {
2502 // Skip if drive not capable of this test
2503 switch (test_type_chars[i]) {
2504 case 'L': if (state.not_cap_long) continue; break;
2505 case 'S': if (state.not_cap_short) continue; break;
2506 case 'C': if (scsi || state.not_cap_conveyance) continue; break;
2507 case 'O': if (scsi || state.not_cap_offline) continue; break;
2508 case 'c': case 'n':
2509 case 'r': if (scsi || state.not_cap_selective) continue; break;
2510 default: continue;
2511 }
2512 // Try match of "T/MM/DD/d/HH"
2513 char pattern[16];
2514 snprintf(pattern, sizeof(pattern), "%c/%02d/%02d/%1d/%02d",
2515 test_type_chars[i], tms->tm_mon+1, tms->tm_mday, weekday, tms->tm_hour);
2516 if (cfg.test_regex.full_match(pattern)) {
2517 // Test found
2518 testtype = pattern[0];
2519 testtime = t; testhour = tms->tm_hour;
2520 // Limit further matches to higher priority self-tests
2521 maxtest = i-1;
2522 break;
2523 }
2524 }
2525 // Exit if no tests left or current time reached
2526 if (maxtest < 0)
2527 break;
2528 if (t >= now)
2529 break;
2530 // Check next hour
2531 if ((t += 3600) > now)
2532 t = now;
2533 }
2534
2535 // Do next check not before next hour.
2536 struct tm * tmnow = localtime(&now);
2537 state.scheduled_test_next_check = now + (3600 - tmnow->tm_min*60 - tmnow->tm_sec);
2538
2539 if (testtype) {
2540 state.must_write = true;
2541 // Tell user if an old test was found.
2542 if (!usetime && !(testhour == tmnow->tm_hour && testtime + 3600 > now)) {
2543 char datebuf[DATEANDEPOCHLEN]; dateandtimezoneepoch(datebuf, testtime);
2544 PrintOut(LOG_INFO, "Device: %s, old test of type %c not run at %s, starting now.\n",
2545 cfg.name.c_str(), testtype, datebuf);
2546 }
832b75ed 2547 }
2127e193
GI
2548
2549 return testtype;
832b75ed
GG
2550}
2551
2552// Print a list of future tests.
2127e193
GI
2553static void PrintTestSchedule(const dev_config_vector & configs, dev_state_vector & states, const smart_device_list & devices)
2554{
2555 unsigned numdev = configs.size();
2556 if (!numdev)
832b75ed 2557 return;
2127e193 2558 std::vector<int> testcnts(numdev * num_test_types, 0);
832b75ed
GG
2559
2560 PrintOut(LOG_INFO, "\nNext scheduled self tests (at most 5 of each type per device):\n");
2561
2562 // FixGlibcTimeZoneBug(); // done in PrintOut()
2127e193
GI
2563 time_t now = time(0);
2564 char datenow[DATEANDEPOCHLEN], date[DATEANDEPOCHLEN];
832b75ed 2565 dateandtimezoneepoch(datenow, now);
2127e193
GI
2566
2567 long seconds;
a37e7145 2568 for (seconds=checktime; seconds<3600L*24*90; seconds+=checktime) {
832b75ed
GG
2569 // Check for each device whether a test will be run
2570 time_t testtime = now + seconds;
2127e193
GI
2571 for (unsigned i = 0; i < numdev; i++) {
2572 const dev_config & cfg = configs.at(i);
2573 dev_state & state = states.at(i);
2574 const char * p;
2575 char testtype = next_scheduled_test(cfg, state, devices.at(i)->is_scsi(), testtime);
2576 if (testtype && (p = strchr(test_type_chars, testtype))) {
2577 unsigned t = (p - test_type_chars);
2578 // Report at most 5 tests of each type
2579 if (++testcnts[i*num_test_types + t] <= 5) {
2580 dateandtimezoneepoch(date, testtime);
2581 PrintOut(LOG_INFO, "Device: %s, will do test %d of type %c at %s\n", cfg.name.c_str(),
2582 testcnts[i*num_test_types + t], testtype, date);
832b75ed
GG
2583 }
2584 }
2585 }
2586 }
2587
2588 // Report totals
2589 dateandtimezoneepoch(date, now+seconds);
2590 PrintOut(LOG_INFO, "\nTotals [%s - %s]:\n", datenow, date);
2127e193
GI
2591 for (unsigned i = 0; i < numdev; i++) {
2592 const dev_config & cfg = configs.at(i);
2593 bool scsi = devices.at(i)->is_scsi();
2594 for (unsigned t = 0; t < num_test_types; t++) {
2595 int cnt = testcnts[i*num_test_types + t];
2596 if (cnt == 0 && !strchr((scsi ? "LS" : "LSCO"), test_type_chars[t]))
2597 continue;
2598 PrintOut(LOG_INFO, "Device: %s, will do %3d test%s of type %c\n", cfg.name.c_str(),
2599 cnt, (cnt==1?"":"s"), test_type_chars[t]);
832b75ed
GG
2600 }
2601 }
2602
832b75ed
GG
2603}
2604
2605// Return zero on success, nonzero on failure. Perform offline (background)
2606// short or long (extended) self test on given scsi device.
2127e193
GI
2607static int DoSCSISelfTest(const dev_config & cfg, dev_state & state, scsi_device * device, char testtype)
2608{
832b75ed 2609 int retval = 0;
2127e193
GI
2610 const char *testname = 0;
2611 const char *name = cfg.name.c_str();
832b75ed
GG
2612 int inProgress;
2613
2127e193 2614 if (scsiSelfTestInProgress(device, &inProgress)) {
832b75ed 2615 PrintOut(LOG_CRIT, "Device: %s, does not support Self-Tests\n", name);
2127e193 2616 state.not_cap_short = state.not_cap_long = true;
832b75ed
GG
2617 return 1;
2618 }
2619
2620 if (1 == inProgress) {
2621 PrintOut(LOG_INFO, "Device: %s, skip since Self-Test already in "
2622 "progress.\n", name);
2623 return 1;
2624 }
2625
2626 switch (testtype) {
2627 case 'S':
2628 testname = "Short Self";
2127e193 2629 retval = scsiSmartShortSelfTest(device);
832b75ed
GG
2630 break;
2631 case 'L':
2632 testname = "Long Self";
2127e193 2633 retval = scsiSmartExtendSelfTest(device);
832b75ed
GG
2634 break;
2635 }
2636 // If we can't do the test, exit
2637 if (NULL == testname) {
2638 PrintOut(LOG_CRIT, "Device: %s, not capable of %c Self-Test\n", name,
2639 testtype);
2640 return 1;
2641 }
2642 if (retval) {
2643 if ((SIMPLE_ERR_BAD_OPCODE == retval) ||
2644 (SIMPLE_ERR_BAD_FIELD == retval)) {
2645 PrintOut(LOG_CRIT, "Device: %s, not capable of %s-Test\n", name,
2646 testname);
2647 if ('L'==testtype)
2127e193 2648 state.not_cap_long = true;
832b75ed 2649 else
2127e193 2650 state.not_cap_short = true;
832b75ed
GG
2651
2652 return 1;
2653 }
2654 PrintOut(LOG_CRIT, "Device: %s, execute %s-Test failed (err: %d)\n", name,
2655 testname, retval);
2656 return 1;
2657 }
2658
2659 PrintOut(LOG_INFO, "Device: %s, starting scheduled %s-Test.\n", name, testname);
2660
2661 return 0;
2662}
2663
2664// Do an offline immediate or self-test. Return zero on success,
2665// nonzero on failure.
2127e193
GI
2666static int DoATASelfTest(const dev_config & cfg, dev_state & state, ata_device * device, char testtype)
2667{
2668 const char *name = cfg.name.c_str();
2669
832b75ed 2670 // Read current smart data and check status/capability
2127e193
GI
2671 struct ata_smart_values data;
2672 if (ataReadSmartValues(device, &data) || !(data.offline_data_collection_capability)) {
832b75ed
GG
2673 PrintOut(LOG_CRIT, "Device: %s, not capable of Offline or Self-Testing.\n", name);
2674 return 1;
2675 }
2676
2677 // Check for capability to do the test
2127e193
GI
2678 int dotest = -1, mode = 0;
2679 const char *testname = 0;
832b75ed
GG
2680 switch (testtype) {
2681 case 'O':
2682 testname="Offline Immediate ";
2683 if (isSupportExecuteOfflineImmediate(&data))
2684 dotest=OFFLINE_FULL_SCAN;
2685 else
2127e193 2686 state.not_cap_offline = true;
832b75ed
GG
2687 break;
2688 case 'C':
2689 testname="Conveyance Self-";
2690 if (isSupportConveyanceSelfTest(&data))
2691 dotest=CONVEYANCE_SELF_TEST;
2692 else
2127e193 2693 state.not_cap_conveyance = true;
832b75ed
GG
2694 break;
2695 case 'S':
2696 testname="Short Self-";
2697 if (isSupportSelfTest(&data))
2698 dotest=SHORT_SELF_TEST;
2699 else
2127e193 2700 state.not_cap_short = true;
832b75ed
GG
2701 break;
2702 case 'L':
2703 testname="Long Self-";
2704 if (isSupportSelfTest(&data))
2705 dotest=EXTEND_SELF_TEST;
2706 else
2127e193
GI
2707 state.not_cap_long = true;
2708 break;
2709
2710 case 'c': case 'n': case 'r':
2711 testname = "Selective Self-";
2712 if (isSupportSelectiveSelfTest(&data)) {
2713 dotest = SELECTIVE_SELF_TEST;
2714 switch (testtype) {
2715 case 'c': mode = SEL_CONT; break;
2716 case 'n': mode = SEL_NEXT; break;
2717 case 'r': mode = SEL_REDO; break;
2718 }
2719 }
2720 else
2721 state.not_cap_selective = true;
832b75ed
GG
2722 break;
2723 }
2724
2725 // If we can't do the test, exit
2726 if (dotest<0) {
2727 PrintOut(LOG_CRIT, "Device: %s, not capable of %sTest\n", name, testname);
2728 return 1;
2729 }
2730
2731 // If currently running a self-test, do not interrupt it to start another.
2732 if (15==(data.self_test_exec_status >> 4)) {
ee38a438 2733 if (cfg.firmwarebugs.is_set(BUG_SAMSUNG3) && data.self_test_exec_status == 0xf0) {
a37e7145
GG
2734 PrintOut(LOG_INFO, "Device: %s, will not skip scheduled %sTest "
2735 "despite unclear Self-Test byte (SAMSUNG Firmware bug).\n", name, testname);
2736 } else {
2737 PrintOut(LOG_INFO, "Device: %s, skip scheduled %sTest; %1d0%% remaining of current Self-Test.\n",
2738 name, testname, (int)(data.self_test_exec_status & 0x0f));
2739 return 1;
2740 }
832b75ed
GG
2741 }
2742
2127e193
GI
2743 if (dotest == SELECTIVE_SELF_TEST) {
2744 // Set test span
cfbba5b9 2745 ata_selective_selftest_args selargs, prev_args;
2127e193
GI
2746 selargs.num_spans = 1;
2747 selargs.span[0].mode = mode;
cfbba5b9
GI
2748 prev_args.num_spans = 1;
2749 prev_args.span[0].start = state.selective_test_last_start;
2750 prev_args.span[0].end = state.selective_test_last_end;
2751 if (ataWriteSelectiveSelfTestLog(device, selargs, &data, state.num_sectors, &prev_args)) {
2127e193
GI
2752 PrintOut(LOG_CRIT, "Device: %s, prepare %sTest failed\n", name, testname);
2753 return 1;
2754 }
2755 uint64_t start = selargs.span[0].start, end = selargs.span[0].end;
d2e702cf 2756 PrintOut(LOG_INFO, "Device: %s, %s test span at LBA %" PRIu64 " - %" PRIu64 " (%" PRIu64 " sectors, %u%% - %u%% of disk).\n",
2127e193
GI
2757 name, (selargs.span[0].mode == SEL_NEXT ? "next" : "redo"),
2758 start, end, end - start + 1,
2759 (unsigned)((100 * start + state.num_sectors/2) / state.num_sectors),
2760 (unsigned)((100 * end + state.num_sectors/2) / state.num_sectors));
cfbba5b9
GI
2761 state.selective_test_last_start = start;
2762 state.selective_test_last_end = end;
2127e193
GI
2763 }
2764
2765 // execute the test, and return status
2766 int retval = smartcommandhandler(device, IMMEDIATE_OFFLINE, dotest, NULL);
2767 if (retval) {
832b75ed 2768 PrintOut(LOG_CRIT, "Device: %s, execute %sTest failed.\n", name, testname);
2127e193
GI
2769 return retval;
2770 }
2771
d008864d
GI
2772 // Report recent test start to do_disable_standby_check()
2773 // and force log of next test status
2774 if (testtype == 'O')
2775 state.offline_started = true;
2776 else
2777 state.selftest_started = true;
2127e193
GI
2778
2779 PrintOut(LOG_INFO, "Device: %s, starting scheduled %sTest.\n", name, testname);
2780 return 0;
2781}
2782
2783// Check pending sector count attribute values (-C, -U directives).
2784static void check_pending(const dev_config & cfg, dev_state & state,
2785 unsigned char id, bool increase_only,
2786 const ata_smart_values & smartval,
2787 int mailtype, const char * msg)
2788{
bed94269
GI
2789 // Find attribute index
2790 int i = ata_find_attr_index(id, smartval);
2791 if (!(i >= 0 && ata_find_attr_index(id, state.smartval) == i))
2792 return;
2793
2127e193 2794 // No report if no sectors pending.
bed94269 2795 uint64_t rawval = ata_get_attr_raw_value(smartval.vendor_attributes[i], cfg.attribute_defs);
d008864d
GI
2796 if (rawval == 0) {
2797 reset_warning_mail(cfg, state, mailtype, "No more %s", msg);
2127e193 2798 return;
d008864d 2799 }
2127e193
GI
2800
2801 // If attribute is not reset, report only sector count increases.
bed94269 2802 uint64_t prev_rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs);
2127e193
GI
2803 if (!(!increase_only || prev_rawval < rawval))
2804 return;
2805
2806 // Format message.
d2e702cf 2807 std::string s = strprintf("Device: %s, %" PRId64 " %s", cfg.name.c_str(), rawval, msg);
2127e193 2808 if (prev_rawval > 0 && rawval != prev_rawval)
d2e702cf 2809 s += strprintf(" (changed %+" PRId64 ")", rawval - prev_rawval);
2127e193
GI
2810
2811 PrintOut(LOG_CRIT, "%s\n", s.c_str());
ee38a438 2812 MailWarning(cfg, state, mailtype, "%s", s.c_str());
2127e193
GI
2813 state.must_write = true;
2814}
2815
2816// Format Temperature value
ee38a438 2817static const char * fmt_temp(unsigned char x, char (& buf)[20])
2127e193
GI
2818{
2819 if (!x) // unset
ee38a438
GI
2820 return "??";
2821 snprintf(buf, sizeof(buf), "%u", x);
2127e193 2822 return buf;
832b75ed
GG
2823}
2824
4d59bff9 2825// Check Temperature limits
2127e193 2826static void CheckTemperature(const dev_config & cfg, dev_state & state, unsigned char currtemp, unsigned char triptemp)
4d59bff9 2827{
4d59bff9 2828 if (!(0 < currtemp && currtemp < 255)) {
2127e193 2829 PrintOut(LOG_INFO, "Device: %s, failed to read Temperature\n", cfg.name.c_str());
4d59bff9
GG
2830 return;
2831 }
2832
2127e193
GI
2833 // Update Max Temperature
2834 const char * minchg = "", * maxchg = "";
2835 if (currtemp > state.tempmax) {
2836 if (state.tempmax)
2837 maxchg = "!";
2838 state.tempmax = currtemp;
2839 state.must_write = true;
2840 }
2841
2842 char buf[20];
2843 if (!state.temperature) {
2844 // First check
2845 if (!state.tempmin || currtemp < state.tempmin)
2846 // Delay Min Temperature update by ~ 30 minutes.
2847 state.tempmin_delay = time(0) + CHECKTIME - 60;
2848 PrintOut(LOG_INFO, "Device: %s, initial Temperature is %d Celsius (Min/Max %s/%u%s)\n",
2849 cfg.name.c_str(), (int)currtemp, fmt_temp(state.tempmin, buf), state.tempmax, maxchg);
4d59bff9
GG
2850 if (triptemp)
2851 PrintOut(LOG_INFO, " [trip Temperature is %d Celsius]\n", (int)triptemp);
2127e193 2852 state.temperature = currtemp;
4d59bff9
GG
2853 }
2854 else {
2127e193
GI
2855 if (state.tempmin_delay) {
2856 // End Min Temperature update delay if ...
2857 if ( (state.tempmin && currtemp > state.tempmin) // current temp exceeds recorded min,
2858 || (state.tempmin_delay <= time(0))) { // or delay time is over.
2859 state.tempmin_delay = 0;
2860 if (!state.tempmin)
2861 state.tempmin = 255;
2862 }
4d59bff9 2863 }
2127e193
GI
2864
2865 // Update Min Temperature
2866 if (!state.tempmin_delay && currtemp < state.tempmin) {
2867 state.tempmin = currtemp;
2868 state.must_write = true;
2869 if (currtemp != state.temperature)
2870 minchg = "!";
4d59bff9
GG
2871 }
2872
2873 // Track changes
2127e193
GI
2874 if (cfg.tempdiff && (*minchg || *maxchg || abs((int)currtemp - (int)state.temperature) >= cfg.tempdiff)) {
2875 PrintOut(LOG_INFO, "Device: %s, Temperature changed %+d Celsius to %u Celsius (Min/Max %s%s/%u%s)\n",
2876 cfg.name.c_str(), (int)currtemp-(int)state.temperature, currtemp, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
2877 state.temperature = currtemp;
4d59bff9
GG
2878 }
2879 }
2880
2881 // Check limits
2127e193
GI
2882 if (cfg.tempcrit && currtemp >= cfg.tempcrit) {
2883 PrintOut(LOG_CRIT, "Device: %s, Temperature %u Celsius reached critical limit of %u Celsius (Min/Max %s%s/%u%s)\n",
2884 cfg.name.c_str(), currtemp, cfg.tempcrit, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
ee38a438 2885 MailWarning(cfg, state, 12, "Device: %s, Temperature %d Celsius reached critical limit of %u Celsius (Min/Max %s%s/%u%s)",
2127e193 2886 cfg.name.c_str(), currtemp, cfg.tempcrit, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
4d59bff9 2887 }
2127e193
GI
2888 else if (cfg.tempinfo && currtemp >= cfg.tempinfo) {
2889 PrintOut(LOG_INFO, "Device: %s, Temperature %u Celsius reached limit of %u Celsius (Min/Max %s%s/%u%s)\n",
2890 cfg.name.c_str(), currtemp, cfg.tempinfo, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
4d59bff9 2891 }
d008864d
GI
2892 else if (cfg.tempcrit) {
2893 unsigned char limit = (cfg.tempinfo ? cfg.tempinfo : cfg.tempcrit-5);
2894 if (currtemp < limit)
2895 reset_warning_mail(cfg, state, 12, "Temperature %u Celsius dropped below %u Celsius", currtemp, limit);
2896 }
4d59bff9 2897}
832b75ed 2898
bed94269
GI
2899// Check normalized and raw attribute values.
2900static void check_attribute(const dev_config & cfg, dev_state & state,
2901 const ata_smart_attribute & attr,
2902 const ata_smart_attribute & prev,
cfbba5b9
GI
2903 int attridx,
2904 const ata_smart_threshold_entry * thresholds)
bed94269
GI
2905{
2906 // Check attribute and threshold
cfbba5b9 2907 ata_attr_state attrstate = ata_get_attr_state(attr, attridx, thresholds, cfg.attribute_defs);
bed94269
GI
2908 if (attrstate == ATTRSTATE_NON_EXISTING)
2909 return;
2910
2911 // If requested, check for usage attributes that have failed.
2912 if ( cfg.usagefailed && attrstate == ATTRSTATE_FAILED_NOW
2913 && !cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGN_FAILUSE)) {
ee38a438 2914 std::string attrname = ata_get_smart_attr_name(attr.id, cfg.attribute_defs, cfg.dev_rpm);
bed94269
GI
2915 PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %d %s.\n", cfg.name.c_str(), attr.id, attrname.c_str());
2916 MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %d %s.", cfg.name.c_str(), attr.id, attrname.c_str());
2917 state.must_write = true;
2918 }
2919
2920 // Return if we're not tracking this type of attribute
2921 bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(attr.flags);
2922 if (!( ( prefail && cfg.prefail)
2923 || (!prefail && cfg.usage )))
2924 return;
2925
2926 // Return if '-I ID' was specified
2927 if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_IGNORE))
2928 return;
2929
2930 // Issue warning if they don't have the same ID in all structures.
cfbba5b9
GI
2931 if (attr.id != prev.id) {
2932 PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d\n",
2933 cfg.name.c_str(), attr.id, prev.id);
bed94269
GI
2934 return;
2935 }
2936
2937 // Compare normalized values if valid.
2938 bool valchanged = false;
2939 if (attrstate > ATTRSTATE_NO_NORMVAL) {
2940 if (attr.current != prev.current)
2941 valchanged = true;
2942 }
2943
2944 // Compare raw values if requested.
2945 bool rawchanged = false;
2946 if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW)) {
2947 if ( ata_get_attr_raw_value(attr, cfg.attribute_defs)
2948 != ata_get_attr_raw_value(prev, cfg.attribute_defs))
2949 rawchanged = true;
2950 }
2951
2952 // Return if no change
2953 if (!(valchanged || rawchanged))
2954 return;
2955
2956 // Format value strings
2957 std::string currstr, prevstr;
2958 if (attrstate == ATTRSTATE_NO_NORMVAL) {
2959 // Print raw values only
2960 currstr = strprintf("%s (Raw)",
2961 ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
2962 prevstr = strprintf("%s (Raw)",
2963 ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
2964 }
2965 else if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_PRINT)) {
2966 // Print normalized and raw values
2967 currstr = strprintf("%d [Raw %s]", attr.current,
2968 ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
2969 prevstr = strprintf("%d [Raw %s]", prev.current,
2970 ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
2971 }
2972 else {
2973 // Print normalized values only
2974 currstr = strprintf("%d", attr.current);
2975 prevstr = strprintf("%d", prev.current);
2976 }
2977
2978 // Format message
2979 std::string msg = strprintf("Device: %s, SMART %s Attribute: %d %s changed from %s to %s",
2980 cfg.name.c_str(), (prefail ? "Prefailure" : "Usage"), attr.id,
ee38a438 2981 ata_get_smart_attr_name(attr.id, cfg.attribute_defs, cfg.dev_rpm).c_str(),
bed94269
GI
2982 prevstr.c_str(), currstr.c_str());
2983
2984 // Report this change as critical ?
2985 if ( (valchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_AS_CRIT))
2986 || (rawchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_AS_CRIT))) {
2987 PrintOut(LOG_CRIT, "%s\n", msg.c_str());
2988 MailWarning(cfg, state, 2, "%s", msg.c_str());
2989 }
2990 else {
2991 PrintOut(LOG_INFO, "%s\n", msg.c_str());
2992 }
2993 state.must_write = true;
2994}
2995
2996
a7e8ffec
GI
2997static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device * atadev,
2998 bool firstpass, bool allow_selftests)
2127e193
GI
2999{
3000 const char * name = cfg.name.c_str();
832b75ed
GG
3001
3002 // If user has asked, test the email warning system
2127e193
GI
3003 if (cfg.emailtest)
3004 MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name);
832b75ed
GG
3005
3006 // if we can't open device, fail gracefully rather than hard --
3007 // perhaps the next time around we'll be able to open it. ATAPI
3008 // cd/dvd devices will hang awaiting media if O_NONBLOCK is not
3009 // given (see linux cdrom driver).
2127e193
GI
3010 if (!atadev->open()) {
3011 PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", name, atadev->get_errmsg());
3012 MailWarning(cfg, state, 9, "Device: %s, unable to open device", name);
832b75ed 3013 return 1;
d008864d
GI
3014 }
3015 if (debugmode)
2127e193 3016 PrintOut(LOG_INFO,"Device: %s, opened ATA device\n", name);
d008864d 3017 reset_warning_mail(cfg, state, 9, "open device worked again");
4d59bff9 3018
832b75ed
GG
3019 // user may have requested (with the -n Directive) to leave the disk
3020 // alone if it is in idle or sleeping mode. In this case check the
3021 // power mode and exit without check if needed
2127e193
GI
3022 if (cfg.powermode && !state.powermodefail) {
3023 int dontcheck=0, powermode=ataCheckPowerMode(atadev);
3024 const char * mode = 0;
4d59bff9
GG
3025 if (0 <= powermode && powermode < 0xff) {
3026 // wait for possible spin up and check again
3027 int powermode2;
3028 sleep(5);
2127e193 3029 powermode2 = ataCheckPowerMode(atadev);
832b75ed
GG
3030 if (powermode2 > powermode)
3031 PrintOut(LOG_INFO, "Device: %s, CHECK POWER STATUS spins up disk (0x%02x -> 0x%02x)\n", name, powermode, powermode2);
3032 powermode = powermode2;
3033 }
3034
3035 switch (powermode){
3036 case -1:
3037 // SLEEP
3038 mode="SLEEP";
2127e193 3039 if (cfg.powermode>=1)
4d59bff9 3040 dontcheck=1;
832b75ed
GG
3041 break;
3042 case 0:
3043 // STANDBY
3044 mode="STANDBY";
2127e193 3045 if (cfg.powermode>=2)
4d59bff9 3046 dontcheck=1;
832b75ed
GG
3047 break;
3048 case 0x80:
3049 // IDLE
3050 mode="IDLE";
2127e193 3051 if (cfg.powermode>=3)
4d59bff9 3052 dontcheck=1;
832b75ed
GG
3053 break;
3054 case 0xff:
3055 // ACTIVE/IDLE
4d59bff9 3056 mode="ACTIVE or IDLE";
832b75ed
GG
3057 break;
3058 default:
3059 // UNKNOWN
3060 PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n",
4d59bff9 3061 name, powermode);
2127e193 3062 state.powermodefail = true;
832b75ed
GG
3063 break;
3064 }
3065
3066 // if we are going to skip a check, return now
3067 if (dontcheck){
2127e193
GI
3068 // skip at most powerskipmax checks
3069 if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) {
3070 CloseDevice(atadev, name);
3071 if (!state.powerskipcnt && !cfg.powerquiet) // report first only and avoid waking up system disk
4d59bff9 3072 PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, mode);
2127e193 3073 state.powerskipcnt++;
4d59bff9
GG
3074 return 0;
3075 }
2127e193
GI
3076 else {
3077 PrintOut(LOG_INFO, "Device: %s, %s mode ignored due to reached limit of skipped checks (%d check%s skipped)\n",
3078 name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s"));
3079 }
3080 state.powerskipcnt = 0;
3081 state.tempmin_delay = time(0) + CHECKTIME - 60; // Delay Min Temperature update
4d59bff9 3082 }
2127e193 3083 else if (state.powerskipcnt) {
4d59bff9 3084 PrintOut(LOG_INFO, "Device: %s, is back in %s mode, resuming checks (%d check%s skipped)\n",
2127e193
GI
3085 name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s"));
3086 state.powerskipcnt = 0;
3087 state.tempmin_delay = time(0) + CHECKTIME - 60; // Delay Min Temperature update
4d59bff9 3088 }
832b75ed
GG
3089 }
3090
3091 // check smart status
2127e193
GI
3092 if (cfg.smartcheck) {
3093 int status=ataSmartStatus2(atadev);
832b75ed
GG
3094 if (status==-1){
3095 PrintOut(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name);
2127e193
GI
3096 MailWarning(cfg, state, 5, "Device: %s, not capable of SMART self-check", name);
3097 state.must_write = true;
832b75ed
GG
3098 }
3099 else if (status==1){
3100 PrintOut(LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name);
2127e193
GI
3101 MailWarning(cfg, state, 1, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!", name);
3102 state.must_write = true;
832b75ed
GG
3103 }
3104 }
3105
3106 // Check everything that depends upon SMART Data (eg, Attribute values)
2127e193
GI
3107 if ( cfg.usagefailed || cfg.prefail || cfg.usage
3108 || cfg.curr_pending_id || cfg.offl_pending_id
d008864d
GI
3109 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit
3110 || cfg.selftest || cfg.offlinests || cfg.selfteststs) {
2127e193 3111
bed94269
GI
3112 // Read current attribute values.
3113 ata_smart_values curval;
2127e193 3114 if (ataReadSmartValues(atadev, &curval)){
832b75ed 3115 PrintOut(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name);
2127e193
GI
3116 MailWarning(cfg, state, 6, "Device: %s, failed to read SMART Attribute Data", name);
3117 state.must_write = true;
832b75ed
GG
3118 }
3119 else {
d008864d
GI
3120 reset_warning_mail(cfg, state, 6, "read SMART Attribute Data worked again");
3121
832b75ed 3122 // look for current or offline pending sectors
2127e193
GI
3123 if (cfg.curr_pending_id)
3124 check_pending(cfg, state, cfg.curr_pending_id, cfg.curr_pending_incr, curval, 10,
3125 (!cfg.curr_pending_incr ? "Currently unreadable (pending) sectors"
3126 : "Total unreadable (pending) sectors" ));
3127
3128 if (cfg.offl_pending_id)
3129 check_pending(cfg, state, cfg.offl_pending_id, cfg.offl_pending_incr, curval, 11,
3130 (!cfg.offl_pending_incr ? "Offline uncorrectable sectors"
3131 : "Total offline uncorrectable sectors"));
832b75ed 3132
4d59bff9 3133 // check temperature limits
2127e193 3134 if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
bed94269 3135 CheckTemperature(cfg, state, ata_return_temperature_value(&curval, cfg.attribute_defs), 0);
4d59bff9 3136
d008864d 3137 // look for failed usage attributes, or track usage or prefail attributes
2127e193 3138 if (cfg.usagefailed || cfg.prefail || cfg.usage) {
2127e193 3139 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
bed94269
GI
3140 check_attribute(cfg, state,
3141 curval.vendor_attributes[i],
3142 state.smartval.vendor_attributes[i],
cfbba5b9 3143 i, state.smartthres.thres_entries);
bed94269 3144 }
d008864d 3145 }
2127e193 3146
d008864d
GI
3147 // Log changes of offline data collection status
3148 if (cfg.offlinests) {
3149 if ( curval.offline_data_collection_status
3150 != state.smartval.offline_data_collection_status
3151 || state.offline_started // test was started in previous call
3152 || (firstpass && (debugmode || (curval.offline_data_collection_status & 0x7d))))
3153 log_offline_data_coll_status(name, curval.offline_data_collection_status);
3154 }
2127e193 3155
d008864d
GI
3156 // Log changes of self-test execution status
3157 if (cfg.selfteststs) {
3158 if ( curval.self_test_exec_status != state.smartval.self_test_exec_status
3159 || state.selftest_started // test was started in previous call
3160 || (firstpass && (debugmode || curval.self_test_exec_status != 0x00)))
3161 log_self_test_exec_status(name, curval.self_test_exec_status);
832b75ed 3162 }
d008864d
GI
3163
3164 // Save the new values for the next time around
3165 state.smartval = curval;
832b75ed
GG
3166 }
3167 }
d008864d 3168 state.offline_started = state.selftest_started = false;
832b75ed
GG
3169
3170 // check if number of selftest errors has increased (note: may also DECREASE)
2127e193 3171 if (cfg.selftest)
ee38a438 3172 CheckSelfTestLogs(cfg, state, SelfTestErrorCount(atadev, name, cfg.firmwarebugs));
2127e193 3173
832b75ed 3174 // check if number of ATA errors has increased
e9583e0c 3175 if (cfg.errorlog || cfg.xerrorlog) {
832b75ed 3176
e9583e0c
GI
3177 int errcnt1 = -1, errcnt2 = -1;
3178 if (cfg.errorlog)
ee38a438 3179 errcnt1 = read_ata_error_count(atadev, name, cfg.firmwarebugs, false);
e9583e0c 3180 if (cfg.xerrorlog)
ee38a438 3181 errcnt2 = read_ata_error_count(atadev, name, cfg.firmwarebugs, true);
832b75ed 3182
e9583e0c
GI
3183 // new number of errors is max of both logs
3184 int newc = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2);
832b75ed
GG
3185
3186 // did command fail?
4d59bff9 3187 if (newc<0)
832b75ed 3188 // lack of PrintOut here is INTENTIONAL
2127e193 3189 MailWarning(cfg, state, 7, "Device: %s, Read SMART Error Log Failed", name);
832b75ed
GG
3190
3191 // has error count increased?
e9583e0c 3192 int oldc = state.ataerrorcount;
4d59bff9 3193 if (newc>oldc){
832b75ed 3194 PrintOut(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
4d59bff9 3195 name, oldc, newc);
2127e193 3196 MailWarning(cfg, state, 4, "Device: %s, ATA error count increased from %d to %d",
4d59bff9 3197 name, oldc, newc);
2127e193 3198 state.must_write = true;
832b75ed 3199 }
e9583e0c 3200
4d59bff9 3201 if (newc>=0)
2127e193 3202 state.ataerrorcount=newc;
832b75ed 3203 }
2127e193
GI
3204
3205 // if the user has asked, and device is capable (or we're not yet
3206 // sure) check whether a self test should be done now.
3207 if (allow_selftests && !cfg.test_regex.empty()) {
3208 char testtype = next_scheduled_test(cfg, state, false/*!scsi*/);
3209 if (testtype)
3210 DoATASelfTest(cfg, state, atadev, testtype);
3211 }
3212
832b75ed
GG
3213 // Don't leave device open -- the OS/user may want to access it
3214 // before the next smartd cycle!
2127e193
GI
3215 CloseDevice(atadev, name);
3216
3217 // Copy ATA attribute values to persistent state
3218 state.update_persistent_state();
3219
832b75ed
GG
3220 return 0;
3221}
3222
2127e193 3223static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_device * scsidev, bool allow_selftests)
832b75ed
GG
3224{
3225 UINT8 asc, ascq;
3226 UINT8 currenttemp;
3227 UINT8 triptemp;
ee38a438 3228 UINT8 tBuf[252];
2127e193 3229 const char * name = cfg.name.c_str();
832b75ed
GG
3230 const char *cp;
3231
3232 // If the user has asked for it, test the email warning system
2127e193
GI
3233 if (cfg.emailtest)
3234 MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name);
832b75ed
GG
3235
3236 // if we can't open device, fail gracefully rather than hard --
3237 // perhaps the next time around we'll be able to open it
2127e193
GI
3238 if (!scsidev->open()) {
3239 PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", name, scsidev->get_errmsg());
3240 MailWarning(cfg, state, 9, "Device: %s, unable to open device", name);
832b75ed 3241 return 1;
ba59cff1
GG
3242 } else if (debugmode)
3243 PrintOut(LOG_INFO,"Device: %s, opened SCSI device\n", name);
ee38a438 3244 reset_warning_mail(cfg, state, 9, "open device worked again");
832b75ed
GG
3245 currenttemp = 0;
3246 asc = 0;
3247 ascq = 0;
2127e193
GI
3248 if (!state.SuppressReport) {
3249 if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported,
832b75ed
GG
3250 &asc, &ascq, &currenttemp, &triptemp)) {
3251 PrintOut(LOG_INFO, "Device: %s, failed to read SMART values\n",
3252 name);
2127e193
GI
3253 MailWarning(cfg, state, 6, "Device: %s, failed to read SMART values", name);
3254 state.SuppressReport = 1;
832b75ed
GG
3255 }
3256 }
3257 if (asc > 0) {
3258 cp = scsiGetIEString(asc, ascq);
3259 if (cp) {
3260 PrintOut(LOG_CRIT, "Device: %s, SMART Failure: %s\n", name, cp);
2127e193 3261 MailWarning(cfg, state, 1,"Device: %s, SMART Failure: %s", name, cp);
ee38a438
GI
3262 } else if (asc == 4 && ascq == 9) {
3263 PrintOut(LOG_INFO,"Device: %s, self-test in progress\n", name);
ba59cff1
GG
3264 } else if (debugmode)
3265 PrintOut(LOG_INFO,"Device: %s, non-SMART asc,ascq: %d,%d\n",
3266 name, (int)asc, (int)ascq);
832b75ed 3267 } else if (debugmode)
ba59cff1 3268 PrintOut(LOG_INFO,"Device: %s, SMART health: passed\n", name);
4d59bff9
GG
3269
3270 // check temperature limits
ee38a438 3271 if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit || !cfg.attrlog_file.empty())
2127e193 3272 CheckTemperature(cfg, state, currenttemp, triptemp);
4d59bff9 3273
832b75ed 3274 // check if number of selftest errors has increased (note: may also DECREASE)
2127e193
GI
3275 if (cfg.selftest)
3276 CheckSelfTestLogs(cfg, state, scsiCountFailedSelfTests(scsidev, 0));
832b75ed 3277
2127e193
GI
3278 if (allow_selftests && !cfg.test_regex.empty()) {
3279 char testtype = next_scheduled_test(cfg, state, true/*scsi*/);
3280 if (testtype)
3281 DoSCSISelfTest(cfg, state, scsidev, testtype);
832b75ed 3282 }
ee38a438
GI
3283 if (!cfg.attrlog_file.empty()){
3284 // saving error counters to state
3285 if (state.ReadECounterPageSupported && (0 == scsiLogSense(scsidev,
3286 READ_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
3287 scsiDecodeErrCounterPage(tBuf, &state.scsi_error_counters[0].errCounter);
3288 state.scsi_error_counters[0].found=1;
3289 }
3290 if (state.WriteECounterPageSupported && (0 == scsiLogSense(scsidev,
3291 WRITE_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
3292 scsiDecodeErrCounterPage(tBuf, &state.scsi_error_counters[1].errCounter);
3293 state.scsi_error_counters[1].found=1;
3294 }
3295 if (state.VerifyECounterPageSupported && (0 == scsiLogSense(scsidev,
3296 VERIFY_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
3297 scsiDecodeErrCounterPage(tBuf, &state.scsi_error_counters[2].errCounter);
3298 state.scsi_error_counters[2].found=1;
3299 }
3300 if (state.NonMediumErrorPageSupported && (0 == scsiLogSense(scsidev,
3301 NON_MEDIUM_ERROR_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
3302 scsiDecodeNonMediumErrPage(tBuf, &state.scsi_nonmedium_error.nme);
3303 state.scsi_nonmedium_error.found=1;
3304 }
3305 }
2127e193 3306 CloseDevice(scsidev, name);
832b75ed
GG
3307 return 0;
3308}
3309
d008864d
GI
3310// 0=not used, 1=not disabled, 2=disable rejected by OS, 3=disabled
3311static int standby_disable_state = 0;
3312
3313static void init_disable_standby_check(dev_config_vector & configs)
3314{
3315 // Check for '-l offlinests,ns' or '-l selfteststs,ns' directives
3316 bool sts1 = false, sts2 = false;
3317 for (unsigned i = 0; i < configs.size() && !(sts1 || sts2); i++) {
3318 const dev_config & cfg = configs.at(i);
3319 if (cfg.offlinests_ns)
3320 sts1 = true;
3321 if (cfg.selfteststs_ns)
3322 sts2 = true;
3323 }
3324
3325 // Check for support of disable auto standby
3326 // Reenable standby if smartd.conf was reread
3327 if (sts1 || sts2 || standby_disable_state == 3) {
3328 if (!smi()->disable_system_auto_standby(false)) {
3329 if (standby_disable_state == 3)
3330 PrintOut(LOG_CRIT, "System auto standby enable failed: %s\n", smi()->get_errmsg());
3331 if (sts1 || sts2) {
3332 PrintOut(LOG_INFO, "Disable auto standby not supported, ignoring ',ns' from %s%s%s\n",
3333 (sts1 ? "-l offlinests,ns" : ""), (sts1 && sts2 ? " and " : ""), (sts2 ? "-l selfteststs,ns" : ""));
3334 sts1 = sts2 = false;
3335 }
3336 }
3337 }
3338
3339 standby_disable_state = (sts1 || sts2 ? 1 : 0);
3340}
3341
3342static void do_disable_standby_check(const dev_config_vector & configs, const dev_state_vector & states)
3343{
3344 if (!standby_disable_state)
3345 return;
3346
3347 // Check for just started or still running self-tests
3348 bool running = false;
3349 for (unsigned i = 0; i < configs.size() && !running; i++) {
3350 const dev_config & cfg = configs.at(i); const dev_state & state = states.at(i);
3351
3352 if ( ( cfg.offlinests_ns
3353 && (state.offline_started ||
3354 is_offl_coll_in_progress(state.smartval.offline_data_collection_status)))
3355 || ( cfg.selfteststs_ns
3356 && (state.selftest_started ||
3357 is_self_test_in_progress(state.smartval.self_test_exec_status))) )
3358 running = true;
3359 // state.offline/selftest_started will be reset after next logging of test status
3360 }
3361
3362 // Disable/enable auto standby and log state changes
3363 if (!running) {
3364 if (standby_disable_state != 1) {
3365 if (!smi()->disable_system_auto_standby(false))
3366 PrintOut(LOG_CRIT, "Self-test(s) completed, system auto standby enable failed: %s\n",
3367 smi()->get_errmsg());
3368 else
3369 PrintOut(LOG_INFO, "Self-test(s) completed, system auto standby enabled\n");
3370 standby_disable_state = 1;
3371 }
3372 }
3373 else if (!smi()->disable_system_auto_standby(true)) {
3374 if (standby_disable_state != 2) {
3375 PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disable rejected: %s\n",
3376 smi()->get_errmsg());
3377 standby_disable_state = 2;
3378 }
3379 }
3380 else {
3381 if (standby_disable_state != 3) {
3382 PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disabled\n");
3383 standby_disable_state = 3;
3384 }
3385 }
3386}
3387
832b75ed 3388// Checks the SMART status of all ATA and SCSI devices
2127e193 3389static void CheckDevicesOnce(const dev_config_vector & configs, dev_state_vector & states,
a7e8ffec 3390 smart_device_list & devices, bool firstpass, bool allow_selftests)
2127e193
GI
3391{
3392 for (unsigned i = 0; i < configs.size(); i++) {
3393 const dev_config & cfg = configs.at(i);
3394 dev_state & state = states.at(i);
3395 smart_device * dev = devices.at(i);
3396 if (dev->is_ata())
a7e8ffec 3397 ATACheckDevice(cfg, state, dev->to_ata(), firstpass, allow_selftests);
2127e193
GI
3398 else if (dev->is_scsi())
3399 SCSICheckDevice(cfg, state, dev->to_scsi(), allow_selftests);
34ad0c5f 3400 }
d008864d
GI
3401
3402 do_disable_standby_check(configs, states);
832b75ed
GG
3403}
3404
2127e193
GI
3405// Set if Initialize() was called
3406static bool is_initialized = false;
832b75ed
GG
3407
3408// Does initialization right after fork to daemon mode
cfbba5b9
GI
3409static void Initialize(time_t *wakeuptime)
3410{
2127e193
GI
3411 // Call Goodbye() on exit
3412 is_initialized = true;
832b75ed 3413
2127e193 3414 // write PID file
832b75ed
GG
3415 if (!debugmode)
3416 WritePidFile();
3417
3418 // install signal handlers. On Solaris, can't use signal() because
3419 // it resets the handler to SIG_DFL after each call. So use sigset()
3420 // instead. So SIGNALFN()==signal() or SIGNALFN()==sigset().
3421
3422 // normal and abnormal exit
3423 if (SIGNALFN(SIGTERM, sighandler)==SIG_IGN)
3424 SIGNALFN(SIGTERM, SIG_IGN);
3425 if (SIGNALFN(SIGQUIT, sighandler)==SIG_IGN)
3426 SIGNALFN(SIGQUIT, SIG_IGN);
3427
3428 // in debug mode, <CONTROL-C> ==> HUP
3429 if (SIGNALFN(SIGINT, debugmode?HUPhandler:sighandler)==SIG_IGN)
3430 SIGNALFN(SIGINT, SIG_IGN);
3431
3432 // Catch HUP and USR1
3433 if (SIGNALFN(SIGHUP, HUPhandler)==SIG_IGN)
3434 SIGNALFN(SIGHUP, SIG_IGN);
3435 if (SIGNALFN(SIGUSR1, USR1handler)==SIG_IGN)
3436 SIGNALFN(SIGUSR1, SIG_IGN);
3437#ifdef _WIN32
3438 if (SIGNALFN(SIGUSR2, USR2handler)==SIG_IGN)
3439 SIGNALFN(SIGUSR2, SIG_IGN);
3440#endif
3441
3442 // initialize wakeup time to CURRENT time
3443 *wakeuptime=time(NULL);
3444
3445 return;
3446}
3447
3448#ifdef _WIN32
3449// Toggle debug mode implemented for native windows only
3450// (there is no easy way to reopen tty on *nix)
3451static void ToggleDebugMode()
3452{
3453 if (!debugmode) {
3454 PrintOut(LOG_INFO,"Signal USR2 - enabling debug mode\n");
3455 if (!daemon_enable_console("smartd [Debug]")) {
3456 debugmode = 1;
3457 daemon_signal(SIGINT, HUPhandler);
3458 PrintOut(LOG_INFO,"smartd debug mode enabled, PID=%d\n", getpid());
3459 }
3460 else
3461 PrintOut(LOG_INFO,"enable console failed\n");
3462 }
3463 else if (debugmode == 1) {
3464 daemon_disable_console();
3465 debugmode = 0;
3466 daemon_signal(SIGINT, sighandler);
3467 PrintOut(LOG_INFO,"Signal USR2 - debug mode disabled\n");
3468 }
3469 else
3470 PrintOut(LOG_INFO,"Signal USR2 - debug mode %d not changed\n", debugmode);
3471}
3472#endif
3473
2127e193
GI
3474static time_t dosleep(time_t wakeuptime, bool & sigwakeup)
3475{
832b75ed 3476 // If past wake-up-time, compute next wake-up-time
2127e193 3477 time_t timenow=time(NULL);
832b75ed
GG
3478 while (wakeuptime<=timenow){
3479 int intervals=1+(timenow-wakeuptime)/checktime;
3480 wakeuptime+=intervals*checktime;
3481 }
3482
3483 // sleep until we catch SIGUSR1 or have completed sleeping
d008864d
GI
3484 int addtime = 0;
3485 while (timenow < wakeuptime+addtime && !caughtsigUSR1 && !caughtsigHUP && !caughtsigEXIT) {
832b75ed
GG
3486
3487 // protect user again system clock being adjusted backwards
3488 if (wakeuptime>timenow+checktime){
3489 PrintOut(LOG_CRIT, "System clock time adjusted to the past. Resetting next wakeup time.\n");
3490 wakeuptime=timenow+checktime;
3491 }
3492
3493 // Exit sleep when time interval has expired or a signal is received
d008864d 3494 sleep(wakeuptime+addtime-timenow);
832b75ed
GG
3495
3496#ifdef _WIN32
3497 // toggle debug mode?
3498 if (caughtsigUSR2) {
3499 ToggleDebugMode();
3500 caughtsigUSR2 = 0;
3501 }
3502#endif
3503
3504 timenow=time(NULL);
d008864d
GI
3505
3506 // Actual sleep time too long?
3507 if (!addtime && timenow > wakeuptime+60) {
3508 if (debugmode)
3509 PrintOut(LOG_INFO, "Sleep time was %d seconds too long, assuming wakeup from standby mode.\n",
3510 (int)(timenow-wakeuptime));
3511 // Wait another 20 seconds to avoid I/O errors during disk spin-up
3512 addtime = timenow-wakeuptime+20;
3513 // Use next wake-up-time if close
3514 int nextcheck = checktime - addtime % checktime;
3515 if (nextcheck <= 20)
3516 addtime += nextcheck;
3517 }
832b75ed
GG
3518 }
3519
3520 // if we caught a SIGUSR1 then print message and clear signal
3521 if (caughtsigUSR1){
3522 PrintOut(LOG_INFO,"Signal USR1 - checking devices now rather than in %d seconds.\n",
3523 wakeuptime-timenow>0?(int)(wakeuptime-timenow):0);
3524 caughtsigUSR1=0;
2127e193 3525 sigwakeup = true;
832b75ed
GG
3526 }
3527
3528 // return adjusted wakeuptime
3529 return wakeuptime;
3530}
3531
3532// Print out a list of valid arguments for the Directive d
cfbba5b9
GI
3533static void printoutvaliddirectiveargs(int priority, char d)
3534{
832b75ed
GG
3535 switch (d) {
3536 case 'n':
2127e193 3537 PrintOut(priority, "never[,N][,q], sleep[,N][,q], standby[,N][,q], idle[,N][,q]");
832b75ed
GG
3538 break;
3539 case 's':
3540 PrintOut(priority, "valid_regular_expression");
3541 break;
3542 case 'd':
54965743 3543 PrintOut(priority, "%s", smi()->get_valid_dev_types_str().c_str());
832b75ed
GG
3544 break;
3545 case 'T':
3546 PrintOut(priority, "normal, permissive");
3547 break;
3548 case 'o':
3549 case 'S':
3550 PrintOut(priority, "on, off");
3551 break;
3552 case 'l':
3553 PrintOut(priority, "error, selftest");
3554 break;
3555 case 'M':
3556 PrintOut(priority, "\"once\", \"daily\", \"diminishing\", \"test\", \"exec\"");
3557 break;
3558 case 'v':
2127e193 3559 PrintOut(priority, "\n%s\n", create_vendor_attribute_arg_list().c_str());
832b75ed
GG
3560 break;
3561 case 'P':
3562 PrintOut(priority, "use, ignore, show, showall");
3563 break;
3564 case 'F':
ee38a438
GI
3565 PrintOut(priority, "%s", get_valid_firmwarebug_args());
3566 break;
d008864d
GI
3567 case 'e':
3568 PrintOut(priority, "aam,[N|off], apm,[N|off], lookahead,[on|off], "
3569 "security-freeze, standby,[N|off], wcache,[on|off]");
832b75ed
GG
3570 break;
3571 }
3572}
3573
3574// exits with an error message, or returns integer value of token
cfbba5b9 3575static int GetInteger(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile,
2127e193
GI
3576 int min, int max, char * suffix = 0)
3577{
832b75ed
GG
3578 // make sure argument is there
3579 if (!arg) {
3580 PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes integer argument from %d to %d.\n",
cfbba5b9 3581 cfgfile, lineno, name, token, min, max);
832b75ed
GG
3582 return -1;
3583 }
3584
3585 // get argument value (base 10), check that it's integer, and in-range
2127e193
GI
3586 char *endptr;
3587 int val = strtol(arg,&endptr,10);
3588
3589 // optional suffix present?
3590 if (suffix) {
3591 if (!strcmp(endptr, suffix))
3592 endptr += strlen(suffix);
3593 else
3594 *suffix = 0;
3595 }
3596
3597 if (!(!*endptr && min <= val && val <= max)) {
832b75ed 3598 PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n",
cfbba5b9 3599 cfgfile, lineno, name, token, arg, min, max);
832b75ed
GG
3600 return -1;
3601 }
3602
3603 // all is well; return value
3604 return val;
3605}
3606
4d59bff9
GG
3607
3608// Get 1-3 small integer(s) for '-W' directive
cfbba5b9
GI
3609static int Get3Integers(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile,
3610 unsigned char *val1, unsigned char *val2, unsigned char *val3)
3611{
4d59bff9
GG
3612 unsigned v1 = 0, v2 = 0, v3 = 0;
3613 int n1 = -1, n2 = -1, n3 = -1, len;
3614 if (!arg) {
3615 PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes 1-3 integer argument(s) from 0 to 255.\n",
cfbba5b9 3616 cfgfile, lineno, name, token);
4d59bff9
GG
3617 return -1;
3618 }
3619
3620 len = strlen(arg);
3621 if (!( sscanf(arg, "%u%n,%u%n,%u%n", &v1, &n1, &v2, &n2, &v3, &n3) >= 1
3622 && (n1 == len || n2 == len || n3 == len) && v1 <= 255 && v2 <= 255 && v3 <= 255)) {
3623 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 3624 cfgfile, lineno, name, token, arg);
4d59bff9
GG
3625 return -1;
3626 }
3627 *val1 = (unsigned char)v1; *val2 = (unsigned char)v2; *val3 = (unsigned char)v3;
3628 return 0;
3629}
3630
3631
ee38a438
GI
3632#ifdef _WIN32
3633
3634// Concatenate strtok() results if quoted with "..."
3635static const char * strtok_dequote(const char * delimiters)
3636{
3637 const char * t = strtok(0, delimiters);
3638 if (!t || t[0] != '"')
3639 return t;
3640
3641 static std::string token;
3642 token = t+1;
3643 for (;;) {
3644 t = strtok(0, delimiters);
3645 if (!t || !*t)
3646 return "\"";
3647 token += ' ';
3648 int len = strlen(t);
3649 if (t[len-1] == '"') {
3650 token += std::string(t, len-1);
3651 break;
3652 }
3653 token += t;
3654 }
3655 return token.c_str();
3656}
3657
3658#endif // _WIN32
3659
3660
832b75ed
GG
3661// This function returns 1 if it has correctly parsed one token (and
3662// any arguments), else zero if no tokens remain. It returns -1 if an
3663// error was encountered.
2127e193
GI
3664static int ParseToken(char * token, dev_config & cfg)
3665{
832b75ed 3666 char sym;
2127e193
GI
3667 const char * name = cfg.name.c_str();
3668 int lineno=cfg.lineno;
3669 const char *delim = " \n\t";
832b75ed
GG
3670 int badarg = 0;
3671 int missingarg = 0;
2127e193 3672 const char *arg = 0;
832b75ed
GG
3673
3674 // is the rest of the line a comment
3675 if (*token=='#')
3676 return 1;
3677
3678 // is the token not recognized?
3679 if (*token!='-' || strlen(token)!=2) {
3680 PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
3681 configfile, lineno, name, token);
3682 PrintOut(LOG_CRIT, "Run smartd -D to print a list of valid Directives.\n");
3683 return -1;
3684 }
3685
3686 // token we will be parsing:
3687 sym=token[1];
3688
832b75ed 3689 // parse the token and swallow its argument
2127e193
GI
3690 int val;
3691 char plus[] = "+", excl[] = "!";
832b75ed 3692
2127e193 3693 switch (sym) {
832b75ed
GG
3694 case 'C':
3695 // monitor current pending sector count (default 197)
2127e193 3696 if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255, plus)) < 0)
832b75ed 3697 return -1;
2127e193
GI
3698 cfg.curr_pending_id = (unsigned char)val;
3699 cfg.curr_pending_incr = (*plus == '+');
3700 cfg.curr_pending_set = true;
832b75ed
GG
3701 break;
3702 case 'U':
3703 // monitor offline uncorrectable sectors (default 198)
2127e193 3704 if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 0, 255, plus)) < 0)
832b75ed 3705 return -1;
2127e193
GI
3706 cfg.offl_pending_id = (unsigned char)val;
3707 cfg.offl_pending_incr = (*plus == '+');
3708 cfg.offl_pending_set = true;
832b75ed
GG
3709 break;
3710 case 'T':
3711 // Set tolerance level for SMART command failures
3712 if ((arg = strtok(NULL, delim)) == NULL) {
3713 missingarg = 1;
3714 } else if (!strcmp(arg, "normal")) {
3715 // Normal mode: exit on failure of a mandatory S.M.A.R.T. command, but
3716 // not on failure of an optional S.M.A.R.T. command.
3717 // This is the default so we don't need to actually do anything here.
2127e193 3718 cfg.permissive = false;
832b75ed
GG
3719 } else if (!strcmp(arg, "permissive")) {
3720 // Permissive mode; ignore errors from Mandatory SMART commands
2127e193 3721 cfg.permissive = true;
832b75ed
GG
3722 } else {
3723 badarg = 1;
3724 }
3725 break;
3726 case 'd':
3727 // specify the device type
3728 if ((arg = strtok(NULL, delim)) == NULL) {
3729 missingarg = 1;
ee38a438
GI
3730 } else if (!strcmp(arg, "ignore")) {
3731 cfg.ignore = true;
832b75ed 3732 } else if (!strcmp(arg, "removable")) {
2127e193 3733 cfg.removable = true;
cfbba5b9
GI
3734 } else if (!strcmp(arg, "auto")) {
3735 cfg.dev_type = "";
832b75ed 3736 } else {
2127e193 3737 cfg.dev_type = arg;
832b75ed
GG
3738 }
3739 break;
3740 case 'F':
3741 // fix firmware bug
ee38a438 3742 if (!(arg = strtok(0, delim)))
832b75ed 3743 missingarg = 1;
ee38a438 3744 else if (!parse_firmwarebug_def(arg, cfg.firmwarebugs))
832b75ed 3745 badarg = 1;
832b75ed
GG
3746 break;
3747 case 'H':
3748 // check SMART status
2127e193 3749 cfg.smartcheck = true;
832b75ed
GG
3750 break;
3751 case 'f':
3752 // check for failure of usage attributes
2127e193 3753 cfg.usagefailed = true;
832b75ed
GG
3754 break;
3755 case 't':
3756 // track changes in all vendor attributes
2127e193
GI
3757 cfg.prefail = true;
3758 cfg.usage = true;
832b75ed
GG
3759 break;
3760 case 'p':
3761 // track changes in prefail vendor attributes
2127e193 3762 cfg.prefail = true;
832b75ed
GG
3763 break;
3764 case 'u':
3765 // track changes in usage vendor attributes
2127e193 3766 cfg.usage = true;
832b75ed
GG
3767 break;
3768 case 'l':
3769 // track changes in SMART logs
3770 if ((arg = strtok(NULL, delim)) == NULL) {
3771 missingarg = 1;
3772 } else if (!strcmp(arg, "selftest")) {
3773 // track changes in self-test log
2127e193 3774 cfg.selftest = true;
832b75ed
GG
3775 } else if (!strcmp(arg, "error")) {
3776 // track changes in ATA error log
2127e193 3777 cfg.errorlog = true;
e9583e0c
GI
3778 } else if (!strcmp(arg, "xerror")) {
3779 // track changes in Extended Comprehensive SMART error log
3780 cfg.xerrorlog = true;
d008864d
GI
3781 } else if (!strcmp(arg, "offlinests")) {
3782 // track changes in offline data collection status
3783 cfg.offlinests = true;
3784 } else if (!strcmp(arg, "offlinests,ns")) {
3785 // track changes in offline data collection status, disable auto standby
3786 cfg.offlinests = cfg.offlinests_ns = true;
3787 } else if (!strcmp(arg, "selfteststs")) {
3788 // track changes in self-test execution status
3789 cfg.selfteststs = true;
3790 } else if (!strcmp(arg, "selfteststs,ns")) {
3791 // track changes in self-test execution status, disable auto standby
3792 cfg.selfteststs = cfg.selfteststs_ns = true;
cfbba5b9
GI
3793 } else if (!strncmp(arg, "scterc,", sizeof("scterc,")-1)) {
3794 // set SCT Error Recovery Control
3795 unsigned rt = ~0, wt = ~0; int nc = -1;
3796 sscanf(arg,"scterc,%u,%u%n", &rt, &wt, &nc);
3797 if (nc == (int)strlen(arg) && rt <= 999 && wt <= 999) {
3798 cfg.sct_erc_set = true;
3799 cfg.sct_erc_readtime = rt;
3800 cfg.sct_erc_writetime = wt;
3801 }
3802 else
3803 badarg = 1;
832b75ed
GG
3804 } else {
3805 badarg = 1;
3806 }
3807 break;
3808 case 'a':
3809 // monitor everything
2127e193
GI
3810 cfg.smartcheck = true;
3811 cfg.prefail = true;
3812 cfg.usagefailed = true;
3813 cfg.usage = true;
3814 cfg.selftest = true;
3815 cfg.errorlog = true;
d008864d 3816 cfg.selfteststs = true;
832b75ed
GG
3817 break;
3818 case 'o':
3819 // automatic offline testing enable/disable
3820 if ((arg = strtok(NULL, delim)) == NULL) {
3821 missingarg = 1;
3822 } else if (!strcmp(arg, "on")) {
2127e193 3823 cfg.autoofflinetest = 2;
832b75ed 3824 } else if (!strcmp(arg, "off")) {
2127e193 3825 cfg.autoofflinetest = 1;
832b75ed
GG
3826 } else {
3827 badarg = 1;
3828 }
3829 break;
3830 case 'n':
3831 // skip disk check if in idle or standby mode
3832 if (!(arg = strtok(NULL, delim)))
3833 missingarg = 1;
2127e193
GI
3834 else {
3835 char *endptr = NULL;
3836 char *next = strchr(const_cast<char*>(arg), ',');
3837
3838 cfg.powerquiet = false;
3839 cfg.powerskipmax = 0;
3840
3841 if (next!=NULL) *next='\0';
3842 if (!strcmp(arg, "never"))
3843 cfg.powermode = 0;
3844 else if (!strcmp(arg, "sleep"))
3845 cfg.powermode = 1;
3846 else if (!strcmp(arg, "standby"))
3847 cfg.powermode = 2;
3848 else if (!strcmp(arg, "idle"))
3849 cfg.powermode = 3;
3850 else
3851 badarg = 1;
3852
3853 // if optional arguments are present
3854 if (!badarg && next!=NULL) {
3855 next++;
3856 cfg.powerskipmax = strtol(next, &endptr, 10);
3857 if (endptr == next)
3858 cfg.powerskipmax = 0;
3859 else {
3860 next = endptr + (*endptr != '\0');
3861 if (cfg.powerskipmax <= 0)
3862 badarg = 1;
3863 }
3864 if (*next != '\0') {
3865 if (!strcmp("q", next))
3866 cfg.powerquiet = true;
3867 else {
3868 badarg = 1;
3869 }
3870 }
3871 }
3872 }
832b75ed
GG
3873 break;
3874 case 'S':
3875 // automatic attribute autosave enable/disable
3876 if ((arg = strtok(NULL, delim)) == NULL) {
3877 missingarg = 1;
3878 } else if (!strcmp(arg, "on")) {
2127e193 3879 cfg.autosave = 2;
832b75ed 3880 } else if (!strcmp(arg, "off")) {
2127e193 3881 cfg.autosave = 1;
832b75ed
GG
3882 } else {
3883 badarg = 1;
3884 }
3885 break;
3886 case 's':
3887 // warn user, and delete any previously given -s REGEXP Directives
2127e193 3888 if (!cfg.test_regex.empty()){
832b75ed 3889 PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Test Directive -s %s\n",
2127e193
GI
3890 configfile, lineno, name, cfg.test_regex.get_pattern());
3891 cfg.test_regex = regular_expression();
832b75ed
GG
3892 }
3893 // check for missing argument
3894 if (!(arg = strtok(NULL, delim))) {
3895 missingarg = 1;
3896 }
2127e193
GI
3897 // Compile regex
3898 else {
3899 if (!cfg.test_regex.compile(arg, REG_EXTENDED)) {
3900 // not a valid regular expression!
3901 PrintOut(LOG_CRIT, "File %s line %d (drive %s): -s argument \"%s\" is INVALID extended regular expression. %s.\n",
3902 configfile, lineno, name, arg, cfg.test_regex.get_errmsg());
3903 return -1;
3904 }
832b75ed
GG
3905 }
3906 // Do a bit of sanity checking and warn user if we think that
3907 // their regexp is "strange". User probably confused about shell
3908 // glob(3) syntax versus regular expression syntax regexp(7).
2127e193 3909 if (arg[(val = strspn(arg, "0123456789/.-+*|()?^$[]SLCOcnr"))])
832b75ed
GG
3910 PrintOut(LOG_INFO, "File %s line %d (drive %s): warning, character %d (%c) looks odd in extended regular expression %s\n",
3911 configfile, lineno, name, val+1, arg[val], arg);
3912 break;
3913 case 'm':
3914 // send email to address that follows
3915 if (!(arg = strtok(NULL,delim)))
3916 missingarg = 1;
3917 else {
2127e193 3918 if (!cfg.emailaddress.empty())
832b75ed 3919 PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Address Directive -m %s\n",
2127e193 3920 configfile, lineno, name, cfg.emailaddress.c_str());
ee38a438
GI
3921#ifdef _WIN32
3922 if ( !strcmp(arg, "msgbox") || !strcmp(arg, "sysmsgbox")
3923 || str_starts_with(arg, "msgbox,") || str_starts_with(arg, "sysmsgbox,")) {
3924 cfg.emailaddress = "console";
3925 const char * arg2 = strchr(arg, ',');
3926 if (arg2)
3927 cfg.emailaddress += arg2;
3928 PrintOut(LOG_INFO, "File %s line %d (drive %s): Deprecated -m %s changed to -m %s\n",
3929 configfile, lineno, name, arg, cfg.emailaddress.c_str());
3930 }
3931 else
3932#endif
2127e193 3933 cfg.emailaddress = arg;
832b75ed
GG
3934 }
3935 break;
3936 case 'M':
3937 // email warning options
3938 if (!(arg = strtok(NULL, delim)))
3939 missingarg = 1;
3940 else if (!strcmp(arg, "once"))
2127e193 3941 cfg.emailfreq = 1;
832b75ed 3942 else if (!strcmp(arg, "daily"))
2127e193 3943 cfg.emailfreq = 2;
832b75ed 3944 else if (!strcmp(arg, "diminishing"))
2127e193 3945 cfg.emailfreq = 3;
832b75ed 3946 else if (!strcmp(arg, "test"))
2127e193 3947 cfg.emailtest = 1;
832b75ed
GG
3948 else if (!strcmp(arg, "exec")) {
3949 // Get the next argument (the command line)
ee38a438
GI
3950#ifdef _WIN32
3951 // Allow "/path name/with spaces/..." on Windows
3952 arg = strtok_dequote(delim);
3953 if (arg && arg[0] == '"') {
3954 PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive %s 'exec' argument: missing closing quote\n",
3955 configfile, lineno, name, token);
3956 return -1;
3957 }
3958#else
3959 arg = strtok(0, delim);
3960#endif
3961 if (!arg) {
832b75ed
GG
3962 PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive %s 'exec' argument must be followed by executable path.\n",
3963 configfile, lineno, name, token);
3964 return -1;
3965 }
3966 // Free the last cmd line given if any, and copy new one
2127e193 3967 if (!cfg.emailcmdline.empty())
832b75ed 3968 PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous mail Directive -M exec %s\n",
2127e193
GI
3969 configfile, lineno, name, cfg.emailcmdline.c_str());
3970 cfg.emailcmdline = arg;
832b75ed
GG
3971 }
3972 else
3973 badarg = 1;
3974 break;
3975 case 'i':
3976 // ignore failure of usage attribute
3977 if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0)
3978 return -1;
2127e193 3979 cfg.monitor_attr_flags.set(val, MONITOR_IGN_FAILUSE);
832b75ed
GG
3980 break;
3981 case 'I':
3982 // ignore attribute for tracking purposes
3983 if ((val=GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255))<0)
3984 return -1;
2127e193 3985 cfg.monitor_attr_flags.set(val, MONITOR_IGNORE);
832b75ed
GG
3986 break;
3987 case 'r':
3988 // print raw value when tracking
2127e193 3989 if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255, excl)) < 0)
832b75ed 3990 return -1;
2127e193
GI
3991 cfg.monitor_attr_flags.set(val, MONITOR_RAW_PRINT);
3992 if (*excl == '!') // attribute change is critical
3993 cfg.monitor_attr_flags.set(val, MONITOR_AS_CRIT);
832b75ed
GG
3994 break;
3995 case 'R':
3996 // track changes in raw value (forces printing of raw value)
2127e193 3997 if ((val = GetInteger(arg=strtok(NULL,delim), name, token, lineno, configfile, 1, 255, excl)) < 0)
832b75ed 3998 return -1;
2127e193
GI
3999 cfg.monitor_attr_flags.set(val, MONITOR_RAW_PRINT|MONITOR_RAW);
4000 if (*excl == '!') // raw value change is critical
4001 cfg.monitor_attr_flags.set(val, MONITOR_RAW_AS_CRIT);
832b75ed 4002 break;
4d59bff9
GG
4003 case 'W':
4004 // track Temperature
4005 if ((val=Get3Integers(arg=strtok(NULL,delim), name, token, lineno, configfile,
2127e193 4006 &cfg.tempdiff, &cfg.tempinfo, &cfg.tempcrit))<0)
4d59bff9 4007 return -1;
4d59bff9 4008 break;
832b75ed
GG
4009 case 'v':
4010 // non-default vendor-specific attribute meaning
4011 if (!(arg=strtok(NULL,delim))) {
4012 missingarg = 1;
bed94269 4013 } else if (!parse_attribute_def(arg, cfg.attribute_defs, PRIOR_USER)) {
832b75ed
GG
4014 badarg = 1;
4015 }
4016 break;
4017 case 'P':
4018 // Define use of drive-specific presets.
4019 if (!(arg = strtok(NULL, delim))) {
4020 missingarg = 1;
4021 } else if (!strcmp(arg, "use")) {
2127e193 4022 cfg.ignorepresets = false;
832b75ed 4023 } else if (!strcmp(arg, "ignore")) {
2127e193 4024 cfg.ignorepresets = true;
832b75ed 4025 } else if (!strcmp(arg, "show")) {
2127e193 4026 cfg.showpresets = true;
832b75ed
GG
4027 } else if (!strcmp(arg, "showall")) {
4028 showallpresets();
4029 } else {
4030 badarg = 1;
4031 }
4032 break;
d008864d
GI
4033
4034 case 'e':
4035 // Various ATA settings
4036 if (!(arg = strtok(NULL, delim))) {
4037 missingarg = true;
4038 }
4039 else {
4040 char arg2[16+1]; unsigned val;
4041 int n1 = -1, n2 = -1, n3 = -1, len = strlen(arg);
4042 if (sscanf(arg, "%16[^,=]%n%*[,=]%n%u%n", arg2, &n1, &n2, &val, &n3) >= 1
4043 && (n1 == len || n2 > 0)) {
4044 bool on = (n2 > 0 && !strcmp(arg+n2, "on"));
4045 bool off = (n2 > 0 && !strcmp(arg+n2, "off"));
4046 if (n3 != len)
4047 val = ~0U;
4048
4049 if (!strcmp(arg2, "aam")) {
4050 if (off)
4051 cfg.set_aam = -1;
4052 else if (val <= 254)
4053 cfg.set_aam = val + 1;
4054 else
4055 badarg = true;
4056 }
4057 else if (!strcmp(arg2, "apm")) {
4058 if (off)
4059 cfg.set_apm = -1;
4060 else if (1 <= val && val <= 254)
4061 cfg.set_apm = val + 1;
4062 else
4063 badarg = true;
4064 }
4065 else if (!strcmp(arg2, "lookahead")) {
4066 if (off)
4067 cfg.set_lookahead = -1;
4068 else if (on)
4069 cfg.set_lookahead = 1;
4070 else
4071 badarg = true;
4072 }
4073 else if (!strcmp(arg, "security-freeze")) {
4074 cfg.set_security_freeze = true;
4075 }
4076 else if (!strcmp(arg2, "standby")) {
4077 if (off)
4078 cfg.set_standby = 0 + 1;
4079 else if (val <= 255)
4080 cfg.set_standby = val + 1;
4081 else
4082 badarg = true;
4083 }
4084 else if (!strcmp(arg2, "wcache")) {
4085 if (off)
4086 cfg.set_wcache = -1;
4087 else if (on)
4088 cfg.set_wcache = 1;
4089 else
4090 badarg = true;
4091 }
4092 else
4093 badarg = true;
4094 }
4095 else
4096 badarg = true;
4097 }
4098 break;
4099
832b75ed
GG
4100 default:
4101 // Directive not recognized
4102 PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
4103 configfile, lineno, name, token);
4104 Directives();
4105 return -1;
4106 }
4107 if (missingarg) {
4108 PrintOut(LOG_CRIT, "File %s line %d (drive %s): Missing argument to %s Directive\n",
4109 configfile, lineno, name, token);
4110 }
4111 if (badarg) {
4112 PrintOut(LOG_CRIT, "File %s line %d (drive %s): Invalid argument to %s Directive: %s\n",
4113 configfile, lineno, name, token, arg);
4114 }
4115 if (missingarg || badarg) {
4116 PrintOut(LOG_CRIT, "Valid arguments to %s Directive are: ", token);
4117 printoutvaliddirectiveargs(LOG_CRIT, sym);
4118 PrintOut(LOG_CRIT, "\n");
4119 return -1;
4120 }
4121
832b75ed
GG
4122 return 1;
4123}
4124
2127e193
GI
4125// Scan directive for configuration file
4126#define SCANDIRECTIVE "DEVICESCAN"
832b75ed 4127
2127e193 4128// This is the routine that adds things to the conf_entries list.
832b75ed
GG
4129//
4130// Return values are:
4131// 1: parsed a normal line
d008864d 4132// 0: found DEFAULT setting or comment or blank line
832b75ed
GG
4133// -1: found SCANDIRECTIVE line
4134// -2: found an error
4135//
4136// Note: this routine modifies *line from the caller!
d008864d 4137static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & default_conf, int lineno, /*const*/ char * line)
2127e193 4138{
2127e193 4139 const char *delim = " \n\t";
832b75ed
GG
4140
4141 // get first token: device name. If a comment, skip line
d008864d
GI
4142 const char * name = strtok(line, delim);
4143 if (!name || *name == '#')
832b75ed 4144 return 0;
832b75ed 4145
d008864d
GI
4146 // Check device name for DEFAULT or DEVICESCAN
4147 int retval;
4148 if (!strcmp("DEFAULT", name)) {
4149 retval = 0;
4150 // Restart with empty defaults
4151 default_conf = dev_config();
832b75ed 4152 }
d008864d
GI
4153 else {
4154 retval = (!strcmp(SCANDIRECTIVE, name) ? -1 : 1);
4155 // Init new entry with current defaults
4156 conf_entries.push_back(default_conf);
4157 }
4158 dev_config & cfg = (retval ? conf_entries.back() : default_conf);
2127e193 4159
cfbba5b9
GI
4160 cfg.name = name; // Later replaced by dev->get_info().info_name
4161 cfg.dev_name = name; // If DEVICESCAN later replaced by get->dev_info().dev_name
d008864d 4162 cfg.lineno = lineno;
2127e193 4163
832b75ed 4164 // parse tokens one at a time from the file.
d008864d
GI
4165 while (char * token = strtok(0, delim)) {
4166 int rc = ParseToken(token, cfg);
4167 if (rc < 0)
832b75ed
GG
4168 // error found on the line
4169 return -2;
d008864d
GI
4170
4171 if (rc == 0)
4172 // No tokens left
4173 break;
4174
4175 // PrintOut(LOG_INFO,"Parsed token %s\n",token);
832b75ed 4176 }
d008864d
GI
4177
4178 // Don't perform checks below for DEFAULT entries
4179 if (retval == 0)
4180 return retval;
4181
832b75ed 4182 // If NO monitoring directives are set, then set all of them.
e9583e0c
GI
4183 if (!( cfg.smartcheck || cfg.selftest
4184 || cfg.errorlog || cfg.xerrorlog
d008864d 4185 || cfg.offlinests || cfg.selfteststs
e9583e0c
GI
4186 || cfg.usagefailed || cfg.prefail || cfg.usage
4187 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) {
832b75ed
GG
4188
4189 PrintOut(LOG_INFO,"Drive: %s, implied '-a' Directive on line %d of file %s\n",
2127e193 4190 cfg.name.c_str(), cfg.lineno, configfile);
832b75ed 4191
2127e193
GI
4192 cfg.smartcheck = true;
4193 cfg.usagefailed = true;
4194 cfg.prefail = true;
4195 cfg.usage = true;
4196 cfg.selftest = true;
4197 cfg.errorlog = true;
d008864d 4198 cfg.selfteststs = true;
832b75ed
GG
4199 }
4200
4201 // additional sanity check. Has user set -M options without -m?
2127e193 4202 if (cfg.emailaddress.empty() && (!cfg.emailcmdline.empty() || cfg.emailfreq || cfg.emailtest)){
832b75ed 4203 PrintOut(LOG_CRIT,"Drive: %s, -M Directive(s) on line %d of file %s need -m ADDRESS Directive\n",
2127e193 4204 cfg.name.c_str(), cfg.lineno, configfile);
832b75ed
GG
4205 return -2;
4206 }
4207
4208 // has the user has set <nomailer>?
2127e193 4209 if (cfg.emailaddress == "<nomailer>") {
832b75ed 4210 // check that -M exec is also set
2127e193 4211 if (cfg.emailcmdline.empty()){
832b75ed 4212 PrintOut(LOG_CRIT,"Drive: %s, -m <nomailer> Directive on line %d of file %s needs -M exec Directive\n",
2127e193 4213 cfg.name.c_str(), cfg.lineno, configfile);
832b75ed
GG
4214 return -2;
4215 }
ee38a438 4216 // From here on the sign of <nomailer> is cfg.emailaddress.empty() and !cfg.emailcmdline.empty()
2127e193 4217 cfg.emailaddress.clear();
832b75ed
GG
4218 }
4219
d008864d 4220 return retval;
832b75ed
GG
4221}
4222
832b75ed
GG
4223// Parses a configuration file. Return values are:
4224// N=>0: found N entries
4225// -1: syntax error in config file
4226// -2: config file does not exist
4227// -3: config file exists but cannot be read
4228//
4229// In the case where the return value is 0, there are three
4230// possiblities:
2127e193
GI
4231// Empty configuration file ==> conf_entries.empty()
4232// No configuration file ==> conf_entries[0].lineno == 0
7f0798ef 4233// SCANDIRECTIVE found ==> conf_entries.back().lineno != 0 (size >= 1)
2127e193
GI
4234static int ParseConfigFile(dev_config_vector & conf_entries)
4235{
4236 // maximum line length in configuration file
4237 const int MAXLINELEN = 256;
4238 // maximum length of a continued line in configuration file
4239 const int MAXCONTLINE = 1023;
832b75ed 4240
2127e193 4241 stdio_file f;
832b75ed 4242 // Open config file, if it exists and is not <stdin>
2127e193
GI
4243 if (!(configfile == configfile_stdin)) { // pointer comparison ok here
4244 if (!f.open(configfile,"r") && (errno!=ENOENT || !configfile_alt.empty())) {
832b75ed
GG
4245 // file exists but we can't read it or it should exist due to '-c' option
4246 int ret = (errno!=ENOENT ? -3 : -2);
4247 PrintOut(LOG_CRIT,"%s: Unable to open configuration file %s\n",
4248 strerror(errno),configfile);
4249 return ret;
4250 }
4251 }
4252 else // read from stdin ('-c -' option)
2127e193
GI
4253 f.open(stdin);
4254
d008864d
GI
4255 // Start with empty defaults
4256 dev_config default_conf;
4257
832b75ed 4258 // No configuration file found -- use fake one
2127e193
GI
4259 int entry = 0;
4260 if (!f) {
d2e702cf 4261 char fakeconfig[] = SCANDIRECTIVE " -a"; // TODO: Remove this hack, build cfg_entry.
2127e193 4262
d008864d 4263 if (ParseConfigLine(conf_entries, default_conf, 0, fakeconfig) != -1)
d2e702cf 4264 throw std::logic_error("Internal error parsing " SCANDIRECTIVE);
832b75ed
GG
4265 return 0;
4266 }
4267
4268#ifdef __CYGWIN__
2127e193 4269 setmode(fileno(f), O_TEXT); // Allow files with \r\n
832b75ed
GG
4270#endif
4271
4272 // configuration file exists
4273 PrintOut(LOG_INFO,"Opened configuration file %s\n",configfile);
4274
4275 // parse config file line by line
2127e193
GI
4276 int lineno = 1, cont = 0, contlineno = 0;
4277 char line[MAXLINELEN+2];
4278 char fullline[MAXCONTLINE+1];
4279
4280 for (;;) {
832b75ed
GG
4281 int len=0,scandevice;
4282 char *lastslash;
4283 char *comment;
4284 char *code;
4285
4286 // make debugging simpler
4287 memset(line,0,sizeof(line));
4288
4289 // get a line
2127e193 4290 code=fgets(line, MAXLINELEN+2, f);
832b75ed
GG
4291
4292 // are we at the end of the file?
4293 if (!code){
4294 if (cont) {
d008864d 4295 scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline);
832b75ed 4296 // See if we found a SCANDIRECTIVE directive
2127e193 4297 if (scandevice==-1)
832b75ed 4298 return 0;
832b75ed 4299 // did we find a syntax error
2127e193 4300 if (scandevice==-2)
832b75ed 4301 return -1;
832b75ed
GG
4302 // the final line is part of a continuation line
4303 cont=0;
4304 entry+=scandevice;
4305 }
4306 break;
4307 }
4308
4309 // input file line number
4310 contlineno++;
4311
4312 // See if line is too long
4313 len=strlen(line);
4314 if (len>MAXLINELEN){
2127e193 4315 const char *warn;
832b75ed
GG
4316 if (line[len-1]=='\n')
4317 warn="(including newline!) ";
4318 else
4319 warn="";
4320 PrintOut(LOG_CRIT,"Error: line %d of file %s %sis more than MAXLINELEN=%d characters.\n",
4321 (int)contlineno,configfile,warn,(int)MAXLINELEN);
832b75ed
GG
4322 return -1;
4323 }
4324
4325 // Ignore anything after comment symbol
4326 if ((comment=strchr(line,'#'))){
4327 *comment='\0';
4328 len=strlen(line);
4329 }
4330
4331 // is the total line (made of all continuation lines) too long?
4332 if (cont+len>MAXCONTLINE){
4333 PrintOut(LOG_CRIT,"Error: continued line %d (actual line %d) of file %s is more than MAXCONTLINE=%d characters.\n",
4334 lineno, (int)contlineno, configfile, (int)MAXCONTLINE);
832b75ed
GG
4335 return -1;
4336 }
4337
4338 // copy string so far into fullline, and increment length
ee38a438 4339 snprintf(fullline+cont, sizeof(fullline)-cont, "%s" ,line);
832b75ed
GG
4340 cont+=len;
4341
4342 // is this a continuation line. If so, replace \ by space and look at next line
4343 if ( (lastslash=strrchr(line,'\\')) && !strtok(lastslash+1," \n\t")){
4344 *(fullline+(cont-len)+(lastslash-line))=' ';
4345 continue;
4346 }
4347
4348 // Not a continuation line. Parse it
d008864d 4349 scandevice = ParseConfigLine(conf_entries, default_conf, contlineno, fullline);
832b75ed
GG
4350
4351 // did we find a scandevice directive?
2127e193 4352 if (scandevice==-1)
832b75ed 4353 return 0;
832b75ed 4354 // did we find a syntax error
2127e193 4355 if (scandevice==-2)
832b75ed 4356 return -1;
832b75ed
GG
4357
4358 entry+=scandevice;
4359 lineno++;
4360 cont=0;
4361 }
2127e193 4362
832b75ed
GG
4363 // note -- may be zero if syntax of file OK, but no valid entries!
4364 return entry;
4365}
4366
832b75ed
GG
4367/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> <=======\n", where
4368 <LIST> is the list of valid arguments for option opt. */
cfbba5b9
GI
4369static void PrintValidArgs(char opt)
4370{
832b75ed
GG
4371 const char *s;
4372
4373 PrintOut(LOG_CRIT, "=======> VALID ARGUMENTS ARE: ");
4374 if (!(s = GetValidArgList(opt)))
4375 PrintOut(LOG_CRIT, "Error constructing argument list for option %c", opt);
4376 else
2127e193 4377 PrintOut(LOG_CRIT, "%s", (char *)s);
832b75ed
GG
4378 PrintOut(LOG_CRIT, " <=======\n");
4379}
4380
d008864d
GI
4381#ifndef _WIN32
4382// Report error and exit if specified path is not absolute.
4383static void check_abs_path(char option, const std::string & path)
2127e193 4384{
d008864d
GI
4385 if (path.empty() || path[0] == '/')
4386 return;
4387
4388 debugmode = 1;
4389 PrintHead();
4390 PrintOut(LOG_CRIT, "=======> INVALID ARGUMENT TO -%c: %s <=======\n\n", option, path.c_str());
4391 PrintOut(LOG_CRIT, "Error: relative path names are not allowed\n\n");
4392 EXIT(EXIT_BADCMD);
2127e193 4393}
d008864d 4394#endif // !_WIN32
2127e193 4395
832b75ed
GG
4396// Parses input line, prints usage message and
4397// version/license/copyright messages
cfbba5b9 4398static void ParseOpts(int argc, char **argv)
e9583e0c 4399{
ee38a438 4400 // Init default path names
e9583e0c 4401#ifndef _WIN32
d2e702cf
GI
4402 configfile = SMARTMONTOOLS_SYSCONFDIR "/smartd.conf";
4403 warning_script = SMARTMONTOOLS_SMARTDSCRIPTDIR "/smartd_warning.sh";
e9583e0c 4404#else
ee38a438
GI
4405 std::string exedir = get_exe_dir();
4406 static std::string configfile_str = exedir + "/smartd.conf";
e9583e0c 4407 configfile = configfile_str.c_str();
ee38a438 4408 warning_script = exedir + "/smartd_warning.cmd";
e9583e0c
GI
4409#endif
4410
832b75ed 4411 // Please update GetValidArgList() if you edit shortopts
ee38a438 4412 static const char shortopts[] = "c:l:q:dDni:p:r:s:A:B:w:Vh?"
a23d5117
GI
4413#ifdef HAVE_LIBCAP_NG
4414 "C"
4415#endif
4416 ;
832b75ed
GG
4417 // Please update GetValidArgList() if you edit longopts
4418 struct option longopts[] = {
4419 { "configfile", required_argument, 0, 'c' },
4420 { "logfacility", required_argument, 0, 'l' },
4421 { "quit", required_argument, 0, 'q' },
4422 { "debug", no_argument, 0, 'd' },
4423 { "showdirectives", no_argument, 0, 'D' },
4424 { "interval", required_argument, 0, 'i' },
a37e7145
GG
4425#ifndef _WIN32
4426 { "no-fork", no_argument, 0, 'n' },
d008864d
GI
4427#else
4428 { "service", no_argument, 0, 'n' },
a37e7145 4429#endif
832b75ed
GG
4430 { "pidfile", required_argument, 0, 'p' },
4431 { "report", required_argument, 0, 'r' },
2127e193
GI
4432 { "savestates", required_argument, 0, 's' },
4433 { "attributelog", required_argument, 0, 'A' },
4434 { "drivedb", required_argument, 0, 'B' },
ee38a438 4435 { "warnexec", required_argument, 0, 'w' },
832b75ed
GG
4436 { "version", no_argument, 0, 'V' },
4437 { "license", no_argument, 0, 'V' },
4438 { "copyright", no_argument, 0, 'V' },
4439 { "help", no_argument, 0, 'h' },
4440 { "usage", no_argument, 0, 'h' },
a23d5117
GI
4441#ifdef HAVE_LIBCAP_NG
4442 { "capabilities", no_argument, 0, 'C' },
4443#endif
832b75ed
GG
4444 { 0, 0, 0, 0 }
4445 };
2127e193 4446
832b75ed 4447 opterr=optopt=0;
2127e193
GI
4448 bool badarg = false;
4449 bool no_defaultdb = false; // set true on '-B FILE'
4450
e9583e0c
GI
4451 // Parse input options.
4452 int optchar;
4453 while ((optchar = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
4454 char *arg;
4455 char *tailptr;
4456 long lchecktime;
4457
832b75ed
GG
4458 switch(optchar) {
4459 case 'q':
4460 // when to quit
4461 if (!(strcmp(optarg,"nodev"))) {
4462 quit=0;
4463 } else if (!(strcmp(optarg,"nodevstartup"))) {
4464 quit=1;
4465 } else if (!(strcmp(optarg,"never"))) {
4466 quit=2;
4467 } else if (!(strcmp(optarg,"onecheck"))) {
4468 quit=3;
4469 debugmode=1;
4470 } else if (!(strcmp(optarg,"showtests"))) {
4471 quit=4;
4472 debugmode=1;
4473 } else if (!(strcmp(optarg,"errors"))) {
4474 quit=5;
4475 } else {
2127e193 4476 badarg = true;
832b75ed
GG
4477 }
4478 break;
4479 case 'l':
4480 // set the log facility level
4481 if (!strcmp(optarg, "daemon"))
4482 facility=LOG_DAEMON;
4483 else if (!strcmp(optarg, "local0"))
4484 facility=LOG_LOCAL0;
4485 else if (!strcmp(optarg, "local1"))
4486 facility=LOG_LOCAL1;
4487 else if (!strcmp(optarg, "local2"))
4488 facility=LOG_LOCAL2;
4489 else if (!strcmp(optarg, "local3"))
4490 facility=LOG_LOCAL3;
4491 else if (!strcmp(optarg, "local4"))
4492 facility=LOG_LOCAL4;
4493 else if (!strcmp(optarg, "local5"))
4494 facility=LOG_LOCAL5;
4495 else if (!strcmp(optarg, "local6"))
4496 facility=LOG_LOCAL6;
4497 else if (!strcmp(optarg, "local7"))
4498 facility=LOG_LOCAL7;
4499 else
2127e193 4500 badarg = true;
832b75ed
GG
4501 break;
4502 case 'd':
4503 // enable debug mode
2127e193 4504 debugmode = 1;
832b75ed 4505 break;
a37e7145
GG
4506 case 'n':
4507 // don't fork()
4508#ifndef _WIN32 // On Windows, --service is already handled by daemon_main()
4509 do_fork = false;
4510#endif
4511 break;
832b75ed
GG
4512 case 'D':
4513 // print summary of all valid directives
2127e193 4514 debugmode = 1;
832b75ed
GG
4515 Directives();
4516 EXIT(0);
4517 break;
4518 case 'i':
4519 // Period (time interval) for checking
4520 // strtol will set errno in the event of overflow, so we'll check it.
4521 errno = 0;
4522 lchecktime = strtol(optarg, &tailptr, 10);
4523 if (*tailptr != '\0' || lchecktime < 10 || lchecktime > INT_MAX || errno) {
4524 debugmode=1;
4525 PrintHead();
4526 PrintOut(LOG_CRIT, "======> INVALID INTERVAL: %s <=======\n", optarg);
4527 PrintOut(LOG_CRIT, "======> INTERVAL MUST BE INTEGER BETWEEN %d AND %d <=======\n", 10, INT_MAX);
4528 PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
4529 EXIT(EXIT_BADCMD);
4530 }
4531 checktime = (int)lchecktime;
4532 break;
4533 case 'r':
4534 // report IOCTL transactions
4535 {
4536 int i;
4537 char *s;
4538
4539 // split_report_arg() may modify its first argument string, so use a
4540 // copy of optarg in case we want optarg for an error message.
4541 if (!(s = strdup(optarg))) {
4542 PrintOut(LOG_CRIT, "No memory to process -r option - exiting\n");
4543 EXIT(EXIT_NOMEM);
4544 }
4545 if (split_report_arg(s, &i)) {
2127e193 4546 badarg = true;
832b75ed
GG
4547 } else if (i<1 || i>3) {
4548 debugmode=1;
4549 PrintHead();
4550 PrintOut(LOG_CRIT, "======> INVALID REPORT LEVEL: %s <=======\n", optarg);
4551 PrintOut(LOG_CRIT, "======> LEVEL MUST BE INTEGER BETWEEN 1 AND 3<=======\n");
4552 EXIT(EXIT_BADCMD);
4553 } else if (!strcmp(s,"ioctl")) {
cfbba5b9 4554 ata_debugmode = scsi_debugmode = i;
832b75ed 4555 } else if (!strcmp(s,"ataioctl")) {
cfbba5b9 4556 ata_debugmode = i;
832b75ed 4557 } else if (!strcmp(s,"scsiioctl")) {
cfbba5b9 4558 scsi_debugmode = i;
832b75ed 4559 } else {
2127e193 4560 badarg = true;
832b75ed 4561 }
2127e193 4562 free(s); // TODO: use std::string
832b75ed
GG
4563 }
4564 break;
4565 case 'c':
4566 // alternate configuration file
4567 if (strcmp(optarg,"-"))
2127e193 4568 configfile = (configfile_alt = optarg).c_str();
832b75ed
GG
4569 else // read from stdin
4570 configfile=configfile_stdin;
4571 break;
4572 case 'p':
4573 // output file with PID number
2127e193
GI
4574 pid_file = optarg;
4575 break;
4576 case 's':
4577 // path prefix of persistent state file
4578 state_path_prefix = optarg;
4579 break;
4580 case 'A':
4581 // path prefix of attribute log file
4582 attrlog_path_prefix = optarg;
4583 break;
4584 case 'B':
4585 {
4586 const char * path = optarg;
4587 if (*path == '+' && path[1])
4588 path++;
4589 else
4590 no_defaultdb = true;
4591 unsigned char savedebug = debugmode; debugmode = 1;
4592 if (!read_drive_database(path))
4593 EXIT(EXIT_BADCMD);
4594 debugmode = savedebug;
4595 }
832b75ed 4596 break;
ee38a438
GI
4597 case 'w':
4598 warning_script = optarg;
4599 break;
832b75ed
GG
4600 case 'V':
4601 // print version and CVS info
2127e193
GI
4602 debugmode = 1;
4603 PrintOut(LOG_INFO, "%s", format_version_info("smartd", true /*full*/).c_str());
832b75ed
GG
4604 EXIT(0);
4605 break;
a23d5117
GI
4606#ifdef HAVE_LIBCAP_NG
4607 case 'C':
4608 // enable capabilities
4609 enable_capabilities = true;
4610 break;
4611#endif
832b75ed
GG
4612 case 'h':
4613 // help: print summary of command-line options
4614 debugmode=1;
4615 PrintHead();
4616 Usage();
4617 EXIT(0);
4618 break;
4619 case '?':
4620 default:
4621 // unrecognized option
4622 debugmode=1;
4623 PrintHead();
832b75ed
GG
4624 // Point arg to the argument in which this option was found.
4625 arg = argv[optind-1];
4626 // Check whether the option is a long option that doesn't map to -h.
4627 if (arg[1] == '-' && optchar != 'h') {
4628 // Iff optopt holds a valid option then argument must be missing.
4629 if (optopt && (strchr(shortopts, optopt) != NULL)) {
4630 PrintOut(LOG_CRIT, "=======> ARGUMENT REQUIRED FOR OPTION: %s <=======\n",arg+2);
4631 PrintValidArgs(optopt);
4632 } else {
4633 PrintOut(LOG_CRIT, "=======> UNRECOGNIZED OPTION: %s <=======\n\n",arg+2);
4634 }
4635 PrintOut(LOG_CRIT, "\nUse smartd --help to get a usage summary\n\n");
4636 EXIT(EXIT_BADCMD);
4637 }
832b75ed
GG
4638 if (optopt) {
4639 // Iff optopt holds a valid option then argument must be missing.
4640 if (strchr(shortopts, optopt) != NULL){
4641 PrintOut(LOG_CRIT, "=======> ARGUMENT REQUIRED FOR OPTION: %c <=======\n",optopt);
4642 PrintValidArgs(optopt);
4643 } else {
4644 PrintOut(LOG_CRIT, "=======> UNRECOGNIZED OPTION: %c <=======\n\n",optopt);
4645 }
4646 PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
4647 EXIT(EXIT_BADCMD);
4648 }
4649 Usage();
4650 EXIT(0);
4651 }
4652
4653 // Check to see if option had an unrecognized or incorrect argument.
4654 if (badarg) {
4655 debugmode=1;
4656 PrintHead();
4657 // It would be nice to print the actual option name given by the user
4658 // here, but we just print the short form. Please fix this if you know
4659 // a clean way to do it.
4660 PrintOut(LOG_CRIT, "=======> INVALID ARGUMENT TO -%c: %s <======= \n", optchar, optarg);
4661 PrintValidArgs(optchar);
4662 PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
4663 EXIT(EXIT_BADCMD);
4664 }
4665 }
4666
4667 // non-option arguments are not allowed
4668 if (argc > optind) {
4669 debugmode=1;
4670 PrintHead();
4671 PrintOut(LOG_CRIT, "=======> UNRECOGNIZED ARGUMENT: %s <=======\n\n", argv[optind]);
4672 PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
4673 EXIT(EXIT_BADCMD);
4674 }
4675
4676 // no pidfile in debug mode
2127e193 4677 if (debugmode && !pid_file.empty()) {
832b75ed
GG
4678 debugmode=1;
4679 PrintHead();
4680 PrintOut(LOG_CRIT, "=======> INVALID CHOICE OF OPTIONS: -d and -p <======= \n\n");
2127e193 4681 PrintOut(LOG_CRIT, "Error: pid file %s not written in debug (-d) mode\n\n", pid_file.c_str());
832b75ed
GG
4682 EXIT(EXIT_BADCMD);
4683 }
2127e193 4684
d008864d
GI
4685#ifndef _WIN32
4686 if (!debugmode) {
4687 // absolute path names are required due to chdir('/') after fork().
4688 check_abs_path('p', pid_file);
4689 check_abs_path('s', state_path_prefix);
4690 check_abs_path('A', attrlog_path_prefix);
2127e193 4691 }
d008864d 4692#endif
2127e193
GI
4693
4694 // Read or init drive database
4695 if (!no_defaultdb) {
4696 unsigned char savedebug = debugmode; debugmode = 1;
4697 if (!read_default_drive_databases())
4698 EXIT(EXIT_BADCMD);
4699 debugmode = savedebug;
4700 }
4701
832b75ed
GG
4702 // print header
4703 PrintHead();
832b75ed
GG
4704}
4705
4706// Function we call if no configuration file was found or if the
4707// SCANDIRECTIVE Directive was found. It makes entries for device
2127e193
GI
4708// names returned by scan_smart_devices() in os_OSNAME.cpp
4709static int MakeConfigEntries(const dev_config & base_cfg,
4710 dev_config_vector & conf_entries, smart_device_list & scanned_devs, const char * type)
4711{
832b75ed 4712 // make list of devices
2127e193
GI
4713 smart_device_list devlist;
4714 if (!smi()->scan_smart_devices(devlist, (*type ? type : 0)))
832b75ed
GG
4715 PrintOut(LOG_CRIT,"Problem creating device name scan list\n");
4716
4717 // if no devices, or error constructing list, return
2127e193 4718 if (devlist.size() <= 0)
832b75ed 4719 return 0;
2127e193 4720
7f0798ef
GI
4721 // add empty device slots for existing config entries
4722 while (scanned_devs.size() < conf_entries.size())
4723 scanned_devs.push_back((smart_device *)0);
4724
832b75ed 4725 // loop over entries to create
2127e193
GI
4726 for (unsigned i = 0; i < devlist.size(); i++) {
4727 // Move device pointer
4728 smart_device * dev = devlist.release(i);
4729 scanned_devs.push_back(dev);
832b75ed 4730
2127e193
GI
4731 // Copy configuration, update device and type name
4732 conf_entries.push_back(base_cfg);
4733 dev_config & cfg = conf_entries.back();
4734 cfg.name = dev->get_info().info_name;
cfbba5b9 4735 cfg.dev_name = dev->get_info().dev_name;
2127e193 4736 cfg.dev_type = type;
832b75ed
GG
4737 }
4738
2127e193 4739 return devlist.size();
832b75ed
GG
4740}
4741
2127e193
GI
4742static void CanNotRegister(const char *name, const char *type, int line, bool scandirective)
4743{
4744 if (!debugmode && scandirective)
4745 return;
832b75ed
GG
4746 if (line)
4747 PrintOut(scandirective?LOG_INFO:LOG_CRIT,
4748 "Unable to register %s device %s at line %d of file %s\n",
4749 type, name, line, configfile);
4750 else
4751 PrintOut(LOG_INFO,"Unable to register %s device %s\n",
4752 type, name);
4753 return;
4754}
4755
4756// Returns negative value (see ParseConfigFile()) if config file
4757// had errors, else number of entries which may be zero or positive.
2127e193
GI
4758static int ReadOrMakeConfigEntries(dev_config_vector & conf_entries, smart_device_list & scanned_devs)
4759{
832b75ed 4760 // parse configuration file configfile (normally /etc/smartd.conf)
2127e193
GI
4761 int entries = ParseConfigFile(conf_entries);
4762
4763 if (entries < 0) {
832b75ed 4764 // There was an error reading the configuration file.
2127e193 4765 conf_entries.clear();
832b75ed
GG
4766 if (entries == -1)
4767 PrintOut(LOG_CRIT, "Configuration file %s has fatal syntax errors.\n", configfile);
4768 return entries;
4769 }
4770
832b75ed
GG
4771 // no error parsing config file.
4772 if (entries) {
4773 // we did not find a SCANDIRECTIVE and did find valid entries
4774 PrintOut(LOG_INFO, "Configuration file %s parsed.\n", configfile);
4775 }
7f0798ef 4776 else if (!conf_entries.empty()) {
832b75ed 4777 // we found a SCANDIRECTIVE or there was no configuration file so
7f0798ef 4778 // scan. Configuration file's last entry contains all options
832b75ed 4779 // that were set
7f0798ef
GI
4780 dev_config first = conf_entries.back();
4781 conf_entries.pop_back();
2127e193
GI
4782
4783 if (first.lineno)
832b75ed
GG
4784 PrintOut(LOG_INFO,"Configuration file %s was parsed, found %s, scanning devices\n", configfile, SCANDIRECTIVE);
4785 else
4786 PrintOut(LOG_INFO,"No configuration file %s found, scanning devices\n", configfile);
4787
2127e193
GI
4788 // make config list of devices to search for
4789 MakeConfigEntries(first, conf_entries, scanned_devs, first.dev_type.c_str());
832b75ed
GG
4790
4791 // warn user if scan table found no devices
2127e193 4792 if (conf_entries.empty())
832b75ed 4793 PrintOut(LOG_CRIT,"In the system's table of devices NO devices found to scan\n");
832b75ed
GG
4794 }
4795 else
293b5ab8 4796 PrintOut(LOG_CRIT, "Configuration file %s parsed but has no entries\n", configfile);
832b75ed 4797
2127e193 4798 return conf_entries.size();
832b75ed
GG
4799}
4800
ee38a438
GI
4801// Return true if TYPE contains a RAID drive number
4802static bool is_raid_type(const char * type)
4803{
4804 if (str_starts_with(type, "sat,"))
4805 return false;
4806 int i;
4807 if (sscanf(type, "%*[^,],%d", &i) != 1)
4808 return false;
4809 return true;
4810}
4811
4812// Return true if DEV is already in DEVICES[0..NUMDEVS) or IGNORED[*]
4813static bool is_duplicate_device(const smart_device * dev,
4814 const smart_device_list & devices, unsigned numdevs,
4815 const dev_config_vector & ignored)
4816{
4817 const smart_device::device_info & info1 = dev->get_info();
4818 bool is_raid1 = is_raid_type(info1.dev_type.c_str());
4819
4820 for (unsigned i = 0; i < numdevs; i++) {
4821 const smart_device::device_info & info2 = devices.at(i)->get_info();
4822 // -d TYPE options must match if RAID drive number is specified
4823 if ( info1.dev_name == info2.dev_name
4824 && ( info1.dev_type == info2.dev_type
4825 || !is_raid1 || !is_raid_type(info2.dev_type.c_str())))
4826 return true;
4827 }
4828
4829 for (unsigned i = 0; i < ignored.size(); i++) {
4830 const dev_config & cfg2 = ignored.at(i);
4831 if ( info1.dev_name == cfg2.dev_name
4832 && ( info1.dev_type == cfg2.dev_type
4833 || !is_raid1 || !is_raid_type(cfg2.dev_type.c_str())))
4834 return true;
4835 }
4836 return false;
4837}
832b75ed 4838
2127e193 4839// This function tries devices from conf_entries. Each one that can be
832b75ed 4840// registered is moved onto the [ata|scsi]devices lists and removed
2127e193
GI
4841// from the conf_entries list.
4842static void RegisterDevices(const dev_config_vector & conf_entries, smart_device_list & scanned_devs,
4843 dev_config_vector & configs, dev_state_vector & states, smart_device_list & devices)
4844{
832b75ed 4845 // start by clearing lists/memory of ALL existing devices
2127e193
GI
4846 configs.clear();
4847 devices.clear();
4848 states.clear();
4849
832b75ed 4850 // Register entries
ee38a438
GI
4851 dev_config_vector ignored_entries;
4852 unsigned numnoscan = 0;
2127e193
GI
4853 for (unsigned i = 0; i < conf_entries.size(); i++){
4854
4855 dev_config cfg = conf_entries[i];
4856
ee38a438
GI
4857 if (cfg.ignore) {
4858 // Store for is_duplicate_device() check and ignore
4859 PrintOut(LOG_INFO, "Device: %s%s%s%s, ignored\n", cfg.name.c_str(),
4860 (!cfg.dev_type.empty() ? " [" : ""),
4861 cfg.dev_type.c_str(),
4862 (!cfg.dev_type.empty() ? "]" : ""));
4863 ignored_entries.push_back(cfg);
4864 continue;
4865 }
4866
2127e193 4867 // get device of appropriate type
bed94269 4868 smart_device_auto_ptr dev;
2127e193
GI
4869 bool scanning = false;
4870
4871 // Device may already be detected during devicescan
4872 if (i < scanned_devs.size()) {
4873 dev = scanned_devs.release(i);
ee38a438
GI
4874 if (dev) {
4875 // Check for a preceding non-DEVICESCAN entry for the same device
4876 if ( (numnoscan || !ignored_entries.empty())
4877 && is_duplicate_device(dev.get(), devices, numnoscan, ignored_entries)) {
4878 PrintOut(LOG_INFO, "Device: %s, duplicate, ignored\n", dev->get_info_name());
4879 continue;
4880 }
2127e193 4881 scanning = true;
ee38a438 4882 }
2127e193
GI
4883 }
4884
4885 if (!dev) {
4886 dev = smi()->get_smart_device(cfg.name.c_str(), cfg.dev_type.c_str());
4887 if (!dev) {
4888 if (cfg.dev_type.empty())
4889 PrintOut(LOG_INFO,"Device: %s, unable to autodetect device type\n", cfg.name.c_str());
4890 else
4891 PrintOut(LOG_INFO,"Device: %s, unsupported device type '%s'\n", cfg.name.c_str(), cfg.dev_type.c_str());
4892 continue;
4893 }
4894 }
4895
4896 // Save old info
4897 smart_device::device_info oldinfo = dev->get_info();
4898
4899 // Open with autodetect support, may return 'better' device
bed94269 4900 dev.replace( dev->autodetect_open() );
2127e193
GI
4901
4902 // Report if type has changed
bed94269 4903 if (oldinfo.dev_type != dev->get_dev_type())
2127e193
GI
4904 PrintOut(LOG_INFO,"Device: %s, type changed from '%s' to '%s'\n",
4905 cfg.name.c_str(), oldinfo.dev_type.c_str(), dev->get_dev_type());
4906
4907 if (!dev->is_open()) {
4908 // For linux+devfs, a nonexistent device gives a strange error
4909 // message. This makes the error message a bit more sensible.
4910 // If no debug and scanning - don't print errors
4911 if (debugmode || !scanning)
4912 PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", dev->get_info_name(), dev->get_errmsg());
832b75ed 4913 continue;
2127e193
GI
4914 }
4915
4916 // Update informal name
4917 cfg.name = dev->get_info().info_name;
4918 PrintOut(LOG_INFO, "Device: %s, opened\n", cfg.name.c_str());
4919
4920 // Prepare initial state
4921 dev_state state;
4922
832b75ed 4923 // register ATA devices
2127e193
GI
4924 if (dev->is_ata()){
4925 if (ATADeviceScan(cfg, state, dev->to_ata())) {
4926 CanNotRegister(cfg.name.c_str(), "ATA", cfg.lineno, scanning);
bed94269 4927 dev.reset();
832b75ed
GG
4928 }
4929 }
2127e193
GI
4930 // or register SCSI devices
4931 else if (dev->is_scsi()){
4932 if (SCSIDeviceScan(cfg, state, dev->to_scsi())) {
4933 CanNotRegister(cfg.name.c_str(), "SCSI", cfg.lineno, scanning);
bed94269 4934 dev.reset();
832b75ed
GG
4935 }
4936 }
bed94269
GI
4937 else {
4938 PrintOut(LOG_INFO, "Device: %s, neither ATA nor SCSI device\n", cfg.name.c_str());
4939 dev.reset();
4940 }
4941
4942 if (dev) {
4943 // move onto the list of devices
4944 configs.push_back(cfg);
4945 states.push_back(state);
4946 devices.push_back(dev);
ee38a438
GI
4947 if (!scanning)
4948 numnoscan = devices.size();
bed94269 4949 }
832b75ed
GG
4950 // if device is explictly listed and we can't register it, then
4951 // exit unless the user has specified that the device is removable
bed94269 4952 else if (!scanning) {
2127e193
GI
4953 if (cfg.removable || quit==2)
4954 PrintOut(LOG_INFO, "Device %s not available\n", cfg.name.c_str());
832b75ed 4955 else {
2127e193 4956 PrintOut(LOG_CRIT, "Unable to register device %s (no Directive -d removable). Exiting.\n", cfg.name.c_str());
832b75ed
GG
4957 EXIT(EXIT_BADDEV);
4958 }
4959 }
832b75ed 4960 }
d008864d
GI
4961
4962 init_disable_standby_check(configs);
832b75ed
GG
4963}
4964
4965
2127e193 4966// Main program without exception handling
cfbba5b9 4967static int main_worker(int argc, char **argv)
832b75ed 4968{
2127e193
GI
4969 // Initialize interface
4970 smart_interface::init();
4971 if (!smi())
4972 return 1;
4973
832b75ed 4974 // is it our first pass through?
2127e193 4975 bool firstpass = true;
832b75ed
GG
4976
4977 // next time to wake up
cfbba5b9 4978 time_t wakeuptime = 0;
832b75ed
GG
4979
4980 // parse input and print header and usage info if needed
4981 ParseOpts(argc,argv);
4982
2127e193
GI
4983 // Configuration for each device
4984 dev_config_vector configs;
4985 // Device states
4986 dev_state_vector states;
4987 // Devices to monitor
4988 smart_device_list devices;
4989
4990 bool write_states_always = true;
4991
a23d5117
GI
4992#ifdef HAVE_LIBCAP_NG
4993 // Drop capabilities
4994 if (enable_capabilities) {
4995 capng_clear(CAPNG_SELECT_BOTH);
4996 capng_updatev(CAPNG_ADD, (capng_type_t)(CAPNG_EFFECTIVE|CAPNG_PERMITTED),
4997 CAP_SYS_ADMIN, CAP_MKNOD, CAP_SYS_RAWIO, -1);
4998 capng_apply(CAPNG_SELECT_BOTH);
4999 }
5000#endif
5001
832b75ed 5002 // the main loop of the code
2127e193 5003 for (;;) {
832b75ed
GG
5004
5005 // are we exiting from a signal?
5006 if (caughtsigEXIT) {
5007 // are we exiting with SIGTERM?
5008 int isterm=(caughtsigEXIT==SIGTERM);
5009 int isquit=(caughtsigEXIT==SIGQUIT);
5010 int isok=debugmode?isterm || isquit:isterm;
5011
5012 PrintOut(isok?LOG_INFO:LOG_CRIT, "smartd received signal %d: %s\n",
5013 caughtsigEXIT, strsignal(caughtsigEXIT));
2127e193
GI
5014
5015 if (!isok)
5016 return EXIT_SIGNAL;
5017
5018 // Write state files
5019 if (!state_path_prefix.empty())
5020 write_all_dev_states(configs, states);
5021
5022 return 0;
832b75ed
GG
5023 }
5024
5025 // Should we (re)read the config file?
5026 if (firstpass || caughtsigHUP){
832b75ed 5027 if (!firstpass) {
2127e193
GI
5028 // Write state files
5029 if (!state_path_prefix.empty())
5030 write_all_dev_states(configs, states);
5031
832b75ed
GG
5032 PrintOut(LOG_INFO,
5033 caughtsigHUP==1?
5034 "Signal HUP - rereading configuration file %s\n":
d2e702cf 5035 "\a\nSignal INT - rereading configuration file %s (" SIGQUIT_KEYNAME " quits)\n\n",
832b75ed
GG
5036 configfile);
5037 }
5038
2127e193
GI
5039 {
5040 dev_config_vector conf_entries; // Entries read from smartd.conf
5041 smart_device_list scanned_devs; // Devices found during scan
5042 // (re)reads config file, makes >=0 entries
5043 int entries = ReadOrMakeConfigEntries(conf_entries, scanned_devs);
5044
5045 if (entries>=0) {
5046 // checks devices, then moves onto ata/scsi list or deallocates.
5047 RegisterDevices(conf_entries, scanned_devs, configs, states, devices);
5048 if (!(configs.size() == devices.size() && configs.size() == states.size()))
5049 throw std::logic_error("Invalid result from RegisterDevices");
5050 }
5051 else if (quit==2 || ((quit==0 || quit==1) && !firstpass)) {
5052 // user has asked to continue on error in configuration file
5053 if (!firstpass)
5054 PrintOut(LOG_INFO,"Reusing previous configuration\n");
5055 }
5056 else {
5057 // exit with configuration file error status
a23d5117 5058 return (entries==-3 ? EXIT_READCONF : entries==-2 ? EXIT_NOCONF : EXIT_BADCONF);
2127e193 5059 }
832b75ed
GG
5060 }
5061
5062 // Log number of devices we are monitoring...
2127e193
GI
5063 if (devices.size() > 0 || quit==2 || (quit==1 && !firstpass)) {
5064 int numata = 0;
5065 for (unsigned i = 0; i < devices.size(); i++) {
5066 if (devices.at(i)->is_ata())
5067 numata++;
5068 }
832b75ed 5069 PrintOut(LOG_INFO,"Monitoring %d ATA and %d SCSI devices\n",
2127e193
GI
5070 numata, devices.size() - numata);
5071 }
832b75ed
GG
5072 else {
5073 PrintOut(LOG_INFO,"Unable to monitor any SMART enabled devices. Try debug (-d) option. Exiting...\n");
a23d5117 5074 return EXIT_NODEV;
832b75ed
GG
5075 }
5076
5077 if (quit==4) {
5078 // user has asked to print test schedule
2127e193 5079 PrintTestSchedule(configs, states, devices);
a23d5117 5080 return 0;
832b75ed 5081 }
a23d5117
GI
5082
5083#ifdef HAVE_LIBCAP_NG
5084 if (enable_capabilities) {
5085 for (unsigned i = 0; i < configs.size(); i++) {
5086 if (!configs[i].emailaddress.empty() || !configs[i].emailcmdline.empty()) {
5087 PrintOut(LOG_WARNING, "Mail can't be enabled together with --capabilities. All mail will be suppressed.\n");
5088 break;
5089 }
5090 }
5091 }
5092#endif
5093
832b75ed
GG
5094 // reset signal
5095 caughtsigHUP=0;
2127e193
GI
5096
5097 // Always write state files after (re)configuration
5098 write_states_always = true;
832b75ed
GG
5099 }
5100
a37e7145
GG
5101 // check all devices once,
5102 // self tests are not started in first pass unless '-q onecheck' is specified
a7e8ffec 5103 CheckDevicesOnce(configs, states, devices, firstpass, (!firstpass || quit==3));
2127e193
GI
5104
5105 // Write state files
5106 if (!state_path_prefix.empty())
5107 write_all_dev_states(configs, states, write_states_always);
5108 write_states_always = false;
5109
5110 // Write attribute logs
5111 if (!attrlog_path_prefix.empty())
5112 write_all_dev_attrlogs(configs, states);
5113
832b75ed
GG
5114 // user has asked us to exit after first check
5115 if (quit==3) {
5116 PrintOut(LOG_INFO,"Started with '-q onecheck' option. All devices sucessfully checked once.\n"
5117 "smartd is exiting (exit status 0)\n");
a23d5117 5118 return 0;
832b75ed
GG
5119 }
5120
5121 // fork into background if needed
5122 if (firstpass && !debugmode) {
832b75ed
GG
5123 DaemonInit();
5124 }
5125
5126 // set exit and signal handlers, write PID file, set wake-up time
5127 if (firstpass){
5128 Initialize(&wakeuptime);
2127e193 5129 firstpass = false;
832b75ed
GG
5130 }
5131
5132 // sleep until next check time, or a signal arrives
2127e193 5133 wakeuptime = dosleep(wakeuptime, write_states_always);
832b75ed
GG
5134 }
5135}
5136
5137
2127e193
GI
5138#ifndef _WIN32
5139// Main program
5140int main(int argc, char **argv)
5141#else
5142// Windows: internal main function started direct or by service control manager
5143static int smartd_main(int argc, char **argv)
5144#endif
5145{
5146 int status;
5147 try {
5148 // Do the real work ...
5149 status = main_worker(argc, argv);
5150 }
5151 catch (int ex) {
5152 // EXIT(status) arrives here
5153 status = ex;
5154 }
5155 catch (const std::bad_alloc & /*ex*/) {
5156 // Memory allocation failed (also thrown by std::operator new)
5157 PrintOut(LOG_CRIT, "Smartd: Out of memory\n");
5158 status = EXIT_NOMEM;
5159 }
5160 catch (const std::exception & ex) {
5161 // Other fatal errors
5162 PrintOut(LOG_CRIT, "Smartd: Exception: %s\n", ex.what());
5163 status = EXIT_BADCODE;
5164 }
5165
5166 if (is_initialized)
5167 status = Goodbye(status);
5168
5169#ifdef _WIN32
5170 daemon_winsvc_exitcode = status;
5171#endif
5172 return status;
5173}
5174
5175
832b75ed
GG
5176#ifdef _WIN32
5177// Main function for Windows
5178int main(int argc, char **argv){
5179 // Options for smartd windows service
5180 static const daemon_winsvc_options svc_opts = {
5181 "--service", // cmd_opt
5182 "smartd", "SmartD Service", // servicename, displayname
5183 // description
5184 "Controls and monitors storage devices using the Self-Monitoring, "
d2e702cf
GI
5185 "Analysis and Reporting Technology System (SMART) built into "
5186 "ATA/SATA and SCSI/SAS hard drives and solid-state drives. "
5187 "www.smartmontools.org"
832b75ed
GG
5188 };
5189 // daemon_main() handles daemon and service specific commands
5190 // and starts smartd_main() direct, from a new process,
5191 // or via service control manager
5192 return daemon_main("smartd", &svc_opts , smartd_main, argc, argv);
5193}
5194#endif