smartmontools SVN Rev 5707
Utility to control and monitor storage systems with "S.M.A.R.T."
smartd.cpp
Go to the documentation of this file.
1/*
2 * Home page of code is: https://www.smartmontools.org
3 *
4 * Copyright (C) 2002-11 Bruce Allen
5 * Copyright (C) 2008-25 Christian Franke
6 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
7 * Copyright (C) 2008 Oliver Bock <brevilo@users.sourceforge.net>
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12#include "config.h"
13#define __STDC_FORMAT_MACROS 1 // enable PRI* for C++
14
15// unconditionally included files
16#include <inttypes.h>
17#include <stdio.h>
18#include <sys/types.h>
19#include <sys/stat.h> // umask
20#include <signal.h>
21#include <fcntl.h>
22#include <string.h>
23#include <syslog.h>
24#include <stdarg.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <time.h>
28#include <limits.h>
29#include <getopt.h>
30
31#include <algorithm> // std::replace()
32#include <map>
33#include <stdexcept>
34#include <string>
35#include <vector>
36
37// conditionally included files
38#ifndef _WIN32
39#include <sys/wait.h>
40#endif
41#ifdef HAVE_UNISTD_H
42#include <unistd.h>
43#endif
44
45#ifdef _WIN32
46#include "os_win32/popen.h" // popen_as_rstr_user(), pclose()
47#ifdef _MSC_VER
48#pragma warning(disable:4761) // "conversion supplied"
49typedef unsigned short mode_t;
50typedef int pid_t;
51#endif
52#include <io.h> // umask()
53#include <process.h> // getpid()
54#endif // _WIN32
55
56#ifdef __CYGWIN__
57#include <io.h> // setmode()
58#endif // __CYGWIN__
59
60#ifdef HAVE_LIBCAP_NG
61#include <cap-ng.h>
62#endif // LIBCAP_NG
63
64#ifdef HAVE_LIBSYSTEMD
65#include <systemd/sd-daemon.h>
66#endif // HAVE_LIBSYSTEMD
67
68// locally included files
69#include "atacmds.h"
70#include "dev_interface.h"
71#include "knowndrives.h"
72#include "scsicmds.h"
73#include "nvmecmds.h"
74#include "utility.h"
75#include "sg_unaligned.h"
76
77#ifdef HAVE_POSIX_API
78#include "popen_as_ugid.h"
79#endif
80
81#ifdef _WIN32
82// fork()/signal()/initd simulation for native Windows
83#include "os_win32/daemon_win32.h" // daemon_main/detach/signal()
84#define strsignal daemon_strsignal
85#define sleep daemon_sleep
86// SIGQUIT does not exist, CONTROL-Break signals SIGBREAK.
87#define SIGQUIT SIGBREAK
88#define SIGQUIT_KEYNAME "CONTROL-Break"
89#else // _WIN32
90#define SIGQUIT_KEYNAME "CONTROL-\\"
91#endif // _WIN32
92
93const char * smartd_cpp_cvsid = "$Id: smartd.cpp 5696 2025-04-22 14:23:18Z chrfranke $"
94 CONFIG_H_CVSID;
95
96extern "C" {
97 typedef void (*signal_handler_type)(int);
98}
99
101{
102#if defined(_WIN32)
103 // signal() emulation
104 daemon_signal(sig, handler);
105
106#else
107 // SVr4, POSIX.1-2001, ..., POSIX.1-2024
108 struct sigaction sa;
109 sa.sa_handler = SIG_DFL;
110 sigaction(sig, (struct sigaction *)0, &sa);
111 if (sa.sa_handler == SIG_IGN)
112 return;
113
114 sa = {};
115 sa.sa_handler = handler;
116 sa.sa_flags = SA_RESTART; // BSD signal() semantics
117 sigaction(sig, &sa, (struct sigaction *)0);
118#endif
119}
120
121using namespace smartmontools;
122
123static const int scsiLogRespLen = 252;
124
125// smartd exit codes
126#define EXIT_BADCMD 1 // command line did not parse
127#define EXIT_BADCONF 2 // syntax error in config file
128#define EXIT_STARTUP 3 // problem forking daemon
129#define EXIT_PID 4 // problem creating pid file
130#define EXIT_NOCONF 5 // config file does not exist
131#define EXIT_READCONF 6 // config file exists but cannot be read
132
133#define EXIT_NOMEM 8 // out of memory
134#define EXIT_BADCODE 10 // internal error - should NEVER happen
135
136#define EXIT_BADDEV 16 // we can't monitor this device
137#define EXIT_NODEV 17 // no devices to monitor
138
139#define EXIT_SIGNAL 254 // abort on signal
140
141
142// command-line: 1=debug mode, 2=print presets
143static unsigned char debugmode = 0;
144
145// command-line: how long to sleep between checks
146static constexpr int default_checktime = 1800;
148static int checktime_min = 0; // Minimum individual check time, 0 if none
149
150// command-line: name of PID file (empty for no pid file)
151static std::string pid_file;
152
153// command-line: path prefix of persistent state file, empty if no persistence.
154static std::string state_path_prefix
155#ifdef SMARTMONTOOLS_SAVESTATES
156 = SMARTMONTOOLS_SAVESTATES
157#endif
158 ;
159
160// command-line: path prefix of attribute log file, empty if no logs.
161static std::string attrlog_path_prefix
162#ifdef SMARTMONTOOLS_ATTRIBUTELOG
163 = SMARTMONTOOLS_ATTRIBUTELOG
164#endif
165 ;
166
167// configuration file name
168static const char * configfile;
169// configuration file "name" if read from stdin
170static const char * const configfile_stdin = "<stdin>";
171// path of alternate configuration file
172static std::string configfile_alt;
173
174// warning script file
175static std::string warning_script;
176
177#ifdef HAVE_POSIX_API
178// run warning script as non-privileged user
179static bool warn_as_user;
180static uid_t warn_uid;
181static gid_t warn_gid;
182static std::string warn_uname, warn_gname;
183#elif defined(_WIN32)
184// run warning script as restricted user
185static bool warn_as_restr_user;
186#endif
187
188// command-line: when should we exit?
189enum quit_t {
194static bool quit_nodev0 = false;
195
196// command-line; this is the default syslog(3) log facility to use.
197static int facility=LOG_DAEMON;
198
199#ifndef _WIN32
200// command-line: fork into background?
201static bool do_fork=true;
202#endif
203
204// TODO: This smartctl only variable is also used in some os_*.cpp
205unsigned char failuretest_permissive = 0;
206
207// set to one if we catch a USR1 (check devices now)
208static volatile int caughtsigUSR1=0;
209
210#ifdef _WIN32
211// set to one if we catch a USR2 (toggle debug mode)
212static volatile int caughtsigUSR2=0;
213#endif
214
215// set to one if we catch a HUP (reload config file). In debug mode,
216// set to two, if we catch INT (also reload config file).
217static volatile int caughtsigHUP=0;
218
219// set to signal value if we catch INT, QUIT, or TERM
220static volatile int caughtsigEXIT=0;
221
222// This function prints either to stdout or to the syslog as needed.
223static void PrintOut(int priority, const char *fmt, ...)
225
226#ifdef HAVE_LIBSYSTEMD
227// systemd notify support
228
229static bool notify_enabled = false;
230static bool notify_ready = false;
231
232static inline void notify_init()
233{
234 if (!getenv("NOTIFY_SOCKET"))
235 return;
236 notify_enabled = true;
237}
238
239static inline bool notify_post_init()
240{
241 if (!notify_enabled)
242 return true;
243 if (do_fork) {
244 PrintOut(LOG_CRIT, "Option -n (--no-fork) is required if 'Type=notify' is set.\n");
245 return false;
246 }
247 return true;
248}
249
250static inline void notify_extend_timeout()
251{
252 if (!notify_enabled)
253 return;
254 if (notify_ready)
255 return;
256 const char * notify = "EXTEND_TIMEOUT_USEC=20000000"; // typical drive spinup time is 20s tops
257 if (debugmode) {
258 pout("sd_notify(0, \"%s\")\n", notify);
259 return;
260 }
261 sd_notify(0, notify);
262}
263
264static void notify_msg(const char * msg, bool ready = false)
265{
266 if (!notify_enabled)
267 return;
268 if (debugmode) {
269 pout("sd_notify(0, \"%sSTATUS=%s\")\n", (ready ? "READY=1\\n" : ""), msg);
270 return;
271 }
272 sd_notifyf(0, "%sSTATUS=%s", (ready ? "READY=1\n" : ""), msg);
273}
274
275static void notify_check(int numdev)
276{
277 if (!notify_enabled)
278 return;
279 char msg[32];
280 snprintf(msg, sizeof(msg), "Checking %d device%s ...",
281 numdev, (numdev != 1 ? "s" : ""));
282 notify_msg(msg);
283}
284
285static void notify_wait(time_t wakeuptime, int numdev)
286{
287 if (!notify_enabled)
288 return;
289 char ts[16] = ""; struct tm tmbuf;
290 strftime(ts, sizeof(ts), "%H:%M:%S", time_to_tm_local(&tmbuf, wakeuptime));
291 char msg[64];
292 snprintf(msg, sizeof(msg), "Next check of %d device%s will start at %s",
293 numdev, (numdev != 1 ? "s" : ""), ts);
294 notify_msg(msg, !notify_ready); // first call notifies READY=1
295 notify_ready = true;
296}
297
298static void notify_exit(int status)
299{
300 if (!notify_enabled)
301 return;
302 const char * msg;
303 switch (status) {
304 case 0: msg = "Exiting ..."; break;
305 case EXIT_BADCMD: msg = "Error in command line (see SYSLOG)"; break;
306 case EXIT_BADCONF: case EXIT_NOCONF:
307 case EXIT_READCONF: msg = "Error in config file (see SYSLOG)"; break;
308 case EXIT_BADDEV: msg = "Unable to register a device (see SYSLOG)"; break;
309 case EXIT_NODEV: msg = "No devices to monitor"; break;
310 default: msg = "Error (see SYSLOG)"; break;
311 }
312 // Ensure that READY=1 is notified before 'exit(0)' because otherwise
313 // systemd will report a service (protocol) failure
314 notify_msg(msg, (!status && !notify_ready));
315}
316
317#else // HAVE_LIBSYSTEMD
318// No systemd notify support
319
320static inline bool notify_post_init()
321{
322#ifdef __linux__
323 if (getenv("NOTIFY_SOCKET")) {
324 PrintOut(LOG_CRIT, "This version of smartd was build without 'Type=notify' support.\n");
325 return false;
326 }
327#endif
328 return true;
329}
330
331static inline void notify_init() { }
332static inline void notify_extend_timeout() { }
333static inline void notify_msg(const char *) { }
334static inline void notify_check(int) { }
335static inline void notify_wait(time_t, int) { }
336static inline void notify_exit(int) { }
337
338#endif // HAVE_LIBSYSTEMD
339
340// Email frequencies
341enum class emailfreqs : unsigned char {
343};
344
345// Attribute monitoring flags.
346// See monitor_attr_flags below.
347enum {
354};
355
356// Array of flags for each attribute.
358{
359public:
360 bool is_set(int id, unsigned char flag) const
361 { return (0 < id && id < (int)sizeof(m_flags) && (m_flags[id] & flag)); }
362
363 void set(int id, unsigned char flags)
364 {
365 if (0 < id && id < (int)sizeof(m_flags))
366 m_flags[id] |= flags;
367 }
368
369private:
370 unsigned char m_flags[256]{};
371};
372
373
374/// Configuration data for a device. Read from smartd.conf.
375/// Supports copy & assignment and is compatible with STL containers.
377{
378 int lineno{}; // Line number of entry in file
379 std::string name; // Device name (with optional extra info)
380 std::string dev_name; // Device name (plain, for SMARTD_DEVICE variable)
381 std::string dev_type; // Device type argument from -d directive, empty if none
382 std::string dev_idinfo; // Device identify info for warning emails and duplicate check
383 std::string dev_idinfo_bc; // Same without namespace id for duplicate check
384 std::string state_file; // Path of the persistent state file, empty if none
385 std::string attrlog_file; // Path of the persistent attrlog file, empty if none
386 int checktime{}; // Individual check interval, 0 if none
387 bool ignore{}; // Ignore this entry
388 bool id_is_unique{}; // True if dev_idinfo is unique (includes S/N or WWN)
389 bool smartcheck{}; // Check SMART status
390 uint8_t smartcheck_nvme{}; // Check these bits from NVMe Critical Warning byte
391 bool usagefailed{}; // Check for failed Usage Attributes
392 bool prefail{}; // Track changes in Prefail Attributes
393 bool usage{}; // Track changes in Usage Attributes
394 bool selftest{}; // Monitor number of selftest errors
395 bool errorlog{}; // Monitor number of ATA errors
396 bool xerrorlog{}; // Monitor number of ATA errors (Extended Comprehensive error log)
397 bool offlinests{}; // Monitor changes in offline data collection status
398 bool offlinests_ns{}; // Disable auto standby if in progress
399 bool selfteststs{}; // Monitor changes in self-test execution status
400 bool selfteststs_ns{}; // Disable auto standby if in progress
401 bool permissive{}; // Ignore failed SMART commands
402 char autosave{}; // 1=disable, 2=enable Autosave Attributes
403 char autoofflinetest{}; // 1=disable, 2=enable Auto Offline Test
404 firmwarebug_defs firmwarebugs; // -F directives from drivedb or smartd.conf
405 bool ignorepresets{}; // Ignore database of -v options
406 bool showpresets{}; // Show database entry for this device
407 bool removable{}; // Device may disappear (not be present)
408 char powermode{}; // skip check, if disk in idle or standby mode
409 bool powerquiet{}; // skip powermode 'skipping checks' message
410 int powerskipmax{}; // how many times can be check skipped
411 unsigned char tempdiff{}; // Track Temperature changes >= this limit
412 unsigned char tempinfo{}, tempcrit{}; // Track Temperatures >= these limits as LOG_INFO, LOG_CRIT+mail
413 regular_expression test_regex; // Regex for scheduled testing
414 unsigned test_offset_factor{}; // Factor for staggering of scheduled tests
415
416 // Configuration of email warning messages
417 std::string emailcmdline; // script to execute, empty if no messages
418 std::string emailaddress; // email address, or empty
419 emailfreqs emailfreq{}; // Send emails once, daily, diminishing
420 bool emailtest{}; // Send test email?
421
422 // ATA ONLY
423 int dev_rpm{}; // rotation rate, 0 = unknown, 1 = SSD, >1 = HDD
424 int set_aam{}; // disable(-1), enable(1..255->0..254) Automatic Acoustic Management
425 int set_apm{}; // disable(-1), enable(2..255->1..254) Advanced Power Management
426 int set_lookahead{}; // disable(-1), enable(1) read look-ahead
427 int set_standby{}; // set(1..255->0..254) standby timer
428 bool set_security_freeze{}; // Freeze ATA security
429 int set_wcache{}; // disable(-1), enable(1) write cache
430 int set_dsn{}; // disable(0x2), enable(0x1) DSN
431
432 bool sct_erc_set{}; // set SCT ERC to:
433 unsigned short sct_erc_readtime{}; // ERC read time (deciseconds)
434 unsigned short sct_erc_writetime{}; // ERC write time (deciseconds)
435
436 unsigned char curr_pending_id{}; // ID of current pending sector count, 0 if none
437 unsigned char offl_pending_id{}; // ID of offline uncorrectable sector count, 0 if none
438 bool curr_pending_incr{}, offl_pending_incr{}; // True if current/offline pending values increase
439 bool curr_pending_set{}, offl_pending_set{}; // True if '-C', '-U' set in smartd.conf
440
441 attribute_flags monitor_attr_flags; // MONITOR_* flags for each attribute
442
444
445 // NVMe only
446 unsigned nvme_err_log_max_entries{}; // size of error log
447};
448
449// Number of allowed mail message types
450static const int SMARTD_NMAIL = 13;
451// Type for '-M test' mails (state not persistent)
452static const int MAILTYPE_TEST = 0;
453// TODO: Add const or enum for all mail types.
454
455struct mailinfo {
456 int logged{}; // number of times an email has been sent
457 time_t firstsent{}; // time first email was sent, as defined by time(2)
458 time_t lastsent{}; // time last email was sent, as defined by time(2)
459};
460
461/// Persistent state data for a device.
463{
464 unsigned char tempmin{}, tempmax{}; // Min/Max Temperatures
465
466 unsigned char selflogcount{}; // total number of self-test errors
467 uint64_t selfloghour{}; // lifetime hours of last self-test error
468 // (NVMe self-test log uses a 64 bit value)
469
470 time_t scheduled_test_next_check{}; // Time of next check for scheduled self-tests
471
472 uint64_t selective_test_last_start{}; // Start LBA of last scheduled selective self-test
473 uint64_t selective_test_last_end{}; // End LBA of last scheduled selective self-test
474
475 mailinfo maillog[SMARTD_NMAIL]; // log info on when mail sent
476
477 // ATA ONLY
478 int ataerrorcount{}; // Total number of ATA errors
479
480 // Persistent part of ata_smart_values:
482 unsigned char id{};
483 unsigned char val{};
484 unsigned char worst{}; // Byte needed for 'raw64' attribute only.
485 uint64_t raw{};
486 unsigned char resvd{};
487 };
489
490 // SCSI ONLY
491
494 unsigned char found{};
495 };
497
500 unsigned char found{};
501 };
503
504 // NVMe only
506
507 // NVMe SMART/Health information: only the fields avail_spare,
508 // percent_used and media_errors are persistent.
510};
511
512/// Non-persistent state data for a device.
514{
515 bool must_write{}; // true if persistent part should be written
516
517 bool skip{}; // skip during next check cycle
518 time_t wakeuptime{}; // next wakeup time, 0 if unknown or global
519
520 bool not_cap_offline{}; // true == not capable of offline testing
525
526 unsigned char temperature{}; // last recorded Temperature (in Celsius)
527 time_t tempmin_delay{}; // time where Min Temperature tracking will start
528
529 bool removed{}; // true if open() failed for removable device
530
531 bool powermodefail{}; // true if power mode check failed
532 int powerskipcnt{}; // Number of checks skipped due to idle or standby mode
533 int lastpowermodeskipped{}; // the last power mode that was skipped
534
535 int attrlog_valid{}; // nonzero if data is valid for protocol specific
536 // attribute log: 1=ATA, 2=SCSI, 3=NVMe
537
538 // SCSI ONLY
539 // TODO: change to bool
540 unsigned char SmartPageSupported{}; // has log sense IE page (0x2f)
541 unsigned char TempPageSupported{}; // has log sense temperature page (0xd)
546 unsigned char SuppressReport{}; // minimize nuisance reports
547 unsigned char modese_len{}; // mode sense/select cmd len: 0 (don't
548 // know yet) 6 or 10
549 // ATA ONLY
550 uint64_t num_sectors{}; // Number of sectors
551 ata_smart_values smartval{}; // SMART data
553 bool offline_started{}; // true if offline data collection was started
554
555 // ATA and NVMe
556 bool selftest_started{}; // true if self-test was started
557
558 // NVMe only
559 uint8_t selftest_op{}; // last self-test operation
560 uint8_t selftest_compl{}; // last self-test completion
561};
562
563/// Runtime state data for a device.
565: public persistent_dev_state,
566 public temp_dev_state
567{
569 void update_temp_state();
570};
571
572/// Container for configuration info for each device.
573typedef std::vector<dev_config> dev_config_vector;
574
575/// Container for state info for each device.
576typedef std::vector<dev_state> dev_state_vector;
577
578// Copy ATA attributes to persistent state.
580{
581 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
584 pa.id = ta.id;
585 if (ta.id == 0) {
586 pa.val = pa.worst = 0; pa.raw = 0;
587 continue;
588 }
589 pa.val = ta.current;
590 pa.worst = ta.worst;
591 pa.raw = ta.raw[0]
592 | ( ta.raw[1] << 8)
593 | ( ta.raw[2] << 16)
594 | ((uint64_t)ta.raw[3] << 24)
595 | ((uint64_t)ta.raw[4] << 32)
596 | ((uint64_t)ta.raw[5] << 40);
597 pa.resvd = ta.reserv;
598 }
599}
600
601// Copy ATA from persistent to temp state.
603{
604 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
605 const ata_attribute & pa = ata_attributes[i];
607 ta.id = pa.id;
608 if (pa.id == 0) {
609 ta.current = ta.worst = 0;
610 memset(ta.raw, 0, sizeof(ta.raw));
611 continue;
612 }
613 ta.current = pa.val;
614 ta.worst = pa.worst;
615 ta.raw[0] = (unsigned char) pa.raw;
616 ta.raw[1] = (unsigned char)(pa.raw >> 8);
617 ta.raw[2] = (unsigned char)(pa.raw >> 16);
618 ta.raw[3] = (unsigned char)(pa.raw >> 24);
619 ta.raw[4] = (unsigned char)(pa.raw >> 32);
620 ta.raw[5] = (unsigned char)(pa.raw >> 40);
621 ta.reserv = pa.resvd;
622 }
623}
624
625// Convert 128 bit LE integer to uint64_t or its max value on overflow.
626static uint64_t le128_to_uint64(const unsigned char (& val)[16])
627{
628 if (sg_get_unaligned_le64(val + 8))
629 return ~(uint64_t)0;
630 return sg_get_unaligned_le64(val);
631}
632
633// Convert uint64_t to 128 bit LE integer
634static void uint64_to_le128(unsigned char (& destval)[16], uint64_t srcval)
635{
636 sg_put_unaligned_le64(0, destval + 8);
637 sg_put_unaligned_le64(srcval, destval);
638}
639
640// Parse a line from a state file.
641static bool parse_dev_state_line(const char * line, persistent_dev_state & state)
642{
643 static const regular_expression regex(
644 "^ *"
645 "((temperature-min)" // (1 (2)
646 "|(temperature-max)" // (3)
647 "|(self-test-errors)" // (4)
648 "|(self-test-last-err-hour)" // (5)
649 "|(scheduled-test-next-check)" // (6)
650 "|(selective-test-last-start)" // (7)
651 "|(selective-test-last-end)" // (8)
652 "|(ata-error-count)" // (9)
653 "|(mail\\.([0-9]+)\\." // (10 (11)
654 "((count)" // (12 (13)
655 "|(first-sent-time)" // (14)
656 "|(last-sent-time)" // (15)
657 ")" // 12)
658 ")" // 10)
659 "|(ata-smart-attribute\\.([0-9]+)\\." // (16 (17)
660 "((id)" // (18 (19)
661 "|(val)" // (20)
662 "|(worst)" // (21)
663 "|(raw)" // (22)
664 "|(resvd)" // (23)
665 ")" // 18)
666 ")" // 16)
667 "|(nvme-err-log-entries)" // (24)
668 "|(nvme-available-spare)" // (25)
669 "|(nvme-percentage-used)" // (26)
670 "|(nvme-media-errors)" // (27)
671 ")" // 1)
672 " *= *([0-9]+)[ \n]*$" // (28)
673 );
674
675 constexpr int nmatch = 1+28;
677 if (!regex.execute(line, nmatch, match))
678 return false;
679 if (match[nmatch-1].rm_so < 0)
680 return false;
681
682 uint64_t val = strtoull(line + match[nmatch-1].rm_so, (char **)0, 10);
683
684 int m = 1;
685 if (match[++m].rm_so >= 0)
686 state.tempmin = (unsigned char)val;
687 else if (match[++m].rm_so >= 0)
688 state.tempmax = (unsigned char)val;
689 else if (match[++m].rm_so >= 0)
690 state.selflogcount = (unsigned char)val;
691 else if (match[++m].rm_so >= 0)
692 state.selfloghour = val;
693 else if (match[++m].rm_so >= 0)
694 state.scheduled_test_next_check = (time_t)val;
695 else if (match[++m].rm_so >= 0)
696 state.selective_test_last_start = val;
697 else if (match[++m].rm_so >= 0)
698 state.selective_test_last_end = val;
699 else if (match[++m].rm_so >= 0)
700 state.ataerrorcount = (int)val;
701 else if (match[m+=2].rm_so >= 0) {
702 int i = atoi(line+match[m].rm_so);
703 if (!(0 <= i && i < SMARTD_NMAIL))
704 return false;
705 if (i == MAILTYPE_TEST) // Don't suppress test mails
706 return true;
707 if (match[m+=2].rm_so >= 0)
708 state.maillog[i].logged = (int)val;
709 else if (match[++m].rm_so >= 0)
710 state.maillog[i].firstsent = (time_t)val;
711 else if (match[++m].rm_so >= 0)
712 state.maillog[i].lastsent = (time_t)val;
713 else
714 return false;
715 }
716 else if (match[m+=5+1].rm_so >= 0) {
717 int i = atoi(line+match[m].rm_so);
718 if (!(0 <= i && i < NUMBER_ATA_SMART_ATTRIBUTES))
719 return false;
720 if (match[m+=2].rm_so >= 0)
721 state.ata_attributes[i].id = (unsigned char)val;
722 else if (match[++m].rm_so >= 0)
723 state.ata_attributes[i].val = (unsigned char)val;
724 else if (match[++m].rm_so >= 0)
725 state.ata_attributes[i].worst = (unsigned char)val;
726 else if (match[++m].rm_so >= 0)
727 state.ata_attributes[i].raw = val;
728 else if (match[++m].rm_so >= 0)
729 state.ata_attributes[i].resvd = (unsigned char)val;
730 else
731 return false;
732 }
733 else if (match[m+=7].rm_so >= 0)
734 state.nvme_err_log_entries = val;
735 else if (match[++m].rm_so >= 0)
736 state.nvme_smartval.avail_spare = val;
737 else if (match[++m].rm_so >= 0)
738 state.nvme_smartval.percent_used = val;
739 else if (match[++m].rm_so >= 0)
741 else
742 return false;
743 return true;
744}
745
746// Read a state file.
747static bool read_dev_state(const char * path, persistent_dev_state & state)
748{
749 stdio_file f(path, "r");
750 if (!f) {
751 if (errno != ENOENT)
752 pout("Cannot read state file \"%s\"\n", path);
753 return false;
754 }
755#ifdef __CYGWIN__
756 setmode(fileno(f), O_TEXT); // Allow files with \r\n
757#endif
758
759 persistent_dev_state new_state;
760 int good = 0, bad = 0;
761 char line[256];
762 while (fgets(line, sizeof(line), f)) {
763 const char * s = line + strspn(line, " \t");
764 if (!*s || *s == '#')
765 continue;
766 if (!parse_dev_state_line(line, new_state))
767 bad++;
768 else
769 good++;
770 }
771
772 if (bad) {
773 if (!good) {
774 pout("%s: format error\n", path);
775 return false;
776 }
777 pout("%s: %d invalid line(s) ignored\n", path, bad);
778 }
779
780 // This sets the values missing in the file to 0.
781 state = new_state;
782 return true;
783}
784
785static void write_dev_state_line(FILE * f, const char * name, uint64_t val)
786{
787 if (val)
788 fprintf(f, "%s = %" PRIu64 "\n", name, val);
789}
790
791static void write_dev_state_line(FILE * f, const char * name1, int id, const char * name2, uint64_t val)
792{
793 if (val)
794 fprintf(f, "%s.%d.%s = %" PRIu64 "\n", name1, id, name2, val);
795}
796
797// Write a state file
798static bool write_dev_state(const char * path, const persistent_dev_state & state)
799{
800 // Rename old "file" to "file~"
801 std::string pathbak = path; pathbak += '~';
802 unlink(pathbak.c_str());
803 rename(path, pathbak.c_str());
804
805 stdio_file f(path, "w");
806 if (!f) {
807 pout("Cannot create state file \"%s\"\n", path);
808 return false;
809 }
810
811 fprintf(f, "# smartd state file\n");
812 write_dev_state_line(f, "temperature-min", state.tempmin);
813 write_dev_state_line(f, "temperature-max", state.tempmax);
814 write_dev_state_line(f, "self-test-errors", state.selflogcount);
815 write_dev_state_line(f, "self-test-last-err-hour", state.selfloghour);
816 write_dev_state_line(f, "scheduled-test-next-check", state.scheduled_test_next_check);
817 write_dev_state_line(f, "selective-test-last-start", state.selective_test_last_start);
818 write_dev_state_line(f, "selective-test-last-end", state.selective_test_last_end);
819
820 for (int i = 0; i < SMARTD_NMAIL; i++) {
821 if (i == MAILTYPE_TEST) // Don't suppress test mails
822 continue;
823 const mailinfo & mi = state.maillog[i];
824 if (!mi.logged)
825 continue;
826 write_dev_state_line(f, "mail", i, "count", mi.logged);
827 write_dev_state_line(f, "mail", i, "first-sent-time", mi.firstsent);
828 write_dev_state_line(f, "mail", i, "last-sent-time", mi.lastsent);
829 }
830
831 // ATA ONLY
832 write_dev_state_line(f, "ata-error-count", state.ataerrorcount);
833
834 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
835 const auto & pa = state.ata_attributes[i];
836 if (!pa.id)
837 continue;
838 write_dev_state_line(f, "ata-smart-attribute", i, "id", pa.id);
839 write_dev_state_line(f, "ata-smart-attribute", i, "val", pa.val);
840 write_dev_state_line(f, "ata-smart-attribute", i, "worst", pa.worst);
841 write_dev_state_line(f, "ata-smart-attribute", i, "raw", pa.raw);
842 write_dev_state_line(f, "ata-smart-attribute", i, "resvd", pa.resvd);
843 }
844
845 // NVMe only
846 write_dev_state_line(f, "nvme-err-log-entries", state.nvme_err_log_entries);
847 write_dev_state_line(f, "nvme-available-spare", state.nvme_smartval.avail_spare);
848 write_dev_state_line(f, "nvme-percentage-used", state.nvme_smartval.percent_used);
849 write_dev_state_line(f, "nvme-media-errors", le128_to_uint64(state.nvme_smartval.media_errors));
850
851 return true;
852}
853
854static void write_ata_attrlog(FILE * f, const dev_state & state)
855{
856 for (const auto & pa : state.ata_attributes) {
857 if (!pa.id)
858 continue;
859 fprintf(f, "\t%d;%d;%" PRIu64 ";", pa.id, pa.val, pa.raw);
860 }
861}
862
863static void write_scsi_attrlog(FILE * f, const dev_state & state)
864{
865 const struct scsiErrorCounter * ecp;
866 const char * pageNames[3] = {"read", "write", "verify"};
867 for (int k = 0; k < 3; ++k) {
868 if ( !state.scsi_error_counters[k].found ) continue;
869 ecp = &state.scsi_error_counters[k].errCounter;
870 fprintf(f, "\t%s-corr-by-ecc-fast;%" PRIu64 ";"
871 "\t%s-corr-by-ecc-delayed;%" PRIu64 ";"
872 "\t%s-corr-by-retry;%" PRIu64 ";"
873 "\t%s-total-err-corrected;%" PRIu64 ";"
874 "\t%s-corr-algorithm-invocations;%" PRIu64 ";"
875 "\t%s-gb-processed;%.3f;"
876 "\t%s-total-unc-errors;%" PRIu64 ";",
877 pageNames[k], ecp->counter[0],
878 pageNames[k], ecp->counter[1],
879 pageNames[k], ecp->counter[2],
880 pageNames[k], ecp->counter[3],
881 pageNames[k], ecp->counter[4],
882 pageNames[k], (ecp->counter[5] / 1000000000.0),
883 pageNames[k], ecp->counter[6]);
884 }
885 if(state.scsi_nonmedium_error.found && state.scsi_nonmedium_error.nme.gotPC0) {
886 fprintf(f, "\tnon-medium-errors;%" PRIu64 ";", state.scsi_nonmedium_error.nme.counterPC0);
887 }
888 // write SCSI current temperature if it is monitored
889 if (state.temperature)
890 fprintf(f, "\ttemperature;%d;", state.temperature);
891}
892
893static void write_nvme_attrlog(FILE * f, const dev_state & state)
894{
895 const nvme_smart_log & s = state.nvme_smartval;
896 // Names similar to smartctl JSON output with '-' instead of '_'
897 fprintf(f,
898 "\tcritical-warning;%d;"
899 "\ttemperature;%d;"
900 "\tavailable-spare;%d;"
901 "\tavailable-spare-threshold;%d;"
902 "\tpercentage-used;%d;"
903 "\tdata-units-read;%" PRIu64 ";"
904 "\tdata-units-written;%" PRIu64 ";"
905 "\thost-reads;%" PRIu64 ";"
906 "\thost-writes;%" PRIu64 ";"
907 "\tcontroller-busy-time;%" PRIu64 ";"
908 "\tpower-cycles;%" PRIu64 ";"
909 "\tpower-on-hours;%" PRIu64 ";"
910 "\tunsafe-shutdowns;%" PRIu64 ";"
911 "\tmedia-errors;%" PRIu64 ";"
912 "\tnum-err-log-entries;%" PRIu64 ";",
913 s.critical_warning,
914 (int)sg_get_unaligned_le16(s.temperature) - 273,
915 s.avail_spare,
916 s.spare_thresh,
917 s.percent_used,
918 le128_to_uint64(s.data_units_read),
919 le128_to_uint64(s.data_units_written),
920 le128_to_uint64(s.host_reads),
921 le128_to_uint64(s.host_writes),
922 le128_to_uint64(s.ctrl_busy_time),
923 le128_to_uint64(s.power_cycles),
924 le128_to_uint64(s.power_on_hours),
925 le128_to_uint64(s.unsafe_shutdowns),
926 le128_to_uint64(s.media_errors),
927 le128_to_uint64(s.num_err_log_entries)
928 );
929}
930
931// Write to the attrlog file
932static bool write_dev_attrlog(const char * path, const dev_state & state)
933{
934 stdio_file f(path, "a");
935 if (!f) {
936 pout("Cannot create attribute log file \"%s\"\n", path);
937 return false;
938 }
939
940 time_t now = time(nullptr);
941 struct tm tmbuf, * tms = time_to_tm_local(&tmbuf, now);
942 fprintf(f, "%d-%02d-%02d %02d:%02d:%02d;",
943 1900+tms->tm_year, 1+tms->tm_mon, tms->tm_mday,
944 tms->tm_hour, tms->tm_min, tms->tm_sec);
945
946 switch (state.attrlog_valid) {
947 case 1: write_ata_attrlog(f, state); break;
948 case 2: write_scsi_attrlog(f, state); break;
949 case 3: write_nvme_attrlog(f, state); break;
950 }
951
952 fprintf(f, "\n");
953 return true;
954}
955
956// Write all state files. If write_always is false, don't write
957// unless must_write is set.
958static void write_all_dev_states(const dev_config_vector & configs,
959 dev_state_vector & states,
960 bool write_always = true)
961{
962 for (unsigned i = 0; i < states.size(); i++) {
963 const dev_config & cfg = configs.at(i);
964 if (cfg.state_file.empty())
965 continue;
966 dev_state & state = states[i];
967 if (!write_always && !state.must_write)
968 continue;
969 if (!write_dev_state(cfg.state_file.c_str(), state))
970 continue;
971 state.must_write = false;
972 if (write_always || debugmode)
973 PrintOut(LOG_INFO, "Device: %s, state written to %s\n",
974 cfg.name.c_str(), cfg.state_file.c_str());
975 }
976}
977
978// Write to all attrlog files
979static void write_all_dev_attrlogs(const dev_config_vector & configs,
980 dev_state_vector & states)
981{
982 for (unsigned i = 0; i < states.size(); i++) {
983 const dev_config & cfg = configs.at(i);
984 if (cfg.attrlog_file.empty())
985 continue;
986 dev_state & state = states[i];
987 if (!state.attrlog_valid)
988 continue;
989 write_dev_attrlog(cfg.attrlog_file.c_str(), state);
990 state.attrlog_valid = 0;
991 if (debugmode)
992 PrintOut(LOG_INFO, "Device: %s, attribute log written to %s\n",
993 cfg.name.c_str(), cfg.attrlog_file.c_str());
994 }
995}
996
997extern "C" { // signal handlers require C-linkage
998
999// Note if we catch a SIGUSR1
1000static void USR1handler(int sig)
1001{
1002 if (SIGUSR1==sig)
1003 caughtsigUSR1=1;
1004 return;
1005}
1006
1007#ifdef _WIN32
1008// Note if we catch a SIGUSR2
1009static void USR2handler(int sig)
1010{
1011 if (SIGUSR2==sig)
1012 caughtsigUSR2=1;
1013 return;
1014}
1015#endif
1016
1017// Note if we catch a HUP (or INT in debug mode)
1018static void HUPhandler(int sig)
1019{
1020 if (sig==SIGHUP)
1021 caughtsigHUP=1;
1022 else
1023 caughtsigHUP=2;
1024 return;
1025}
1026
1027// signal handler for TERM, QUIT, and INT (if not in debug mode)
1028static void sighandler(int sig)
1029{
1030 if (!caughtsigEXIT)
1031 caughtsigEXIT=sig;
1032 return;
1033}
1034
1035} // extern "C"
1036
1037#ifdef HAVE_LIBCAP_NG
1038// capabilities(7) support
1039
1040static int capabilities_mode /* = 0 */; // 1=enabled, 2=mail
1041
1042static void capabilities_drop_now()
1043{
1044 if (!capabilities_mode)
1045 return;
1046 capng_clear(CAPNG_SELECT_BOTH);
1047 capng_updatev(CAPNG_ADD, (capng_type_t)(CAPNG_EFFECTIVE|CAPNG_PERMITTED),
1048 CAP_SYS_ADMIN, CAP_MKNOD, CAP_SYS_RAWIO, -1);
1049 if (warn_as_user && (warn_uid || warn_gid)) {
1050 // For popen_as_ugid()
1051 capng_updatev(CAPNG_ADD, (capng_type_t)(CAPNG_EFFECTIVE|CAPNG_PERMITTED),
1052 CAP_SETGID, CAP_SETUID, -1);
1053 }
1054 if (capabilities_mode > 1) {
1055 // For exim MTA
1056 capng_updatev(CAPNG_ADD, CAPNG_BOUNDING_SET,
1057 CAP_SETGID, CAP_SETUID, CAP_CHOWN, CAP_FOWNER, CAP_DAC_OVERRIDE, -1);
1058 }
1059 capng_apply(CAPNG_SELECT_BOTH);
1060}
1061
1062static void capabilities_log_error_hint()
1063{
1064 if (!capabilities_mode)
1065 return;
1066 PrintOut(LOG_INFO, "If mail notification does not work with '--capabilities%s\n",
1067 (capabilities_mode == 1 ? "', try '--capabilities=mail'"
1068 : "=mail', please inform " PACKAGE_BUGREPORT));
1069}
1070
1071#else // HAVE_LIBCAP_NG
1072// No capabilities(7) support
1073
1074static inline void capabilities_drop_now() { }
1075static inline void capabilities_log_error_hint() { }
1076
1077#endif // HAVE_LIBCAP_NG
1078
1079// a replacement for setenv() which is not available on all platforms.
1080// Note that the string passed to putenv must not be freed or made
1081// invalid, since a pointer to it is kept by putenv(). This means that
1082// it must either be a static buffer or allocated off the heap. The
1083// string can be freed if the environment variable is redefined via
1084// another call to putenv(). There is no portable way to unset a variable
1085// with putenv(). So we manage the buffer in a static object.
1086// Using setenv() if available is not considered because some
1087// implementations may produce memory leaks.
1088
1090{
1091public:
1092 env_buffer() = default;
1093 env_buffer(const env_buffer &) = delete;
1094 void operator=(const env_buffer &) = delete;
1095
1096 void set(const char * name, const char * value);
1097private:
1098 char * m_buf = nullptr;
1099};
1100
1101void env_buffer::set(const char * name, const char * value)
1102{
1103 int size = strlen(name) + 1 + strlen(value) + 1;
1104 char * newbuf = new char[size];
1105 snprintf(newbuf, size, "%s=%s", name, value);
1106
1107 if (putenv(newbuf))
1108 throw std::runtime_error("putenv() failed");
1109
1110 // This assumes that the same NAME is passed on each call
1111 delete [] m_buf;
1112 m_buf = newbuf;
1113}
1114
1115#define EBUFLEN 1024
1116
1117static void MailWarning(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...)
1119
1120// If either address or executable path is non-null then send and log
1121// a warning email, or execute executable
1122static void MailWarning(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...)
1123{
1124 // See if user wants us to send mail
1125 if (cfg.emailaddress.empty() && cfg.emailcmdline.empty())
1126 return;
1127
1128 // Which type of mail are we sending?
1129 static const char * const whichfail[] = {
1130 "EmailTest", // 0
1131 "Health", // 1
1132 "Usage", // 2
1133 "SelfTest", // 3
1134 "ErrorCount", // 4
1135 "FailedHealthCheck", // 5
1136 "FailedReadSmartData", // 6
1137 "FailedReadSmartErrorLog", // 7
1138 "FailedReadSmartSelfTestLog", // 8
1139 "FailedOpenDevice", // 9
1140 "CurrentPendingSector", // 10
1141 "OfflineUncorrectableSector", // 11
1142 "Temperature" // 12
1143 };
1144 STATIC_ASSERT(sizeof(whichfail) == SMARTD_NMAIL * sizeof(whichfail[0]));
1145
1146 if (!(0 <= which && which < SMARTD_NMAIL)) {
1147 PrintOut(LOG_CRIT, "Internal error in MailWarning(): which=%d\n", which);
1148 return;
1149 }
1150 mailinfo * mail = state.maillog + which;
1151
1152 // Calc current and next interval for warning reminder emails
1153 int days, nextdays;
1154 if (which == 0)
1155 days = nextdays = -1; // EmailTest
1156 else switch (cfg.emailfreq) {
1157 case emailfreqs::once:
1158 days = nextdays = -1; break;
1159 case emailfreqs::always:
1160 days = nextdays = 0; break;
1161 case emailfreqs::daily:
1162 days = nextdays = 1; break;
1164 // 0, 1, 2, 3, 4, 5, 6, 7, ... => 1, 2, 4, 8, 16, 32, 32, 32, ...
1165 nextdays = 1 << ((unsigned)mail->logged <= 5 ? mail->logged : 5);
1166 // 0, 1, 2, 3, 4, 5, 6, 7, ... => 0, 1, 2, 4, 8, 16, 32, 32, ... (0 not used below)
1167 days = ((unsigned)mail->logged <= 5 ? nextdays >> 1 : nextdays);
1168 break;
1169 default:
1170 PrintOut(LOG_CRIT, "Internal error in MailWarning(): cfg.emailfreq=%d\n", (int)cfg.emailfreq);
1171 return;
1172 }
1173
1174 time_t now = time(nullptr);
1175 if (mail->logged) {
1176 // Return if no warning reminder email needs to be sent (now)
1177 if (days < 0)
1178 return; // '-M once' or EmailTest
1179 if (days > 0 && now < mail->lastsent + days * 24 * 3600)
1180 return; // '-M daily/diminishing' and too early
1181 }
1182 else {
1183 // Record the time of this first email message
1184 mail->firstsent = now;
1185 }
1186
1187 // Record the time of this email message
1188 mail->lastsent = now;
1189
1190 // print warning string into message
1191 // Note: Message length may reach ~300 characters as device names may be
1192 // very long on certain platforms (macOS ~230 characters).
1193 // Message length must not exceed email line length limit, see RFC 5322:
1194 // "... MUST be no more than 998 characters, ... excluding the CRLF."
1195 char message[512];
1196 va_list ap;
1197 va_start(ap, fmt);
1198 vsnprintf(message, sizeof(message), fmt, ap);
1199 va_end(ap);
1200
1201 // replace commas by spaces to separate recipients
1202 std::string address = cfg.emailaddress;
1203 std::replace(address.begin(), address.end(), ',', ' ');
1204
1205 // Export information in environment variables that will be useful
1206 // for user scripts
1207 const char * executable = cfg.emailcmdline.c_str();
1208 static env_buffer env[13];
1209 env[0].set("SMARTD_MAILER", executable);
1210 env[1].set("SMARTD_MESSAGE", message);
1211 char dates[DATEANDEPOCHLEN];
1212 snprintf(dates, sizeof(dates), "%d", mail->logged);
1213 env[2].set("SMARTD_PREVCNT", dates);
1214 dateandtimezoneepoch(dates, mail->firstsent);
1215 env[3].set("SMARTD_TFIRST", dates);
1216 snprintf(dates, DATEANDEPOCHLEN,"%d", (int)mail->firstsent);
1217 env[4].set("SMARTD_TFIRSTEPOCH", dates);
1218 env[5].set("SMARTD_FAILTYPE", whichfail[which]);
1219 env[6].set("SMARTD_ADDRESS", address.c_str());
1220 env[7].set("SMARTD_DEVICESTRING", cfg.name.c_str());
1221
1222 // Allow 'smartctl ... -d $SMARTD_DEVICETYPE $SMARTD_DEVICE'
1223 env[8].set("SMARTD_DEVICETYPE",
1224 (!cfg.dev_type.empty() ? cfg.dev_type.c_str() : "auto"));
1225 env[9].set("SMARTD_DEVICE", cfg.dev_name.c_str());
1226
1227 env[10].set("SMARTD_DEVICEINFO", cfg.dev_idinfo.c_str());
1228 dates[0] = 0;
1229 if (nextdays >= 0)
1230 snprintf(dates, sizeof(dates), "%d", nextdays);
1231 env[11].set("SMARTD_NEXTDAYS", dates);
1232 // Avoid false positive recursion detection by smartd_warning.{sh,cmd}
1233 env[12].set("SMARTD_SUBJECT", "");
1234
1235 // now construct a command to send this as EMAIL
1236 if (!*executable)
1237 executable = "<mail>";
1238 const char * newadd = (!address.empty()? address.c_str() : "<nomailer>");
1239 const char * newwarn = (which? "Warning via" : "Test of");
1240
1241 char command[256];
1242#ifdef _WIN32
1243 // Path may contain spaces
1244 snprintf(command, sizeof(command), "\"%s\" 2>&1", warning_script.c_str());
1245#else
1246 snprintf(command, sizeof(command), "%s 2>&1", warning_script.c_str());
1247#endif
1248
1249 // tell SYSLOG what we are about to do...
1250 PrintOut(LOG_INFO,"%s %s to %s%s ...\n",
1251 (which ? "Sending warning via" : "Executing test of"), executable, newadd,
1252 (
1253#ifdef HAVE_POSIX_API
1254 warn_as_user ?
1255 strprintf(" (uid=%u(%s) gid=%u(%s))",
1256 (unsigned)warn_uid, warn_uname.c_str(),
1257 (unsigned)warn_gid, warn_gname.c_str() ).c_str() :
1258#elif defined(_WIN32)
1259 warn_as_restr_user ? " (restricted user)" :
1260#endif
1261 ""
1262 )
1263 );
1264
1265 // issue the command to send mail or to run the user's executable
1266 errno=0;
1267 FILE * pfp;
1268
1269#ifdef HAVE_POSIX_API
1270 if (warn_as_user) {
1271 pfp = popen_as_ugid(command, "r", warn_uid, warn_gid);
1272 } else
1273#endif
1274 {
1275#ifdef _WIN32
1276 pfp = popen_as_restr_user(command, "r", warn_as_restr_user);
1277#else
1278 pfp = popen(command, "r");
1279#endif
1280 }
1281
1282 if (!pfp)
1283 // failed to popen() mail process
1284 PrintOut(LOG_CRIT,"%s %s to %s: failed (fork or pipe failed, or no memory) %s\n",
1285 newwarn, executable, newadd, errno?strerror(errno):"");
1286 else {
1287 // pipe succeeded!
1288 int len;
1289 char buffer[EBUFLEN];
1290
1291 // if unexpected output on stdout/stderr, null terminate, print, and flush
1292 if ((len=fread(buffer, 1, EBUFLEN, pfp))) {
1293 int count=0;
1294 int newlen = len<EBUFLEN ? len : EBUFLEN-1;
1295 buffer[newlen]='\0';
1296 PrintOut(LOG_CRIT,"%s %s to %s produced unexpected output (%s%d bytes) to STDOUT/STDERR: \n%s\n",
1297 newwarn, executable, newadd, len!=newlen?"here truncated to ":"", newlen, buffer);
1298
1299 // flush pipe if needed
1300 while (fread(buffer, 1, EBUFLEN, pfp) && count<EBUFLEN)
1301 count++;
1302
1303 // tell user that pipe was flushed, or that something is really wrong
1304 if (count && count<EBUFLEN)
1305 PrintOut(LOG_CRIT,"%s %s to %s: flushed remaining STDOUT/STDERR\n",
1306 newwarn, executable, newadd);
1307 else if (count)
1308 PrintOut(LOG_CRIT,"%s %s to %s: more than 1 MB STDOUT/STDERR flushed, breaking pipe\n",
1309 newwarn, executable, newadd);
1310 }
1311
1312 // if something went wrong with mail process, print warning
1313 errno=0;
1314 int status;
1315
1316#ifdef HAVE_POSIX_API
1317 if (warn_as_user) {
1318 status = pclose_as_ugid(pfp);
1319 } else
1320#endif
1321 {
1322 status = pclose(pfp);
1323 }
1324
1325 if (status == -1)
1326 PrintOut(LOG_CRIT,"%s %s to %s: pclose(3) failed %s\n", newwarn, executable, newadd,
1327 errno?strerror(errno):"");
1328 else {
1329 // mail process apparently succeeded. Check and report exit status
1330 if (WIFEXITED(status)) {
1331 // exited 'normally' (but perhaps with nonzero status)
1332 int status8 = WEXITSTATUS(status);
1333 if (status8>128)
1334 PrintOut(LOG_CRIT,"%s %s to %s: failed (32-bit/8-bit exit status: %d/%d) perhaps caught signal %d [%s]\n",
1335 newwarn, executable, newadd, status, status8, status8-128, strsignal(status8-128));
1336 else if (status8) {
1337 PrintOut(LOG_CRIT,"%s %s to %s: failed (32-bit/8-bit exit status: %d/%d)\n",
1338 newwarn, executable, newadd, status, status8);
1340 }
1341 else
1342 PrintOut(LOG_INFO,"%s %s to %s: successful\n", newwarn, executable, newadd);
1343 }
1344
1345 if (WIFSIGNALED(status))
1346 PrintOut(LOG_INFO,"%s %s to %s: exited because of uncaught signal %d [%s]\n",
1347 newwarn, executable, newadd, WTERMSIG(status), strsignal(WTERMSIG(status)));
1348
1349 // this branch is probably not possible. If subprocess is
1350 // stopped then pclose() should not return.
1351 if (WIFSTOPPED(status))
1352 PrintOut(LOG_CRIT,"%s %s to %s: process STOPPED because it caught signal %d [%s]\n",
1353 newwarn, executable, newadd, WSTOPSIG(status), strsignal(WSTOPSIG(status)));
1354
1355 }
1356 }
1357
1358 // increment mail sent counter
1359 mail->logged++;
1360}
1361
1362static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...)
1364
1365static void reset_warning_mail(const dev_config & cfg, dev_state & state, int which, const char *fmt, ...)
1366{
1367 if (!(0 <= which && which < SMARTD_NMAIL))
1368 return;
1369
1370 // Return if no mail sent yet
1371 mailinfo & mi = state.maillog[which];
1372 if (!mi.logged)
1373 return;
1374
1375 // Format & print message
1376 char msg[256];
1377 va_list ap;
1378 va_start(ap, fmt);
1379 vsnprintf(msg, sizeof(msg), fmt, ap);
1380 va_end(ap);
1381
1382 PrintOut(LOG_INFO, "Device: %s, %s, warning condition reset after %d email%s\n", cfg.name.c_str(),
1383 msg, mi.logged, (mi.logged==1 ? "" : "s"));
1384
1385 // Clear mail counter and timestamps
1386 mi = mailinfo();
1387 state.must_write = true;
1388}
1389
1390#ifndef _WIN32
1391
1392// Output multiple lines via separate syslog(3) calls.
1394static void vsyslog_lines(int priority, const char * fmt, va_list ap)
1395{
1396 char buf[512+EBUFLEN]; // enough space for exec cmd output in MailWarning()
1397 vsnprintf(buf, sizeof(buf), fmt, ap);
1398
1399 for (char * p = buf, * q; p && *p; p = q) {
1400 if ((q = strchr(p, '\n')))
1401 *q++ = 0;
1402 if (*p)
1403 syslog(priority, "%s\n", p);
1404 }
1405}
1406
1407#else // _WIN32
1408// os_win32/syslog_win32.cpp supports multiple lines.
1409#define vsyslog_lines vsyslog
1410#endif // _WIN32
1411
1412// Printing function for watching ataprint commands, or losing them
1413// [From GLIBC Manual: Since the prototype doesn't specify types for
1414// optional arguments, in a call to a variadic function the default
1415// argument promotions are performed on the optional argument
1416// values. This means the objects of type char or short int (whether
1417// signed or not) are promoted to either int or unsigned int, as
1418// appropriate.]
1419void pout(const char *fmt, ...){
1420 va_list ap;
1421
1422 // get the correct time in syslog()
1424 // initialize variable argument list
1425 va_start(ap,fmt);
1426 // in debugmode==1 mode we will print the output from the ataprint.o functions!
1427 if (debugmode && debugmode != 2) {
1428 FILE * f = stdout;
1429#ifdef _WIN32
1430 if (facility == LOG_LOCAL1) // logging to stdout
1431 f = stderr;
1432#endif
1433 vfprintf(f, fmt, ap);
1434 fflush(f);
1435 }
1436 // in debugmode==2 mode we print output from knowndrives.o functions
1437 else if (debugmode==2 || ata_debugmode || scsi_debugmode) {
1438 openlog("smartd", LOG_PID, facility);
1439 vsyslog_lines(LOG_INFO, fmt, ap);
1440 closelog();
1441 }
1442 va_end(ap);
1443 return;
1444}
1445
1446// This function prints either to stdout or to the syslog as needed.
1447static void PrintOut(int priority, const char *fmt, ...){
1448 va_list ap;
1449
1450 // get the correct time in syslog()
1452 // initialize variable argument list
1453 va_start(ap,fmt);
1454 if (debugmode) {
1455 FILE * f = stdout;
1456#ifdef _WIN32
1457 if (facility == LOG_LOCAL1) // logging to stdout
1458 f = stderr;
1459#endif
1460 vfprintf(f, fmt, ap);
1461 fflush(f);
1462 }
1463 else {
1464 openlog("smartd", LOG_PID, facility);
1465 vsyslog_lines(priority, fmt, ap);
1466 closelog();
1467 }
1468 va_end(ap);
1469 return;
1470}
1471
1472// Used to warn users about invalid checksums. Called from atacmds.cpp.
1473void checksumwarning(const char * string)
1474{
1475 pout("Warning! %s error: invalid SMART checksum.\n", string);
1476}
1477
1478#ifndef _WIN32
1479
1480// Wait for the pid file to show up, this makes sure a calling program knows
1481// that the daemon is really up and running and has a pid to kill it
1482static bool WaitForPidFile()
1483{
1484 int waited, max_wait = 10;
1485 struct stat stat_buf;
1486
1487 if (pid_file.empty() || debugmode)
1488 return true;
1489
1490 for(waited = 0; waited < max_wait; ++waited) {
1491 if (!stat(pid_file.c_str(), &stat_buf)) {
1492 return true;
1493 } else
1494 sleep(1);
1495 }
1496 return false;
1497}
1498
1499#endif // _WIN32
1500
1501// Forks new process if needed, closes ALL file descriptors,
1502// redirects stdin, stdout, and stderr. Not quite daemon().
1503// See https://www.linuxjournal.com/article/2335
1504// for a good description of why we do things this way.
1505static int daemon_init()
1506{
1507#ifndef _WIN32
1508
1509 // flush all buffered streams. Else we might get two copies of open
1510 // streams since both parent and child get copies of the buffers.
1511 fflush(nullptr);
1512
1513 if (do_fork) {
1514 pid_t pid;
1515 if ((pid=fork()) < 0) {
1516 // unable to fork!
1517 PrintOut(LOG_CRIT,"smartd unable to fork daemon process!\n");
1518 return EXIT_STARTUP;
1519 }
1520 if (pid) {
1521 // we are the parent process, wait for pid file, then exit cleanly
1522 if(!WaitForPidFile()) {
1523 PrintOut(LOG_CRIT,"PID file %s didn't show up!\n", pid_file.c_str());
1524 return EXIT_STARTUP;
1525 }
1526 return 0;
1527 }
1528
1529 // from here on, we are the child process.
1530 setsid();
1531
1532 // Fork one more time to avoid any possibility of having terminals
1533 if ((pid=fork()) < 0) {
1534 // unable to fork!
1535 PrintOut(LOG_CRIT,"smartd unable to fork daemon process!\n");
1536 return EXIT_STARTUP;
1537 }
1538 if (pid)
1539 // we are the parent process -- exit cleanly
1540 return 0;
1541
1542 // Now we are the child's child...
1543 }
1544
1545 // close any open file descriptors
1546 int open_max = sysconf(_SC_OPEN_MAX);
1547#ifdef HAVE_CLOSE_RANGE
1548 if (close_range(0, open_max - 1, 0))
1549#endif
1550 {
1551 // Limit number of unneeded close() calls under the assumption that
1552 // there are no large gaps between open FDs
1553 for (int i = 0, failed = 0; i < open_max && failed < 1024; i++)
1554 failed = (!close(i) ? 0 : failed + 1);
1555 }
1556
1557 // redirect any IO attempts to /dev/null and change to root directory
1558 int fd = open("/dev/null", O_RDWR);
1559 if (!(fd == 0 && dup(fd) == 1 && dup(fd) == 2 && !chdir("/"))) {
1560 PrintOut(LOG_CRIT, "smartd unable to redirect to /dev/null or to chdir to root!\n");
1561 return EXIT_STARTUP;
1562 }
1563 umask(0022);
1564
1565 if (do_fork)
1566 PrintOut(LOG_INFO, "smartd has fork()ed into background mode. New PID=%d.\n", (int)getpid());
1567
1568#else // _WIN32
1569
1570 // No fork() on native Win32
1571 // Detach this process from console
1572 fflush(nullptr);
1573 if (daemon_detach("smartd")) {
1574 PrintOut(LOG_CRIT,"smartd unable to detach from console!\n");
1575 return EXIT_STARTUP;
1576 }
1577 // stdin/out/err now closed if not redirected
1578
1579#endif // _WIN32
1580
1581 // No error, continue in main_worker()
1582 return -1;
1583}
1584
1585// create a PID file containing the current process id
1586static bool write_pid_file()
1587{
1588 if (!pid_file.empty()) {
1589 pid_t pid = getpid();
1590 mode_t old_umask;
1591#ifndef __CYGWIN__
1592 old_umask = umask(0077); // rwx------
1593#else
1594 // Cygwin: smartd service runs on system account, ensure PID file can be read by admins
1595 old_umask = umask(0033); // rwxr--r--
1596#endif
1597
1598 stdio_file f(pid_file.c_str(), "w");
1599 umask(old_umask);
1600 if (!(f && fprintf(f, "%d\n", (int)pid) > 0 && f.close())) {
1601 PrintOut(LOG_CRIT, "unable to write PID file %s - exiting.\n", pid_file.c_str());
1602 return false;
1603 }
1604 PrintOut(LOG_INFO, "file %s written containing PID %d\n", pid_file.c_str(), (int)pid);
1605 }
1606 return true;
1607}
1608
1609// Prints header identifying version of code and home
1610static void PrintHead()
1611{
1612 PrintOut(LOG_INFO, "%s\n", format_version_info("smartd").c_str());
1613}
1614
1615// prints help info for configuration file Directives
1616static void Directives()
1617{
1618 PrintOut(LOG_INFO,
1619 "Configuration file (%s) Directives (after device name):\n"
1620 " -d TYPE Set the device type: auto, ignore, removable,\n"
1621 " %s\n"
1622 " -T TYPE Set the tolerance to one of: normal, permissive\n"
1623 " -o VAL Enable/disable automatic offline tests (on/off)\n"
1624 " -S VAL Enable/disable attribute autosave (on/off)\n"
1625 " -n MODE No check if: never, sleep[,N][,q], standby[,N][,q], idle[,N][,q]\n"
1626 " -H Monitor SMART Health Status, report if failed\n"
1627 " -H MASK Monitor specific NVMe Critical Warning bits\n"
1628 " -s REG Do Self-Test at time(s) given by regular expression REG\n"
1629 " -l TYPE Monitor SMART log or self-test status:\n"
1630 " error, selftest, xerror, offlinests[,ns], selfteststs[,ns]\n"
1631 " -l scterc,R,W Set SCT Error Recovery Control\n"
1632 " -e Change device setting: aam,[N|off], apm,[N|off], dsn,[on|off],\n"
1633 " lookahead,[on|off], security-freeze, standby,[N|off], wcache,[on|off]\n"
1634 " -f Monitor 'Usage' Attributes, report failures\n"
1635 " -m ADD Send email warning to address ADD\n"
1636 " -M TYPE Modify email warning behavior (see man page)\n"
1637 " -p Report changes in 'Prefailure' Attributes\n"
1638 " -u Report changes in 'Usage' Attributes\n"
1639 " -t Equivalent to -p and -u Directives\n"
1640 " -r ID Also report Raw values of Attribute ID with -p, -u or -t\n"
1641 " -R ID Track changes in Attribute ID Raw value with -p, -u or -t\n"
1642 " -i ID Ignore Attribute ID for -f Directive\n"
1643 " -I ID Ignore Attribute ID for -p, -u or -t Directive\n"
1644 " -C ID[+] Monitor [increases of] Current Pending Sectors in Attribute ID\n"
1645 " -U ID[+] Monitor [increases of] Offline Uncorrectable Sectors in Attribute ID\n"
1646 " -W D,I,C Monitor Temperature D)ifference, I)nformal limit, C)ritical limit\n"
1647 " -v N,ST Modifies labeling of Attribute N (see man page) \n"
1648 " -P TYPE Drive-specific presets: use, ignore, show, showall\n"
1649 " -a Default: -H -f -t -l error -l selftest -l selfteststs -C 197 -U 198\n"
1650 " -F TYPE Use firmware bug workaround:\n"
1651 " %s\n"
1652 " -c i=N Set interval between disk checks to N seconds\n"
1653 " # Comment: text after a hash sign is ignored\n"
1654 " \\ Line continuation character\n"
1655 "Attribute ID is a decimal integer 1 <= ID <= 255\n"
1656 "Use ID = 0 to turn off -C and/or -U Directives\n"
1657 "Example: /dev/sda -a\n",
1658 configfile,
1659 smi()->get_valid_dev_types_str().c_str(),
1661}
1662
1663/* Returns a pointer to a static string containing a formatted list of the valid
1664 arguments to the option opt or nullptr on failure. */
1665static const char *GetValidArgList(char opt)
1666{
1667 switch (opt) {
1668 case 'A':
1669 case 's':
1670 return "<PATH_PREFIX>, -";
1671 case 'B':
1672 return "[+]<FILE_NAME>";
1673 case 'c':
1674 return "<FILE_NAME>, -";
1675 case 'l':
1676 return "daemon, local0, local1, local2, local3, local4, local5, local6, local7";
1677 case 'q':
1678 return "nodev[0], errors[,nodev0], nodev[0]startup, never, onecheck, showtests";
1679 case 'r':
1680 return "ioctl[,N], ataioctl[,N], scsiioctl[,N], nvmeioctl[,N]";
1681 case 'p':
1682 case 'w':
1683 return "<FILE_NAME>";
1684 case 'i':
1685 return "<INTEGER_SECONDS>";
1686#ifdef HAVE_POSIX_API
1687 case 'u':
1688 return "<USER>[:<GROUP>], -";
1689#elif defined(_WIN32)
1690 case 'u':
1691 return "restricted, unchanged";
1692#endif
1693#ifdef HAVE_LIBCAP_NG
1694 case 'C':
1695 return "mail, <no_argument>";
1696#endif
1697 default:
1698 return nullptr;
1699 }
1700}
1701
1702/* prints help information for command syntax */
1703static void Usage()
1704{
1705 PrintOut(LOG_INFO,"Usage: smartd [options]\n\n");
1706#ifdef SMARTMONTOOLS_ATTRIBUTELOG
1707 PrintOut(LOG_INFO," -A PREFIX|-, --attributelog=PREFIX|-\n");
1708#else
1709 PrintOut(LOG_INFO," -A PREFIX, --attributelog=PREFIX\n");
1710#endif
1711 PrintOut(LOG_INFO," Log attribute information to {PREFIX}MODEL-SERIAL.TYPE.csv\n");
1712#ifdef SMARTMONTOOLS_ATTRIBUTELOG
1713 PrintOut(LOG_INFO," [default is " SMARTMONTOOLS_ATTRIBUTELOG "MODEL-SERIAL.TYPE.csv]\n");
1714#endif
1715 PrintOut(LOG_INFO,"\n");
1716 PrintOut(LOG_INFO," -B [+]FILE, --drivedb=[+]FILE\n");
1717 PrintOut(LOG_INFO," Read and replace [add] drive database from FILE\n");
1718 PrintOut(LOG_INFO," [default is +%s", get_drivedb_path_add());
1719#ifdef SMARTMONTOOLS_DRIVEDBDIR
1720 PrintOut(LOG_INFO,"\n");
1721 PrintOut(LOG_INFO," and then %s", get_drivedb_path_default());
1722#endif
1723 PrintOut(LOG_INFO,"]\n\n");
1724 PrintOut(LOG_INFO," -c NAME|-, --configfile=NAME|-\n");
1725 PrintOut(LOG_INFO," Read configuration file NAME or stdin\n");
1726 PrintOut(LOG_INFO," [default is %s]\n\n", configfile);
1727#ifdef HAVE_LIBCAP_NG
1728 PrintOut(LOG_INFO," -C, --capabilities[=mail]\n");
1729 PrintOut(LOG_INFO," Drop unneeded Linux process capabilities.\n"
1730 " Warning: Mail notification may not work when used.\n\n");
1731#endif
1732 PrintOut(LOG_INFO," -d, --debug\n");
1733 PrintOut(LOG_INFO," Start smartd in debug mode\n\n");
1734 PrintOut(LOG_INFO," -D, --showdirectives\n");
1735 PrintOut(LOG_INFO," Print the configuration file Directives and exit\n\n");
1736 PrintOut(LOG_INFO," -h, --help, --usage\n");
1737 PrintOut(LOG_INFO," Display this help and exit\n\n");
1738 PrintOut(LOG_INFO," -i N, --interval=N\n");
1739 PrintOut(LOG_INFO," Set interval between disk checks to N seconds, where N >= 10\n\n");
1740 PrintOut(LOG_INFO," -l local[0-7], --logfacility=local[0-7]\n");
1741#ifndef _WIN32
1742 PrintOut(LOG_INFO," Use syslog facility local0 - local7 or daemon [default]\n\n");
1743#else
1744 PrintOut(LOG_INFO," Log to \"./smartd.log\", stdout, stderr [default is event log]\n\n");
1745#endif
1746#ifndef _WIN32
1747 PrintOut(LOG_INFO," -n, --no-fork\n");
1748 PrintOut(LOG_INFO," Do not fork into background\n");
1749#ifdef HAVE_LIBSYSTEMD
1750 PrintOut(LOG_INFO," (systemd 'Type=notify' is assumed if $NOTIFY_SOCKET is set)\n");
1751#endif // HAVE_LIBSYSTEMD
1752 PrintOut(LOG_INFO,"\n");
1753#endif // WIN32
1754 PrintOut(LOG_INFO," -p NAME, --pidfile=NAME\n");
1755 PrintOut(LOG_INFO," Write PID file NAME\n\n");
1756 PrintOut(LOG_INFO," -q WHEN, --quit=WHEN\n");
1757 PrintOut(LOG_INFO," Quit on one of: %s\n\n", GetValidArgList('q'));
1758 PrintOut(LOG_INFO," -r, --report=TYPE\n");
1759 PrintOut(LOG_INFO," Report transactions for one of: %s\n\n", GetValidArgList('r'));
1760#ifdef SMARTMONTOOLS_SAVESTATES
1761 PrintOut(LOG_INFO," -s PREFIX|-, --savestates=PREFIX|-\n");
1762#else
1763 PrintOut(LOG_INFO," -s PREFIX, --savestates=PREFIX\n");
1764#endif
1765 PrintOut(LOG_INFO," Save disk states to {PREFIX}MODEL-SERIAL.TYPE.state\n");
1766#ifdef SMARTMONTOOLS_SAVESTATES
1767 PrintOut(LOG_INFO," [default is " SMARTMONTOOLS_SAVESTATES "MODEL-SERIAL.TYPE.state]\n");
1768#endif
1769 PrintOut(LOG_INFO,"\n");
1770 PrintOut(LOG_INFO," -w NAME, --warnexec=NAME\n");
1771 PrintOut(LOG_INFO," Run executable NAME on warnings\n");
1772#ifndef _WIN32
1773 PrintOut(LOG_INFO," [default is " SMARTMONTOOLS_SMARTDSCRIPTDIR "/smartd_warning.sh]\n\n");
1774#else
1775 PrintOut(LOG_INFO," [default is %s/smartd_warning.cmd]\n\n", get_exe_dir().c_str());
1776#endif
1777#ifdef HAVE_POSIX_API
1778 PrintOut(LOG_INFO," -u USER[:GROUP], --warn-as-user=USER[:GROUP]\n");
1779 PrintOut(LOG_INFO," Run warning script as non-privileged USER\n\n");
1780#elif defined(_WIN32)
1781 PrintOut(LOG_INFO," -u MODE, --warn-as-user=MODE\n");
1782 PrintOut(LOG_INFO," Run warning script with modified access token: %s\n\n", GetValidArgList('u'));
1783#endif
1784#ifdef _WIN32
1785 PrintOut(LOG_INFO," --service\n");
1786 PrintOut(LOG_INFO," Running as windows service (see man page), install with:\n");
1787 PrintOut(LOG_INFO," smartd install [options]\n");
1788 PrintOut(LOG_INFO," Remove service with:\n");
1789 PrintOut(LOG_INFO," smartd remove\n\n");
1790#endif // _WIN32
1791 PrintOut(LOG_INFO," -V, --version, --license, --copyright\n");
1792 PrintOut(LOG_INFO," Print License, Copyright, and version information\n");
1793}
1794
1795static int CloseDevice(smart_device * device, const char * name)
1796{
1797 if (!device->close()){
1798 PrintOut(LOG_INFO,"Device: %s, %s, close() failed\n", name, device->get_errmsg());
1799 return 1;
1800 }
1801 // device successfully closed
1802 return 0;
1803}
1804
1805// Replace invalid characters in cfg.dev_idinfo
1806static bool sanitize_dev_idinfo(std::string & s)
1807{
1808 bool changed = false;
1809 for (unsigned i = 0; i < s.size(); i++) {
1810 char c = s[i];
1811 STATIC_ASSERT(' ' == 0x20 && '~' == 0x07e); // Assume ASCII
1812 // Don't pass possible command escapes ('~! COMMAND') to the 'mail' command.
1813 if ((' ' <= c && c <= '~') && !(i == 0 && c == '~'))
1814 continue;
1815 s[i] = '?';
1816 changed = true;
1817 }
1818 return changed;
1819}
1820
1821// return true if a char is not allowed in a state file name
1822static bool not_allowed_in_filename(char c)
1823{
1824 return !( ('0' <= c && c <= '9')
1825 || ('A' <= c && c <= 'Z')
1826 || ('a' <= c && c <= 'z'));
1827}
1828
1829// Read error count from Summary or Extended Comprehensive SMART error log
1830// Return -1 on error
1831static int read_ata_error_count(ata_device * device, const char * name,
1832 firmwarebug_defs firmwarebugs, bool extended)
1833{
1834 if (!extended) {
1836 if (ataReadErrorLog(device, &log, firmwarebugs)){
1837 PrintOut(LOG_INFO,"Device: %s, Read Summary SMART Error Log failed\n",name);
1838 return -1;
1839 }
1840 return (log.error_log_pointer ? log.ata_error_count : 0);
1841 }
1842 else {
1844 if (!ataReadExtErrorLog(device, &logx, 0, 1 /*first sector only*/, firmwarebugs)) {
1845 PrintOut(LOG_INFO,"Device: %s, Read Extended Comprehensive SMART Error Log failed\n",name);
1846 return -1;
1847 }
1848 // Some disks use the reserved byte as index, see ataprint.cpp.
1849 return (logx.error_log_index || logx.reserved1 ? logx.device_error_count : 0);
1850 }
1851}
1852
1853// Count error entries in ATA self-test log, set HOUR to power on hours of most
1854// recent error. Return error count or -1 on failure.
1855static int check_ata_self_test_log(ata_device * device, const char * name,
1856 firmwarebug_defs firmwarebugs,
1857 unsigned & hour)
1858{
1859 struct ata_smart_selftestlog log;
1860
1861 hour = 0;
1862 if (ataReadSelfTestLog(device, &log, firmwarebugs)){
1863 PrintOut(LOG_INFO,"Device: %s, Read SMART Self Test Log Failed\n",name);
1864 return -1;
1865 }
1866
1867 if (!log.mostrecenttest)
1868 // No tests logged
1869 return 0;
1870
1871 // Count failed self-tests
1872 int errcnt = 0;
1873 for (int i = 20; i >= 0; i--) {
1874 int j = (i + log.mostrecenttest) % 21;
1876 if (!nonempty(&entry, sizeof(entry)))
1877 continue;
1878
1879 int status = entry.selfteststatus >> 4;
1880 if (status == 0x0 && (entry.selftestnumber & 0x7f) == 0x02)
1881 // First successful extended self-test, stop count
1882 break;
1883
1884 if (0x3 <= status && status <= 0x8) {
1885 // Self-test showed an error
1886 errcnt++;
1887 // Keep track of time of most recent error
1888 if (!hour)
1889 hour = entry.timestamp;
1890 }
1891 }
1892
1893 return errcnt;
1894}
1895
1896// Check offline data collection status
1897static inline bool is_offl_coll_in_progress(unsigned char status)
1898{
1899 return ((status & 0x7f) == 0x03);
1900}
1901
1902// Check self-test execution status
1903static inline bool is_self_test_in_progress(unsigned char status)
1904{
1905 return ((status >> 4) == 0xf);
1906}
1907
1908// Log offline data collection status
1909static void log_offline_data_coll_status(const char * name, unsigned char status)
1910{
1911 const char * msg;
1912 switch (status & 0x7f) {
1913 case 0x00: msg = "was never started"; break;
1914 case 0x02: msg = "was completed without error"; break;
1915 case 0x03: msg = "is in progress"; break;
1916 case 0x04: msg = "was suspended by an interrupting command from host"; break;
1917 case 0x05: msg = "was aborted by an interrupting command from host"; break;
1918 case 0x06: msg = "was aborted by the device with a fatal error"; break;
1919 default: msg = nullptr;
1920 }
1921
1922 if (msg)
1923 PrintOut(((status & 0x7f) == 0x06 ? LOG_CRIT : LOG_INFO),
1924 "Device: %s, offline data collection %s%s\n", name, msg,
1925 ((status & 0x80) ? " (auto:on)" : ""));
1926 else
1927 PrintOut(LOG_INFO, "Device: %s, unknown offline data collection status 0x%02x\n",
1928 name, status);
1929}
1930
1931// Log self-test execution status
1932static void log_self_test_exec_status(const char * name, unsigned char status)
1933{
1934 const char * msg;
1935 switch (status >> 4) {
1936 case 0x0: msg = "completed without error"; break;
1937 case 0x1: msg = "was aborted by the host"; break;
1938 case 0x2: msg = "was interrupted by the host with a reset"; break;
1939 case 0x3: msg = "could not complete due to a fatal or unknown error"; break;
1940 case 0x4: msg = "completed with error (unknown test element)"; break;
1941 case 0x5: msg = "completed with error (electrical test element)"; break;
1942 case 0x6: msg = "completed with error (servo/seek test element)"; break;
1943 case 0x7: msg = "completed with error (read test element)"; break;
1944 case 0x8: msg = "completed with error (handling damage?)"; break;
1945 default: msg = nullptr;
1946 }
1947
1948 if (msg)
1949 PrintOut(((status >> 4) >= 0x4 ? LOG_CRIT : LOG_INFO),
1950 "Device: %s, previous self-test %s\n", name, msg);
1951 else if ((status >> 4) == 0xf)
1952 PrintOut(LOG_INFO, "Device: %s, self-test in progress, %u0%% remaining\n",
1953 name, status & 0x0f);
1954 else
1955 PrintOut(LOG_INFO, "Device: %s, unknown self-test status 0x%02x\n",
1956 name, status);
1957}
1958
1959// Check pending sector count id (-C, -U directives).
1960static bool check_pending_id(const dev_config & cfg, const dev_state & state,
1961 unsigned char id, const char * msg)
1962{
1963 // Check attribute index
1964 int i = ata_find_attr_index(id, state.smartval);
1965 if (i < 0) {
1966 PrintOut(LOG_INFO, "Device: %s, can't monitor %s count - no Attribute %d\n",
1967 cfg.name.c_str(), msg, id);
1968 return false;
1969 }
1970
1971 // Check value
1972 uint64_t rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i],
1973 cfg.attribute_defs);
1974 if (rawval >= (state.num_sectors ? state.num_sectors : 0xffffffffULL)) {
1975 PrintOut(LOG_INFO, "Device: %s, ignoring %s count - bogus Attribute %d value %" PRIu64 " (0x%" PRIx64 ")\n",
1976 cfg.name.c_str(), msg, id, rawval, rawval);
1977 return false;
1978 }
1979
1980 return true;
1981}
1982
1983// Called by ATA/SCSI/NVMeDeviceScan() after successful device check
1984static void finish_device_scan(dev_config & cfg, dev_state & state)
1985{
1986 // Set cfg.emailfreq if user hasn't set it
1987 if ((!cfg.emailaddress.empty() || !cfg.emailcmdline.empty()) && cfg.emailfreq == emailfreqs::unknown) {
1988 // Avoid that emails are suppressed forever due to state persistence
1989 if (cfg.state_file.empty())
1991 else
1993 }
1994
1995 // Start self-test regex check now if time was not read from state file
1996 if (!cfg.test_regex.empty() && !state.scheduled_test_next_check)
1997 state.scheduled_test_next_check = time(nullptr);
1998}
1999
2000// Common function to format result message for ATA setting
2001static void format_set_result_msg(std::string & msg, const char * name, bool ok,
2002 int set_option = 0, bool has_value = false)
2003{
2004 if (!msg.empty())
2005 msg += ", ";
2006 msg += name;
2007 if (!ok)
2008 msg += ":--";
2009 else if (set_option < 0)
2010 msg += ":off";
2011 else if (has_value)
2012 msg += strprintf(":%d", set_option-1);
2013 else if (set_option > 0)
2014 msg += ":on";
2015}
2016
2017// Return true and print message if CFG.dev_idinfo is already in PREV_CFGS
2018static bool is_duplicate_dev_idinfo(const dev_config & cfg, const dev_config_vector & prev_cfgs)
2019{
2020 if (!cfg.id_is_unique)
2021 return false;
2022
2023 for (const auto & prev_cfg : prev_cfgs) {
2024 if (!prev_cfg.id_is_unique)
2025 continue;
2026 if (!( cfg.dev_idinfo == prev_cfg.dev_idinfo
2027 // Also check identity without NSID if device does not support multiple namespaces
2028 || (!cfg.dev_idinfo_bc.empty() && cfg.dev_idinfo_bc == prev_cfg.dev_idinfo)
2029 || (!prev_cfg.dev_idinfo_bc.empty() && cfg.dev_idinfo == prev_cfg.dev_idinfo_bc)))
2030 continue;
2031
2032 PrintOut(LOG_INFO, "Device: %s, same identity as %s, ignored\n",
2033 cfg.dev_name.c_str(), prev_cfg.dev_name.c_str());
2034 return true;
2035 }
2036
2037 return false;
2038}
2039
2040// TODO: Add '-F swapid' directive
2041const bool fix_swapped_id = false;
2042
2043// scan to see what ata devices there are, and if they support SMART
2044static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atadev,
2045 const dev_config_vector * prev_cfgs)
2046{
2047 int supported=0;
2048 struct ata_identify_device drive;
2049 const char *name = cfg.name.c_str();
2050 int retid;
2051
2052 // Device must be open
2053
2054 // Get drive identity structure
2055 if ((retid = ata_read_identity(atadev, &drive, fix_swapped_id))) {
2056 if (retid<0)
2057 // Unable to read Identity structure
2058 PrintOut(LOG_INFO,"Device: %s, not ATA, no IDENTIFY DEVICE Structure\n",name);
2059 else
2060 PrintOut(LOG_INFO,"Device: %s, packet devices [this device %s] not SMART capable\n",
2061 name, packetdevicetype(retid-1));
2062 CloseDevice(atadev, name);
2063 return 2;
2064 }
2065
2066 // Get drive identity, size and rotation rate (HDD/SSD)
2067 char model[40+1], serial[20+1], firmware[8+1];
2068 ata_format_id_string(model, drive.model, sizeof(model)-1);
2069 ata_format_id_string(serial, drive.serial_no, sizeof(serial)-1);
2070 ata_format_id_string(firmware, drive.fw_rev, sizeof(firmware)-1);
2071
2072 ata_size_info sizes;
2073 ata_get_size_info(&drive, sizes);
2074 state.num_sectors = sizes.sectors;
2075 cfg.dev_rpm = ata_get_rotation_rate(&drive);
2076
2077 char wwn[64]; wwn[0] = 0;
2078 unsigned oui = 0; uint64_t unique_id = 0;
2079 int naa = ata_get_wwn(&drive, oui, unique_id);
2080 if (naa >= 0)
2081 snprintf(wwn, sizeof(wwn), "WWN:%x-%06x-%09" PRIx64 ", ", naa, oui, unique_id);
2082
2083 // Format device id string for warning emails
2084 char cap[32];
2085 cfg.dev_idinfo = strprintf("%s, S/N:%s, %sFW:%s, %s", model, serial, wwn, firmware,
2086 format_capacity(cap, sizeof(cap), sizes.capacity, "."));
2087 cfg.id_is_unique = true; // TODO: Check serial?
2089 cfg.id_is_unique = false;
2090
2091 PrintOut(LOG_INFO, "Device: %s, %s\n", name, cfg.dev_idinfo.c_str());
2092
2093 // Check for duplicates
2094 if (prev_cfgs && is_duplicate_dev_idinfo(cfg, *prev_cfgs)) {
2095 CloseDevice(atadev, name);
2096 return 1;
2097 }
2098
2099 // Show if device in database, and use preset vendor attribute
2100 // options unless user has requested otherwise.
2101 if (cfg.ignorepresets)
2102 PrintOut(LOG_INFO, "Device: %s, smartd database not searched (Directive: -P ignore).\n", name);
2103 else {
2104 // Apply vendor specific presets, print warning if present
2105 std::string dbversion;
2107 &drive, cfg.attribute_defs, cfg.firmwarebugs, dbversion);
2108 if (!dbentry)
2109 PrintOut(LOG_INFO, "Device: %s, not found in smartd database%s%s.\n", name,
2110 (!dbversion.empty() ? " " : ""), (!dbversion.empty() ? dbversion.c_str() : ""));
2111 else {
2112 PrintOut(LOG_INFO, "Device: %s, found in smartd database%s%s%s%s\n",
2113 name, (!dbversion.empty() ? " " : ""), (!dbversion.empty() ? dbversion.c_str() : ""),
2114 (*dbentry->modelfamily ? ": " : "."), (*dbentry->modelfamily ? dbentry->modelfamily : ""));
2115 if (*dbentry->warningmsg)
2116 PrintOut(LOG_CRIT, "Device: %s, WARNING: %s\n", name, dbentry->warningmsg);
2117 }
2118 }
2119
2120 // Check for ATA Security LOCK
2121 unsigned short word128 = drive.words088_255[128-88];
2122 bool locked = ((word128 & 0x0007) == 0x0007); // LOCKED|ENABLED|SUPPORTED
2123 if (locked)
2124 PrintOut(LOG_INFO, "Device: %s, ATA Security is **LOCKED**\n", name);
2125
2126 // Set default '-C 197[+]' if no '-C ID' is specified.
2127 if (!cfg.curr_pending_set)
2129 // Set default '-U 198[+]' if no '-U ID' is specified.
2130 if (!cfg.offl_pending_set)
2132
2133 // If requested, show which presets would be used for this drive
2134 if (cfg.showpresets) {
2135 int savedebugmode=debugmode;
2136 PrintOut(LOG_INFO, "Device %s: presets are:\n", name);
2137 if (!debugmode)
2138 debugmode=2;
2139 show_presets(&drive);
2140 debugmode=savedebugmode;
2141 }
2142
2143 // see if drive supports SMART
2144 supported=ataSmartSupport(&drive);
2145 if (supported!=1) {
2146 if (supported==0)
2147 // drive does NOT support SMART
2148 PrintOut(LOG_INFO,"Device: %s, lacks SMART capability\n",name);
2149 else
2150 // can't tell if drive supports SMART
2151 PrintOut(LOG_INFO,"Device: %s, ATA IDENTIFY DEVICE words 82-83 don't specify if SMART capable.\n",name);
2152
2153 // should we proceed anyway?
2154 if (cfg.permissive) {
2155 PrintOut(LOG_INFO,"Device: %s, proceeding since '-T permissive' Directive given.\n",name);
2156 }
2157 else {
2158 PrintOut(LOG_INFO,"Device: %s, to proceed anyway, use '-T permissive' Directive.\n",name);
2159 CloseDevice(atadev, name);
2160 return 2;
2161 }
2162 }
2163
2164 if (ataEnableSmart(atadev)) {
2165 // Enable SMART command has failed
2166 PrintOut(LOG_INFO,"Device: %s, could not enable SMART capability\n",name);
2167
2168 if (ataIsSmartEnabled(&drive) <= 0) {
2169 if (!cfg.permissive) {
2170 PrintOut(LOG_INFO, "Device: %s, to proceed anyway, use '-T permissive' Directive.\n", name);
2171 CloseDevice(atadev, name);
2172 return 2;
2173 }
2174 PrintOut(LOG_INFO, "Device: %s, proceeding since '-T permissive' Directive given.\n", name);
2175 }
2176 else {
2177 PrintOut(LOG_INFO, "Device: %s, proceeding since SMART is already enabled\n", name);
2178 }
2179 }
2180
2181 // disable device attribute autosave...
2182 if (cfg.autosave==1) {
2183 if (ataDisableAutoSave(atadev))
2184 PrintOut(LOG_INFO,"Device: %s, could not disable SMART Attribute Autosave.\n",name);
2185 else
2186 PrintOut(LOG_INFO,"Device: %s, disabled SMART Attribute Autosave.\n",name);
2187 }
2188
2189 // or enable device attribute autosave
2190 if (cfg.autosave==2) {
2191 if (ataEnableAutoSave(atadev))
2192 PrintOut(LOG_INFO,"Device: %s, could not enable SMART Attribute Autosave.\n",name);
2193 else
2194 PrintOut(LOG_INFO,"Device: %s, enabled SMART Attribute Autosave.\n",name);
2195 }
2196
2197 // capability check: SMART status
2198 if (cfg.smartcheck && ataSmartStatus2(atadev) == -1) {
2199 PrintOut(LOG_INFO,"Device: %s, not capable of SMART Health Status check\n",name);
2200 cfg.smartcheck = false;
2201 }
2202
2203 // capability check: Read smart values and thresholds. Note that
2204 // smart values are ALSO needed even if we ONLY want to know if the
2205 // device is self-test log or error-log capable! After ATA-5, this
2206 // information was ALSO reproduced in the IDENTIFY DEVICE response,
2207 // but sadly not for ATA-5. Sigh.
2208
2209 // do we need to get SMART data?
2210 bool smart_val_ok = false;
2211 if ( cfg.autoofflinetest || cfg.selftest
2212 || cfg.errorlog || cfg.xerrorlog
2213 || cfg.offlinests || cfg.selfteststs
2214 || cfg.usagefailed || cfg.prefail || cfg.usage
2215 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit
2216 || cfg.curr_pending_id || cfg.offl_pending_id ) {
2217
2218 if (ataReadSmartValues(atadev, &state.smartval)) {
2219 PrintOut(LOG_INFO, "Device: %s, Read SMART Values failed\n", name);
2220 cfg.usagefailed = cfg.prefail = cfg.usage = false;
2221 cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
2222 cfg.curr_pending_id = cfg.offl_pending_id = 0;
2223 }
2224 else {
2225 smart_val_ok = true;
2226 if (ataReadSmartThresholds(atadev, &state.smartthres)) {
2227 PrintOut(LOG_INFO, "Device: %s, Read SMART Thresholds failed%s\n",
2228 name, (cfg.usagefailed ? ", ignoring -f Directive" : ""));
2229 cfg.usagefailed = false;
2230 // Let ata_get_attr_state() return ATTRSTATE_NO_THRESHOLD:
2231 memset(&state.smartthres, 0, sizeof(state.smartthres));
2232 }
2233 }
2234
2235 // see if the necessary Attribute is there to monitor offline or
2236 // current pending sectors or temperature
2237 if ( cfg.curr_pending_id
2238 && !check_pending_id(cfg, state, cfg.curr_pending_id,
2239 "Current_Pending_Sector"))
2240 cfg.curr_pending_id = 0;
2241
2242 if ( cfg.offl_pending_id
2243 && !check_pending_id(cfg, state, cfg.offl_pending_id,
2244 "Offline_Uncorrectable"))
2245 cfg.offl_pending_id = 0;
2246
2247 if ( (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
2249 PrintOut(LOG_INFO, "Device: %s, can't monitor Temperature, ignoring -W %d,%d,%d\n",
2250 name, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit);
2251 cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
2252 }
2253
2254 // Report ignored '-r' or '-R' directives
2255 for (int id = 1; id <= 255; id++) {
2257 char opt = (!cfg.monitor_attr_flags.is_set(id, MONITOR_RAW) ? 'r' : 'R');
2258 const char * excl = (cfg.monitor_attr_flags.is_set(id,
2259 (opt == 'r' ? MONITOR_AS_CRIT : MONITOR_RAW_AS_CRIT)) ? "!" : "");
2260
2261 int idx = ata_find_attr_index(id, state.smartval);
2262 if (idx < 0)
2263 PrintOut(LOG_INFO,"Device: %s, no Attribute %d, ignoring -%c %d%s\n", name, id, opt, id, excl);
2264 else {
2265 bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(state.smartval.vendor_attributes[idx].flags);
2266 if (!((prefail && cfg.prefail) || (!prefail && cfg.usage)))
2267 PrintOut(LOG_INFO,"Device: %s, not monitoring %s Attributes, ignoring -%c %d%s\n", name,
2268 (prefail ? "Prefailure" : "Usage"), opt, id, excl);
2269 }
2270 }
2271 }
2272 }
2273
2274 // enable/disable automatic on-line testing
2275 if (cfg.autoofflinetest) {
2276 // is this an enable or disable request?
2277 const char *what=(cfg.autoofflinetest==1)?"disable":"enable";
2278 if (!smart_val_ok)
2279 PrintOut(LOG_INFO,"Device: %s, could not %s SMART Automatic Offline Testing.\n",name, what);
2280 else {
2281 // if command appears unsupported, issue a warning...
2282 if (!isSupportAutomaticTimer(&state.smartval))
2283 PrintOut(LOG_INFO,"Device: %s, SMART Automatic Offline Testing unsupported...\n",name);
2284 // ... but then try anyway
2285 if ((cfg.autoofflinetest==1)?ataDisableAutoOffline(atadev):ataEnableAutoOffline(atadev))
2286 PrintOut(LOG_INFO,"Device: %s, %s SMART Automatic Offline Testing failed.\n", name, what);
2287 else
2288 PrintOut(LOG_INFO,"Device: %s, %sd SMART Automatic Offline Testing.\n", name, what);
2289 }
2290 }
2291
2292 // Read log directories if required for capability check
2293 ata_smart_log_directory smart_logdir, gp_logdir;
2294 bool smart_logdir_ok = false, gp_logdir_ok = false;
2295
2297 && (cfg.errorlog || cfg.selftest)
2298 && !cfg.firmwarebugs.is_set(BUG_NOLOGDIR)) {
2299 if (!ataReadLogDirectory(atadev, &smart_logdir, false))
2300 smart_logdir_ok = true;
2301 }
2302
2303 if (cfg.xerrorlog && !cfg.firmwarebugs.is_set(BUG_NOLOGDIR)) {
2304 if (!ataReadLogDirectory(atadev, &gp_logdir, true))
2305 gp_logdir_ok = true;
2306 }
2307
2308 // capability check: self-test-log
2309 state.selflogcount = 0; state.selfloghour = 0;
2310 if (cfg.selftest) {
2311 int errcnt = 0; unsigned hour = 0;
2312 if (!( cfg.permissive
2313 || ( smart_logdir_ok && smart_logdir.entry[0x06-1].numsectors)
2314 || (!smart_logdir_ok && smart_val_ok && isSmartTestLogCapable(&state.smartval, &drive)))) {
2315 PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest (override with -T permissive)\n", name);
2316 cfg.selftest = false;
2317 }
2318 else if ((errcnt = check_ata_self_test_log(atadev, name, cfg.firmwarebugs, hour)) < 0) {
2319 PrintOut(LOG_INFO, "Device: %s, no SMART Self-test Log, ignoring -l selftest\n", name);
2320 cfg.selftest = false;
2321 }
2322 else {
2323 state.selflogcount = (unsigned char)errcnt;
2324 state.selfloghour = hour;
2325 }
2326 }
2327
2328 // capability check: ATA error log
2329 state.ataerrorcount = 0;
2330 if (cfg.errorlog) {
2331 int errcnt1;
2332 if (!( cfg.permissive
2333 || ( smart_logdir_ok && smart_logdir.entry[0x01-1].numsectors)
2334 || (!smart_logdir_ok && smart_val_ok && isSmartErrorLogCapable(&state.smartval, &drive)))) {
2335 PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error (override with -T permissive)\n", name);
2336 cfg.errorlog = false;
2337 }
2338 else if ((errcnt1 = read_ata_error_count(atadev, name, cfg.firmwarebugs, false)) < 0) {
2339 PrintOut(LOG_INFO, "Device: %s, no SMART Error Log, ignoring -l error\n", name);
2340 cfg.errorlog = false;
2341 }
2342 else
2343 state.ataerrorcount = errcnt1;
2344 }
2345
2346 if (cfg.xerrorlog) {
2347 int errcnt2;
2348 if (!( cfg.permissive || cfg.firmwarebugs.is_set(BUG_NOLOGDIR)
2349 || (gp_logdir_ok && gp_logdir.entry[0x03-1].numsectors) )) {
2350 PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror (override with -T permissive)\n",
2351 name);
2352 cfg.xerrorlog = false;
2353 }
2354 else if ((errcnt2 = read_ata_error_count(atadev, name, cfg.firmwarebugs, true)) < 0) {
2355 PrintOut(LOG_INFO, "Device: %s, no Extended Comprehensive SMART Error Log, ignoring -l xerror\n", name);
2356 cfg.xerrorlog = false;
2357 }
2358 else if (cfg.errorlog && state.ataerrorcount != errcnt2) {
2359 PrintOut(LOG_INFO, "Device: %s, SMART Error Logs report different error counts: %d != %d\n",
2360 name, state.ataerrorcount, errcnt2);
2361 // Record max error count
2362 if (errcnt2 > state.ataerrorcount)
2363 state.ataerrorcount = errcnt2;
2364 }
2365 else
2366 state.ataerrorcount = errcnt2;
2367 }
2368
2369 // capability check: self-test and offline data collection status
2370 if (cfg.offlinests || cfg.selfteststs) {
2371 if (!(cfg.permissive || (smart_val_ok && state.smartval.offline_data_collection_capability))) {
2372 if (cfg.offlinests)
2373 PrintOut(LOG_INFO, "Device: %s, no SMART Offline Data Collection capability, ignoring -l offlinests (override with -T permissive)\n", name);
2374 if (cfg.selfteststs)
2375 PrintOut(LOG_INFO, "Device: %s, no SMART Self-test capability, ignoring -l selfteststs (override with -T permissive)\n", name);
2376 cfg.offlinests = cfg.selfteststs = false;
2377 }
2378 }
2379
2380 // capabilities check -- does it support powermode?
2381 if (cfg.powermode) {
2382 int powermode = ataCheckPowerMode(atadev);
2383
2384 if (-1 == powermode) {
2385 PrintOut(LOG_CRIT, "Device: %s, no ATA CHECK POWER STATUS support, ignoring -n Directive\n", name);
2386 cfg.powermode=0;
2387 }
2388 else if (powermode!=0x00 && powermode!=0x01
2389 && powermode!=0x40 && powermode!=0x41
2390 && powermode!=0x80 && powermode!=0x81 && powermode!=0x82 && powermode!=0x83
2391 && powermode!=0xff) {
2392 PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n",
2393 name, powermode);
2394 cfg.powermode=0;
2395 }
2396 }
2397
2398 // Apply ATA settings
2399 std::string msg;
2400
2401 if (cfg.set_aam)
2402 format_set_result_msg(msg, "AAM", (cfg.set_aam > 0 ?
2403 ata_set_features(atadev, ATA_ENABLE_AAM, cfg.set_aam-1) :
2404 ata_set_features(atadev, ATA_DISABLE_AAM)), cfg.set_aam, true);
2405
2406 if (cfg.set_apm)
2407 format_set_result_msg(msg, "APM", (cfg.set_apm > 0 ?
2408 ata_set_features(atadev, ATA_ENABLE_APM, cfg.set_apm-1) :
2409 ata_set_features(atadev, ATA_DISABLE_APM)), cfg.set_apm, true);
2410
2411 if (cfg.set_lookahead)
2412 format_set_result_msg(msg, "Rd-ahead", ata_set_features(atadev,
2414 cfg.set_lookahead);
2415
2416 if (cfg.set_wcache)
2417 format_set_result_msg(msg, "Wr-cache", ata_set_features(atadev,
2419
2420 if (cfg.set_dsn)
2421 format_set_result_msg(msg, "DSN", ata_set_features(atadev,
2422 ATA_ENABLE_DISABLE_DSN, (cfg.set_dsn > 0 ? 0x1 : 0x2)));
2423
2424 if (cfg.set_security_freeze)
2425 format_set_result_msg(msg, "Security freeze",
2427
2428 if (cfg.set_standby)
2429 format_set_result_msg(msg, "Standby",
2430 ata_nodata_command(atadev, ATA_IDLE, cfg.set_standby-1), cfg.set_standby, true);
2431
2432 // Report as one log entry
2433 if (!msg.empty())
2434 PrintOut(LOG_INFO, "Device: %s, ATA settings applied: %s\n", name, msg.c_str());
2435
2436 // set SCT Error Recovery Control if requested
2437 if (cfg.sct_erc_set) {
2439 PrintOut(LOG_INFO, "Device: %s, no SCT Error Recovery Control support, ignoring -l scterc\n",
2440 name);
2441 else if (locked)
2442 PrintOut(LOG_INFO, "Device: %s, no SCT support if ATA Security is LOCKED, ignoring -l scterc\n",
2443 name);
2444 else if ( ataSetSCTErrorRecoveryControltime(atadev, 1, cfg.sct_erc_readtime, false, false )
2445 || ataSetSCTErrorRecoveryControltime(atadev, 2, cfg.sct_erc_writetime, false, false))
2446 PrintOut(LOG_INFO, "Device: %s, set of SCT Error Recovery Control failed\n", name);
2447 else
2448 PrintOut(LOG_INFO, "Device: %s, SCT Error Recovery Control set to: Read: %u, Write: %u\n",
2449 name, cfg.sct_erc_readtime, cfg.sct_erc_writetime);
2450 }
2451
2452 // If no tests available or selected, return
2453 if (!( cfg.smartcheck || cfg.selftest
2454 || cfg.errorlog || cfg.xerrorlog
2455 || cfg.offlinests || cfg.selfteststs
2456 || cfg.usagefailed || cfg.prefail || cfg.usage
2457 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) {
2458 CloseDevice(atadev, name);
2459 return 3;
2460 }
2461
2462 // tell user we are registering device
2463 PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n",name);
2464
2465 // close file descriptor
2466 CloseDevice(atadev, name);
2467
2468 if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
2469 // Build file name for state file
2470 std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
2471 std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
2472 if (!state_path_prefix.empty()) {
2473 cfg.state_file = strprintf("%s%s-%s.ata.state", state_path_prefix.c_str(), model, serial);
2474 // Read previous state
2475 if (read_dev_state(cfg.state_file.c_str(), state)) {
2476 PrintOut(LOG_INFO, "Device: %s, state read from %s\n", name, cfg.state_file.c_str());
2477 // Copy ATA attribute values to temp state
2478 state.update_temp_state();
2479 }
2480 }
2481 if (!attrlog_path_prefix.empty())
2482 cfg.attrlog_file = strprintf("%s%s-%s.ata.csv", attrlog_path_prefix.c_str(), model, serial);
2483 }
2484
2485 finish_device_scan(cfg, state);
2486
2487 return 0;
2488}
2489
2490// on success, return 0. On failure, return >0. Never return <0,
2491// please.
2492static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scsidev,
2493 const dev_config_vector * prev_cfgs)
2494{
2495 int err, req_len, avail_len, version, len;
2496 const char *device = cfg.name.c_str();
2497 struct scsi_iec_mode_page iec;
2498 uint8_t tBuf[64];
2499 uint8_t inqBuf[96];
2500 uint8_t vpdBuf[252];
2501 char lu_id[64], serial[256], vendor[40], model[40];
2502
2503 // Device must be open
2504 memset(inqBuf, 0, 96);
2505 req_len = 36;
2506 if ((err = scsiStdInquiry(scsidev, inqBuf, req_len))) {
2507 /* Marvell controllers fail on a 36 bytes StdInquiry, but 64 suffices */
2508 req_len = 64;
2509 int err64;
2510 if ((err64 = scsiStdInquiry(scsidev, inqBuf, req_len))) {
2511 PrintOut(LOG_INFO, "Device: %s, Both 36 and 64 byte INQUIRY failed; "
2512 "skip device [err=%d, %d]\n", device, err, err64);
2513 return 2;
2514 }
2515 }
2516 version = (inqBuf[2] & 0x7f); /* Accept old ISO/IEC 9316:1995 variants */
2517
2518 avail_len = inqBuf[4] + 5;
2519 len = (avail_len < req_len) ? avail_len : req_len;
2520 if (len < 36) {
2521 PrintOut(LOG_INFO, "Device: %s, INQUIRY response less than 36 bytes; "
2522 "skip device\n", device);
2523 return 2;
2524 }
2525
2526 int pdt = inqBuf[0] & 0x1f;
2527
2528 switch (pdt) {
2530 case SCSI_PT_WO:
2531 case SCSI_PT_CDROM:
2532 case SCSI_PT_OPTICAL:
2533 case SCSI_PT_RBC: /* Reduced Block commands */
2534 case SCSI_PT_HOST_MANAGED: /* Zoned disk */
2535 break;
2536 default:
2537 PrintOut(LOG_INFO, "Device: %s, not a disk like device [PDT=0x%x], "
2538 "skip\n", device, pdt);
2539 return 2;
2540 }
2541
2543 delete supported_vpd_pages_p;
2544 supported_vpd_pages_p = nullptr;
2545 }
2547
2548 lu_id[0] = '\0';
2549 if (version >= 0x3) {
2550 /* SPC to SPC-5, assume SPC-6 is version==8 or higher */
2552 vpdBuf, sizeof(vpdBuf))) {
2553 len = vpdBuf[3];
2554 scsi_decode_lu_dev_id(vpdBuf + 4, len, lu_id, sizeof(lu_id), nullptr);
2555 }
2556 }
2557 serial[0] = '\0';
2559 vpdBuf, sizeof(vpdBuf))) {
2560 len = vpdBuf[3];
2561 vpdBuf[4 + len] = '\0';
2562 scsi_format_id_string(serial, &vpdBuf[4], len);
2563 }
2564
2565 char si_str[64];
2566 struct scsi_readcap_resp srr;
2567 uint64_t capacity = scsiGetSize(scsidev, scsidev->use_rcap16(), &srr);
2568
2569 if (capacity)
2570 format_capacity(si_str, sizeof(si_str), capacity, ".");
2571 else
2572 si_str[0] = '\0';
2573
2574 // Format device id string for warning emails
2575 cfg.dev_idinfo = strprintf("[%.8s %.16s %.4s]%s%s%s%s%s%s",
2576 (char *)&inqBuf[8], (char *)&inqBuf[16], (char *)&inqBuf[32],
2577 (lu_id[0] ? ", lu id: " : ""), (lu_id[0] ? lu_id : ""),
2578 (serial[0] ? ", S/N: " : ""), (serial[0] ? serial : ""),
2579 (si_str[0] ? ", " : ""), (si_str[0] ? si_str : ""));
2580 cfg.id_is_unique = (lu_id[0] || serial[0]);
2582 cfg.id_is_unique = false;
2583
2584 // format "model" string
2585 scsi_format_id_string(vendor, &inqBuf[8], 8);
2586 scsi_format_id_string(model, &inqBuf[16], 16);
2587 PrintOut(LOG_INFO, "Device: %s, %s\n", device, cfg.dev_idinfo.c_str());
2588
2589 // Check for duplicates
2590 if (prev_cfgs && is_duplicate_dev_idinfo(cfg, *prev_cfgs)) {
2591 CloseDevice(scsidev, device);
2592 return 1;
2593 }
2594
2595 // check that device is ready for commands. IE stores its stuff on
2596 // the media.
2597 if ((err = scsiTestUnitReady(scsidev))) {
2598 if (SIMPLE_ERR_NOT_READY == err)
2599 PrintOut(LOG_INFO, "Device: %s, NOT READY (e.g. spun down); skip device\n", device);
2600 else if (SIMPLE_ERR_NO_MEDIUM == err)
2601 PrintOut(LOG_INFO, "Device: %s, NO MEDIUM present; skip device\n", device);
2602 else if (SIMPLE_ERR_BECOMING_READY == err)
2603 PrintOut(LOG_INFO, "Device: %s, BECOMING (but not yet) READY; skip device\n", device);
2604 else
2605 PrintOut(LOG_CRIT, "Device: %s, failed Test Unit Ready [err=%d]\n", device, err);
2606 CloseDevice(scsidev, device);
2607 return 2;
2608 }
2609
2610 // Badly-conforming USB storage devices may fail this check.
2611 // The response to the following IE mode page fetch (current and
2612 // changeable values) is carefully examined. It has been found
2613 // that various USB devices that malform the response will lock up
2614 // if asked for a log page (e.g. temperature) so it is best to
2615 // bail out now.
2616 if (!(err = scsiFetchIECmpage(scsidev, &iec, state.modese_len)))
2617 state.modese_len = iec.modese_len;
2618 else if (SIMPLE_ERR_BAD_FIELD == err)
2619 ; /* continue since it is reasonable not to support IE mpage */
2620 else { /* any other error (including malformed response) unreasonable */
2621 PrintOut(LOG_INFO,
2622 "Device: %s, Bad IEC (SMART) mode page, err=%d, skip device\n",
2623 device, err);
2624 CloseDevice(scsidev, device);
2625 return 3;
2626 }
2627
2628 // N.B. The following is passive (i.e. it doesn't attempt to turn on
2629 // smart if it is off). This may change to be the same as the ATA side.
2630 if (!scsi_IsExceptionControlEnabled(&iec)) {
2631 PrintOut(LOG_INFO, "Device: %s, IE (SMART) not enabled, skip device\n"
2632 "Try 'smartctl -s on %s' to turn on SMART features\n",
2633 device, device);
2634 CloseDevice(scsidev, device);
2635 return 3;
2636 }
2637
2638 // Flag that certain log pages are supported (information may be
2639 // available from other sources).
2640 if (0 == scsiLogSense(scsidev, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 0) ||
2641 0 == scsiLogSense(scsidev, SUPPORTED_LPAGES, 0, tBuf, sizeof(tBuf), 68))
2642 /* workaround for the bug #678 on ST8000NM0075/E001. Up to 64 pages + 4b header */
2643 {
2644 for (int k = 4; k < tBuf[3] + LOGPAGEHDRSIZE; ++k) {
2645 switch (tBuf[k]) {
2646 case TEMPERATURE_LPAGE:
2647 state.TempPageSupported = 1;
2648 break;
2649 case IE_LPAGE:
2650 state.SmartPageSupported = 1;
2651 break;
2653 state.ReadECounterPageSupported = 1;
2654 break;
2657 break;
2660 break;
2663 break;
2664 default:
2665 break;
2666 }
2667 }
2668 }
2669
2670 // Check if scsiCheckIE() is going to work
2671 {
2672 uint8_t asc = 0;
2673 uint8_t ascq = 0;
2674 uint8_t currenttemp = 0;
2675 uint8_t triptemp = 0;
2676
2677 if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported,
2678 &asc, &ascq, &currenttemp, &triptemp)) {
2679 PrintOut(LOG_INFO, "Device: %s, unexpectedly failed to read SMART values\n", device);
2680 state.SuppressReport = 1;
2681 }
2682 if ( (state.SuppressReport || !currenttemp)
2683 && (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) {
2684 PrintOut(LOG_INFO, "Device: %s, can't monitor Temperature, ignoring -W %d,%d,%d\n",
2685 device, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit);
2686 cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
2687 }
2688 }
2689
2690 // capability check: self-test-log
2691 if (cfg.selftest){
2692 int retval = scsiCountFailedSelfTests(scsidev, 0);
2693 if (retval<0) {
2694 // no self-test log, turn off monitoring
2695 PrintOut(LOG_INFO, "Device: %s, does not support SMART Self-Test Log.\n", device);
2696 cfg.selftest = false;
2697 state.selflogcount = 0;
2698 state.selfloghour = 0;
2699 }
2700 else {
2701 // register starting values to watch for changes
2702 state.selflogcount = retval & 0xff;
2703 state.selfloghour = (retval >> 8) & 0xffff;
2704 }
2705 }
2706
2707 // disable autosave (set GLTSD bit)
2708 if (cfg.autosave==1){
2709 if (scsiSetControlGLTSD(scsidev, 1, state.modese_len))
2710 PrintOut(LOG_INFO,"Device: %s, could not disable autosave (set GLTSD bit).\n",device);
2711 else
2712 PrintOut(LOG_INFO,"Device: %s, disabled autosave (set GLTSD bit).\n",device);
2713 }
2714
2715 // or enable autosave (clear GLTSD bit)
2716 if (cfg.autosave==2){
2717 if (scsiSetControlGLTSD(scsidev, 0, state.modese_len))
2718 PrintOut(LOG_INFO,"Device: %s, could not enable autosave (clear GLTSD bit).\n",device);
2719 else
2720 PrintOut(LOG_INFO,"Device: %s, enabled autosave (cleared GLTSD bit).\n",device);
2721 }
2722
2723 // tell user we are registering device
2724 PrintOut(LOG_INFO, "Device: %s, is SMART capable. Adding to \"monitor\" list.\n", device);
2725
2726 // Disable ATA specific self-tests
2727 state.not_cap_conveyance = state.not_cap_offline = state.not_cap_selective = true;
2728
2729 // Make sure that init_standby_check() ignores SCSI devices
2730 cfg.offlinests_ns = cfg.selfteststs_ns = false;
2731
2732 // close file descriptor
2733 CloseDevice(scsidev, device);
2734
2735 if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
2736 // Build file name for state file
2737 std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
2738 std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
2739 if (!state_path_prefix.empty()) {
2740 cfg.state_file = strprintf("%s%s-%s-%s.scsi.state", state_path_prefix.c_str(), vendor, model, serial);
2741 // Read previous state
2742 if (read_dev_state(cfg.state_file.c_str(), state)) {
2743 PrintOut(LOG_INFO, "Device: %s, state read from %s\n", device, cfg.state_file.c_str());
2744 // Copy ATA attribute values to temp state
2745 state.update_temp_state();
2746 }
2747 }
2748 if (!attrlog_path_prefix.empty())
2749 cfg.attrlog_file = strprintf("%s%s-%s-%s.scsi.csv", attrlog_path_prefix.c_str(), vendor, model, serial);
2750 }
2751
2752 finish_device_scan(cfg, state);
2753
2754 return 0;
2755}
2756
2757// Check the NVMe Error Information log for device related errors.
2758static bool check_nvme_error_log(const dev_config & cfg, dev_state & state, nvme_device * nvmedev,
2759 uint64_t newcnt = 0)
2760{
2761 // Limit transfer size to one page (64 entries) to avoid problems with
2762 // limits of NVMe pass-through layer or too low MDTS values.
2763 unsigned want_entries = 64;
2764 if (want_entries > cfg.nvme_err_log_max_entries)
2765 want_entries = cfg.nvme_err_log_max_entries;
2766 raw_buffer error_log_buf(want_entries * sizeof(nvme_error_log_page));
2767 nvme_error_log_page * error_log =
2768 reinterpret_cast<nvme_error_log_page *>(error_log_buf.data());
2769 unsigned read_entries = nvme_read_error_log(nvmedev, error_log, want_entries, false /*!lpo_sup*/);
2770 if (!read_entries) {
2771 PrintOut(LOG_INFO, "Device: %s, Read %u entries from Error Information Log failed\n",
2772 cfg.name.c_str(), want_entries);
2773 return false;
2774 }
2775
2776 if (!newcnt)
2777 return true; // Support check only
2778
2779 // Scan log, find device related errors
2780 uint64_t oldcnt = state.nvme_err_log_entries, mincnt = newcnt;
2781 int err = 0, ign = 0;
2782 for (unsigned i = 0; i < read_entries; i++) {
2783 const nvme_error_log_page & e = error_log[i];
2784 if (!e.error_count)
2785 continue; // unused
2786 if (e.error_count <= oldcnt)
2787 break; // stop on first old entry
2788 if (e.error_count < mincnt)
2789 mincnt = e.error_count; // min known error
2790 if (e.error_count > newcnt)
2791 newcnt = e.error_count; // adjust maximum
2792 uint16_t status = e.status_field >> 1;
2793 if (!nvme_status_is_error(status) || nvme_status_to_errno(status) == EINVAL) {
2794 ign++; // Not a device related error
2795 continue;
2796 }
2797
2798 // Log the most recent 8 errors
2799 if (++err > 8)
2800 continue;
2801 char buf[64];
2802 PrintOut(LOG_INFO, "Device: %s, NVMe error [%u], count %" PRIu64 ", status 0x%04x: %s\n",
2803 cfg.name.c_str(), i, e.error_count, e.status_field,
2805 }
2806
2807 std::string msg = strprintf("Device: %s, NVMe error count increased from %" PRIu64 " to %" PRIu64
2808 " (%d new, %d ignored, %" PRIu64 " unknown)",
2809 cfg.name.c_str(), oldcnt, newcnt, err, ign,
2810 (mincnt > oldcnt + 1 ? mincnt - oldcnt - 1 : 0));
2811 // LOG_CRIT only if device related errors are found
2812 if (!err) {
2813 PrintOut(LOG_INFO, "%s\n", msg.c_str());
2814 }
2815 else {
2816 PrintOut(LOG_CRIT, "%s\n", msg.c_str());
2817 MailWarning(cfg, state, 4, "%s", msg.c_str());
2818 }
2819
2820 state.nvme_err_log_entries = newcnt;
2821 state.must_write = true;
2822 return true;
2823}
2824
2825static int NVMeDeviceScan(dev_config & cfg, dev_state & state, nvme_device * nvmedev,
2826 const dev_config_vector * prev_cfgs)
2827{
2828 const char *name = cfg.name.c_str();
2829
2830 // Device must be open
2831
2832 // Get ID Controller
2833 nvme_id_ctrl id_ctrl;
2834 if (!nvme_read_id_ctrl(nvmedev, id_ctrl)) {
2835 PrintOut(LOG_INFO, "Device: %s, NVMe Identify Controller failed\n", name);
2836 CloseDevice(nvmedev, name);
2837 return 2;
2838 }
2839
2840 // Get drive identity
2841 char model[40+1], serial[20+1], firmware[8+1];
2842 format_char_array(model, id_ctrl.mn);
2843 format_char_array(serial, id_ctrl.sn);
2844 format_char_array(firmware, id_ctrl.fr);
2845
2846 // Format device id string for warning emails
2847 char nsstr[32] = "", capstr[32] = "";
2848 unsigned nsid = nvmedev->get_nsid();
2850 snprintf(nsstr, sizeof(nsstr), ", NSID:%u", nsid);
2851 uint64_t capacity = le128_to_uint64(id_ctrl.tnvmcap);
2852 if (capacity)
2853 format_capacity(capstr, sizeof(capstr), capacity, ".");
2854
2855 auto idinfo = &dev_config::dev_idinfo;
2856 for (;;) {
2857 cfg.*idinfo = strprintf("%s, S/N:%s, FW:%s%s%s%s", model, serial, firmware,
2858 nsstr, (capstr[0] ? ", " : ""), capstr);
2859 if (!(nsstr[0] && id_ctrl.nn == 1))
2860 break; // No namespace id or device supports multiple namespaces
2861 // Keep version without namespace id for 'is_duplicate_dev_idinfo()'
2862 nsstr[0] = 0;
2863 idinfo = &dev_config::dev_idinfo_bc;
2864 }
2865
2866 cfg.id_is_unique = true; // TODO: Check serial?
2868 cfg.id_is_unique = false;
2869
2870 PrintOut(LOG_INFO, "Device: %s, %s\n", name, cfg.dev_idinfo.c_str());
2871
2872 // Check for duplicates
2873 if (prev_cfgs && is_duplicate_dev_idinfo(cfg, *prev_cfgs)) {
2874 CloseDevice(nvmedev, name);
2875 return 1;
2876 }
2877
2878 // Read SMART/Health log
2879 // TODO: Support per namespace SMART/Health log
2880 nvme_smart_log & smart_log = state.nvme_smartval;
2881 if (!nvme_read_smart_log(nvmedev, nvme_broadcast_nsid, smart_log)) {
2882 PrintOut(LOG_INFO, "Device: %s, failed to read NVMe SMART/Health Information\n", name);
2883 CloseDevice(nvmedev, name);
2884 return 2;
2885 }
2886
2887 // Check temperature sensor support
2888 if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) {
2889 if (!sg_get_unaligned_le16(smart_log.temperature)) {
2890 PrintOut(LOG_INFO, "Device: %s, no Temperature sensors, ignoring -W %d,%d,%d\n",
2891 name, cfg.tempdiff, cfg.tempinfo, cfg.tempcrit);
2892 cfg.tempdiff = cfg.tempinfo = cfg.tempcrit = 0;
2893 }
2894 }
2895
2896 // Init total error count
2897 cfg.nvme_err_log_max_entries = id_ctrl.elpe + 1; // 0's based value
2898 if (cfg.errorlog || cfg.xerrorlog) {
2899 if (!check_nvme_error_log(cfg, state, nvmedev)) {
2900 PrintOut(LOG_INFO, "Device: %s, Error Information unavailable, ignoring -l [x]error\n", name);
2901 cfg.errorlog = cfg.xerrorlog = false;
2902 }
2903 else
2905 }
2906
2907 // Check for self-test support
2908 state.not_cap_short = state.not_cap_long = !(id_ctrl.oacs & 0x0010);
2909 state.selflogcount = 0; state.selfloghour = 0;
2910 if (cfg.selftest || cfg.selfteststs || !cfg.test_regex.empty()) {
2911 nvme_self_test_log self_test_log;
2912 if ( !state.not_cap_short
2913 && !nvme_read_self_test_log(nvmedev, nvme_broadcast_nsid, self_test_log)) {
2914 PrintOut(LOG_INFO, "Device: %s, Read NVMe Self-test Log failed: %s\n", name,
2915 nvmedev->get_errmsg());
2916 state.not_cap_short = state.not_cap_long = true;
2917 }
2918 if (state.not_cap_short) {
2919 PrintOut(LOG_INFO, "Device: %s, does not support NVMe Self-tests, ignoring%s%s%s%s\n", name,
2920 (cfg.selftest ? " -l selftest" : ""),
2921 (cfg.selfteststs ? " -l selfteststs" : ""),
2922 (!cfg.test_regex.empty() ? " -s " : ""), cfg.test_regex.get_pattern());
2923 cfg.selftest = cfg.selfteststs = false; cfg.test_regex = {};
2924 }
2925 }
2926
2927 // If no supported tests selected, return
2928 if (!( cfg.smartcheck_nvme
2929 || cfg.prefail || cfg.usage || cfg.usagefailed
2930 || cfg.errorlog || cfg.xerrorlog
2931 || cfg.selftest || cfg.selfteststs || !cfg.test_regex.empty()
2932 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit )) {
2933 CloseDevice(nvmedev, name);
2934 return 3;
2935 }
2936
2937 // Tell user we are registering device
2938 PrintOut(LOG_INFO,"Device: %s, is SMART capable. Adding to \"monitor\" list.\n", name);
2939
2940 // Disable ATA specific self-tests
2941 state.not_cap_conveyance = state.not_cap_offline = state.not_cap_selective = true;
2942
2943 // Make sure that init_standby_check() ignores NVMe devices
2944 // TODO: Implement '-l selfteststs,ns' for NVMe
2945 cfg.offlinests_ns = cfg.selfteststs_ns = false;
2946
2947 CloseDevice(nvmedev, name);
2948
2949 if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
2950 // Build file name for state file
2951 std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
2952 std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
2953 nsstr[0] = 0;
2955 snprintf(nsstr, sizeof(nsstr), "-n%u", nsid);
2956 if (!state_path_prefix.empty()) {
2957 cfg.state_file = strprintf("%s%s-%s%s.nvme.state", state_path_prefix.c_str(), model, serial, nsstr);
2958 // Read previous state
2959 if (read_dev_state(cfg.state_file.c_str(), state))
2960 PrintOut(LOG_INFO, "Device: %s, state read from %s\n", name, cfg.state_file.c_str());
2961 }
2962 if (!attrlog_path_prefix.empty())
2963 cfg.attrlog_file = strprintf("%s%s-%s%s.nvme.csv", attrlog_path_prefix.c_str(), model, serial, nsstr);
2964 }
2965
2966 finish_device_scan(cfg, state);
2967
2968 return 0;
2969}
2970
2971// Open device for next check, return false on error
2972static bool open_device(const dev_config & cfg, dev_state & state, smart_device * device,
2973 const char * type)
2974{
2975 const char * name = cfg.name.c_str();
2976
2977 // If user has asked, test the email warning system
2978 if (cfg.emailtest)
2979 MailWarning(cfg, state, 0, "TEST EMAIL from smartd for device: %s", name);
2980
2981 // User may have requested (with the -n Directive) to leave the disk
2982 // alone if it is in idle or standby mode. In this case check the
2983 // power mode first before opening the device for full access,
2984 // and exit without check if disk is reported in standby.
2985 if (device->is_ata() && cfg.powermode && !state.powermodefail && !state.removed) {
2986 // Note that 'is_powered_down()' handles opening the device itself, and
2987 // can be used before calling 'open()' (that's the whole point of 'is_powered_down()'!).
2988 if (device->is_powered_down())
2989 {
2990 // skip at most powerskipmax checks
2991 if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) {
2992 // report first only except if state has changed, avoid waking up system disk
2993 if ((!state.powerskipcnt || state.lastpowermodeskipped != -1) && !cfg.powerquiet) {
2994 PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, "STANDBY (OS)");
2995 state.lastpowermodeskipped = -1;
2996 }
2997 state.powerskipcnt++;
2998 return false;
2999 }
3000 }
3001 }
3002
3003 // if we can't open device, fail gracefully rather than hard --
3004 // perhaps the next time around we'll be able to open it
3005 if (!device->open()) {
3006 // For removable devices, print error message only once and suppress email
3007 if (!cfg.removable) {
3008 PrintOut(LOG_INFO, "Device: %s, open() of %s device failed: %s\n", name, type, device->get_errmsg());
3009 MailWarning(cfg, state, 9, "Device: %s, unable to open %s device", name, type);
3010 }
3011 else if (!state.removed) {
3012 PrintOut(LOG_INFO, "Device: %s, removed %s device: %s\n", name, type, device->get_errmsg());
3013 state.removed = true;
3014 }
3015 else if (debugmode)
3016 PrintOut(LOG_INFO, "Device: %s, %s device still removed: %s\n", name, type, device->get_errmsg());
3017 return false;
3018 }
3019
3020 if (debugmode)
3021 PrintOut(LOG_INFO,"Device: %s, opened %s device\n", name, type);
3022
3023 if (!cfg.removable)
3024 reset_warning_mail(cfg, state, 9, "open of %s device worked again", type);
3025 else if (state.removed) {
3026 PrintOut(LOG_INFO, "Device: %s, reconnected %s device\n", name, type);
3027 state.removed = false;
3028 }
3029
3030 return true;
3031}
3032
3033// If the self-test log has got more self-test errors (or more recent
3034// self-test errors) recorded, then notify user.
3035static void report_self_test_log_changes(const dev_config & cfg, dev_state & state,
3036 int errcnt, uint64_t hour)
3037{
3038 const char * name = cfg.name.c_str();
3039
3040 if (errcnt < 0)
3041 // command failed
3042 // TODO: Move this to ATA/SCSICheckDevice()
3043 MailWarning(cfg, state, 8, "Device: %s, Read SMART Self-Test Log Failed", name);
3044 else {
3045 reset_warning_mail(cfg, state, 8, "Read SMART Self-Test Log worked again");
3046
3047 if (state.selflogcount < errcnt) {
3048 // increase in error count
3049 PrintOut(LOG_CRIT, "Device: %s, Self-Test Log error count increased from %d to %d\n",
3050 name, state.selflogcount, errcnt);
3051 MailWarning(cfg, state, 3, "Device: %s, Self-Test Log error count increased from %d to %d",
3052 name, state.selflogcount, errcnt);
3053 state.must_write = true;
3054 }
3055 else if (errcnt > 0 && state.selfloghour != hour) {
3056 // more recent error
3057 // ATA: a 'more recent' error might actually be a smaller hour number,
3058 // if the hour number has wrapped.
3059 // There's still a bug here. You might just happen to run a new test
3060 // exactly 32768 hours after the previous failure, and have run exactly
3061 // 20 tests between the two, in which case smartd will miss the
3062 // new failure.
3063 PrintOut(LOG_CRIT, "Device: %s, new Self-Test Log error at hour timestamp %" PRIu64 "\n",
3064 name, hour);
3065 MailWarning(cfg, state, 3, "Device: %s, new Self-Test Log error at hour timestamp %" PRIu64 "\n",
3066 name, hour);
3067 state.must_write = true;
3068 }
3069
3070 // Print info if error entries have disappeared
3071 // or newer successful extended self-test exists
3072 if (state.selflogcount > errcnt) {
3073 PrintOut(LOG_INFO, "Device: %s, Self-Test Log error count decreased from %d to %d\n",
3074 name, state.selflogcount, errcnt);
3075 if (errcnt == 0)
3076 reset_warning_mail(cfg, state, 3, "Self-Test Log does no longer report errors");
3077 }
3078
3079 state.selflogcount = errcnt;
3080 state.selfloghour = hour;
3081 }
3082 return;
3083}
3084
3085// Test types, ordered by priority.
3086static const char test_type_chars[] = "LncrSCO";
3087static const unsigned num_test_types = sizeof(test_type_chars)-1;
3088
3089// returns test type if time to do test of type testtype,
3090// 0 if not time to do test.
3091static char next_scheduled_test(const dev_config & cfg, dev_state & state, time_t usetime = 0)
3092{
3093 // check that self-testing has been requested
3094 if (cfg.test_regex.empty())
3095 return 0;
3096
3097 // Exit if drive not capable of any test
3098 if ( state.not_cap_long && state.not_cap_short
3099 && state.not_cap_conveyance && state.not_cap_offline && state.not_cap_selective)
3100 return 0;
3101
3102 // since we are about to call localtime(), be sure glibc is informed
3103 // of any timezone changes we make.
3104 if (!usetime)
3106
3107 // Is it time for next check?
3108 time_t now = (!usetime ? time(nullptr) : usetime);
3109 if (now < state.scheduled_test_next_check) {
3110 if (state.scheduled_test_next_check <= now + 3600)
3111 return 0; // Next check within one hour
3112 // More than one hour, assume system clock time adjusted to the past
3113 state.scheduled_test_next_check = now;
3114 }
3115 else if (state.scheduled_test_next_check + (3600L*24*90) < now) {
3116 // Limit time check interval to 90 days
3117 state.scheduled_test_next_check = now - (3600L*24*90);
3118 }
3119
3120 // Find ':NNN[-LLL]' in regex for possible offsets and limits
3121 const unsigned max_offsets = 1 + num_test_types;
3122 unsigned offsets[max_offsets] = {0, }, limits[max_offsets] = {0, };
3123 unsigned num_offsets = 1; // offsets/limits[0] == 0 always
3124 for (const char * p = cfg.test_regex.get_pattern(); num_offsets < max_offsets; ) {
3125 const char * q = strchr(p, ':');
3126 if (!q)
3127 break;
3128 p = q + 1;
3129 unsigned offset = 0, limit = 0; int n1 = -1, n2 = -1, n3 = -1;
3130 sscanf(p, "%u%n-%n%u%n", &offset, &n1, &n2, &limit, &n3);
3131 if (!(n1 == 3 && (n2 < 0 || (n3 == 3+1+3 && limit > 0))))
3132 continue;
3133 offsets[num_offsets] = offset; limits[num_offsets] = limit;
3134 num_offsets++;
3135 p += (n3 > 0 ? n3 : n1);
3136 }
3137
3138 // Check interval [state.scheduled_test_next_check, now] for scheduled tests
3139 char testtype = 0;
3140 time_t testtime = 0;
3141 int maxtest = num_test_types-1;
3142
3143 for (time_t t = state.scheduled_test_next_check; ; ) {
3144 // Check offset 0 and then all offsets for ':NNN' found above
3145 for (unsigned i = 0; i < num_offsets; i++) {
3146 unsigned offset = offsets[i], limit = limits[i];
3147 unsigned delay = cfg.test_offset_factor * offset;
3148 if (0 < limit && limit < delay)
3149 delay %= limit + 1;
3150 struct tm tmbuf, * tms = time_to_tm_local(&tmbuf, t - (delay * 3600));
3151
3152 // tm_wday is 0 (Sunday) to 6 (Saturday). We use 1 (Monday) to 7 (Sunday).
3153 int weekday = (tms->tm_wday ? tms->tm_wday : 7);
3154 for (int j = 0; j <= maxtest; j++) {
3155 // Skip if drive not capable of this test
3156 switch (test_type_chars[j]) {
3157 case 'L': if (state.not_cap_long) continue; break;
3158 case 'S': if (state.not_cap_short) continue; break;
3159 case 'C': if (state.not_cap_conveyance) continue; break;
3160 case 'O': if (state.not_cap_offline) continue; break;
3161 case 'c': case 'n':
3162 case 'r': if (state.not_cap_selective) continue; break;
3163 default: continue;
3164 }
3165 // Try match of "T/MM/DD/d/HH[:NNN]"
3166 char pattern[64];
3167 snprintf(pattern, sizeof(pattern), "%c/%02d/%02d/%1d/%02d",
3168 test_type_chars[j], tms->tm_mon+1, tms->tm_mday, weekday, tms->tm_hour);
3169 if (i > 0) {
3170 const unsigned len = sizeof("S/01/01/1/01") - 1;
3171 snprintf(pattern + len, sizeof(pattern) - len, ":%03u", offset);
3172 if (limit > 0)
3173 snprintf(pattern + len + 4, sizeof(pattern) - len - 4, "-%03u", limit);
3174 }
3175 if (cfg.test_regex.full_match(pattern)) {
3176 // Test found
3177 testtype = pattern[0];
3178 testtime = t;
3179 // Limit further matches to higher priority self-tests
3180 maxtest = j-1;
3181 break;
3182 }
3183 }
3184 }
3185
3186 // Exit if no tests left or current time reached
3187 if (maxtest < 0)
3188 break;
3189 if (t >= now)
3190 break;
3191 // Check next hour
3192 if ((t += 3600) > now)
3193 t = now;
3194 }
3195
3196 // Do next check not before next hour.
3197 struct tm tmbuf, * tmnow = time_to_tm_local(&tmbuf, now);
3198 state.scheduled_test_next_check = now + (3600 - tmnow->tm_min*60 - tmnow->tm_sec);
3199
3200 if (testtype) {
3201 state.must_write = true;
3202 // Tell user if an old test was found.
3203 if (!usetime && (testtime / 3600) < (now / 3600)) {
3204 char datebuf[DATEANDEPOCHLEN]; dateandtimezoneepoch(datebuf, testtime);
3205 PrintOut(LOG_INFO, "Device: %s, old test of type %c not run at %s, starting now.\n",
3206 cfg.name.c_str(), testtype, datebuf);
3207 }
3208 }
3209
3210 return testtype;
3211}
3212
3213// Print a list of future tests.
3215{
3216 unsigned numdev = configs.size();
3217 if (!numdev)
3218 return;
3219 std::vector<int> testcnts(numdev * num_test_types, 0);
3220
3221 PrintOut(LOG_INFO, "\nNext scheduled self tests (at most 5 of each type per device):\n");
3222
3223 // FixGlibcTimeZoneBug(); // done in PrintOut()
3224 time_t now = time(nullptr);
3225 char datenow[DATEANDEPOCHLEN], date[DATEANDEPOCHLEN];
3226 dateandtimezoneepoch(datenow, now);
3227
3228 long seconds;
3229 for (seconds=checktime; seconds<3600L*24*90; seconds+=checktime) {
3230 // Check for each device whether a test will be run
3231 time_t testtime = now + seconds;
3232 for (unsigned i = 0; i < numdev; i++) {
3233 const dev_config & cfg = configs.at(i);
3234 dev_state & state = states.at(i);
3235 const char * p;
3236 char testtype = next_scheduled_test(cfg, state, testtime);
3237 if (testtype && (p = strchr(test_type_chars, testtype))) {
3238 unsigned t = (p - test_type_chars);
3239 // Report at most 5 tests of each type
3240 if (++testcnts[i*num_test_types + t] <= 5) {
3241 dateandtimezoneepoch(date, testtime);
3242 PrintOut(LOG_INFO, "Device: %s, will do test %d of type %c at %s\n", cfg.name.c_str(),
3243 testcnts[i*num_test_types + t], testtype, date);
3244 }
3245 }
3246 }
3247 }
3248
3249 // Report totals
3250 dateandtimezoneepoch(date, now+seconds);
3251 PrintOut(LOG_INFO, "\nTotals [%s - %s]:\n", datenow, date);
3252 for (unsigned i = 0; i < numdev; i++) {
3253 const dev_config & cfg = configs.at(i);
3254 bool ata = devices.at(i)->is_ata();
3255 for (unsigned t = 0; t < num_test_types; t++) {
3256 int cnt = testcnts[i*num_test_types + t];
3257 if (cnt == 0 && !strchr((ata ? "LSCO" : "LS"), test_type_chars[t]))
3258 continue;
3259 PrintOut(LOG_INFO, "Device: %s, will do %3d test%s of type %c\n", cfg.name.c_str(),
3260 cnt, (cnt==1?"":"s"), test_type_chars[t]);
3261 }
3262 }
3263
3264}
3265
3266// Return zero on success, nonzero on failure. Perform offline (background)
3267// short or long (extended) self test on given scsi device.
3268static int DoSCSISelfTest(const dev_config & cfg, dev_state & state, scsi_device * device, char testtype)
3269{
3270 int retval = 0;
3271 const char *testname = nullptr;
3272 const char *name = cfg.name.c_str();
3273 int inProgress;
3274
3275 if (scsiSelfTestInProgress(device, &inProgress)) {
3276 PrintOut(LOG_CRIT, "Device: %s, does not support Self-Tests\n", name);
3277 state.not_cap_short = state.not_cap_long = true;
3278 return 1;
3279 }
3280
3281 if (1 == inProgress) {
3282 PrintOut(LOG_INFO, "Device: %s, skip since Self-Test already in "
3283 "progress.\n", name);
3284 return 1;
3285 }
3286
3287 switch (testtype) {
3288 case 'S':
3289 testname = "Short Self";
3290 retval = scsiSmartShortSelfTest(device);
3291 break;
3292 case 'L':
3293 testname = "Long Self";
3294 retval = scsiSmartExtendSelfTest(device);
3295 break;
3296 }
3297 // If we can't do the test, exit
3298 if (!testname) {
3299 PrintOut(LOG_CRIT, "Device: %s, not capable of %c Self-Test\n", name,
3300 testtype);
3301 return 1;
3302 }
3303 if (retval) {
3304 if ((SIMPLE_ERR_BAD_OPCODE == retval) ||
3305 (SIMPLE_ERR_BAD_FIELD == retval)) {
3306 PrintOut(LOG_CRIT, "Device: %s, not capable of %s-Test\n", name,
3307 testname);
3308 if ('L'==testtype)
3309 state.not_cap_long = true;
3310 else
3311 state.not_cap_short = true;
3312
3313 return 1;
3314 }
3315 PrintOut(LOG_CRIT, "Device: %s, execute %s-Test failed (err: %d)\n", name,
3316 testname, retval);
3317 return 1;
3318 }
3319
3320 PrintOut(LOG_INFO, "Device: %s, starting scheduled %s-Test.\n", name, testname);
3321
3322 return 0;
3323}
3324
3325// Do an offline immediate or self-test. Return zero on success,
3326// nonzero on failure.
3327static int DoATASelfTest(const dev_config & cfg, dev_state & state, ata_device * device, char testtype)
3328{
3329 const char *name = cfg.name.c_str();
3330
3331 // Read current smart data and check status/capability
3332 // TODO: Reuse smart data already read in ATACheckDevice()
3333 struct ata_smart_values data;
3334 if (ataReadSmartValues(device, &data) || !(data.offline_data_collection_capability)) {
3335 PrintOut(LOG_CRIT, "Device: %s, not capable of Offline or Self-Testing.\n", name);
3336 return 1;
3337 }
3338
3339 // Check for capability to do the test
3340 int dotest = -1, mode = 0;
3341 const char *testname = nullptr;
3342 switch (testtype) {
3343 case 'O':
3344 testname="Offline Immediate ";
3346 dotest=OFFLINE_FULL_SCAN;
3347 else
3348 state.not_cap_offline = true;
3349 break;
3350 case 'C':
3351 testname="Conveyance Self-";
3353 dotest=CONVEYANCE_SELF_TEST;
3354 else
3355 state.not_cap_conveyance = true;
3356 break;
3357 case 'S':
3358 testname="Short Self-";
3359 if (isSupportSelfTest(&data))
3360 dotest=SHORT_SELF_TEST;
3361 else
3362 state.not_cap_short = true;
3363 break;
3364 case 'L':
3365 testname="Long Self-";
3366 if (isSupportSelfTest(&data))
3367 dotest=EXTEND_SELF_TEST;
3368 else
3369 state.not_cap_long = true;
3370 break;
3371
3372 case 'c': case 'n': case 'r':
3373 testname = "Selective Self-";
3375 dotest = SELECTIVE_SELF_TEST;
3376 switch (testtype) {
3377 case 'c': mode = SEL_CONT; break;
3378 case 'n': mode = SEL_NEXT; break;
3379 case 'r': mode = SEL_REDO; break;
3380 }
3381 }
3382 else
3383 state.not_cap_selective = true;
3384 break;
3385 }
3386
3387 // If we can't do the test, exit
3388 if (dotest<0) {
3389 PrintOut(LOG_CRIT, "Device: %s, not capable of %sTest\n", name, testname);
3390 return 1;
3391 }
3392
3393 // If currently running a self-test, do not interrupt it to start another.
3394 if (15==(data.self_test_exec_status >> 4)) {
3395 if (cfg.firmwarebugs.is_set(BUG_SAMSUNG3) && data.self_test_exec_status == 0xf0) {
3396 PrintOut(LOG_INFO, "Device: %s, will not skip scheduled %sTest "
3397 "despite unclear Self-Test byte (SAMSUNG Firmware bug).\n", name, testname);
3398 } else {
3399 PrintOut(LOG_INFO, "Device: %s, skip scheduled %sTest; %1d0%% remaining of current Self-Test.\n",
3400 name, testname, (int)(data.self_test_exec_status & 0x0f));
3401 return 1;
3402 }
3403 }
3404
3405 if (dotest == SELECTIVE_SELF_TEST) {
3406 // Set test span
3407 ata_selective_selftest_args selargs, prev_args;
3408 selargs.num_spans = 1;
3409 selargs.span[0].mode = mode;
3410 prev_args.num_spans = 1;
3411 prev_args.span[0].start = state.selective_test_last_start;
3412 prev_args.span[0].end = state.selective_test_last_end;
3413 if (ataWriteSelectiveSelfTestLog(device, selargs, &data, state.num_sectors, &prev_args)) {
3414 PrintOut(LOG_CRIT, "Device: %s, prepare %sTest failed\n", name, testname);
3415 return 1;
3416 }
3417 uint64_t start = selargs.span[0].start, end = selargs.span[0].end;
3418 PrintOut(LOG_INFO, "Device: %s, %s test span at LBA %" PRIu64 " - %" PRIu64 " (%" PRIu64 " sectors, %u%% - %u%% of disk).\n",
3419 name, (selargs.span[0].mode == SEL_NEXT ? "next" : "redo"),
3420 start, end, end - start + 1,
3421 (unsigned)((100 * start + state.num_sectors/2) / state.num_sectors),
3422 (unsigned)((100 * end + state.num_sectors/2) / state.num_sectors));
3423 state.selective_test_last_start = start;
3424 state.selective_test_last_end = end;
3425 }
3426
3427 // execute the test, and return status
3428 int retval = smartcommandhandler(device, IMMEDIATE_OFFLINE, dotest, nullptr);
3429 if (retval) {
3430 PrintOut(LOG_CRIT, "Device: %s, execute %sTest failed.\n", name, testname);
3431 return retval;
3432 }
3433
3434 // Report recent test start to do_disable_standby_check()
3435 // and force log of next test status
3436 if (testtype == 'O')
3437 state.offline_started = true;
3438 else
3439 state.selftest_started = true;
3440
3441 PrintOut(LOG_INFO, "Device: %s, starting scheduled %sTest.\n", name, testname);
3442 return 0;
3443}
3444
3445// Check pending sector count attribute values (-C, -U directives).
3446static void check_pending(const dev_config & cfg, dev_state & state,
3447 unsigned char id, bool increase_only,
3448 const ata_smart_values & smartval,
3449 int mailtype, const char * msg)
3450{
3451 // Find attribute index
3452 int i = ata_find_attr_index(id, smartval);
3453 if (!(i >= 0 && ata_find_attr_index(id, state.smartval) == i))
3454 return;
3455
3456 // No report if no sectors pending.
3457 uint64_t rawval = ata_get_attr_raw_value(smartval.vendor_attributes[i], cfg.attribute_defs);
3458 if (rawval == 0) {
3459 reset_warning_mail(cfg, state, mailtype, "No more %s", msg);
3460 return;
3461 }
3462
3463 // If attribute is not reset, report only sector count increases.
3464 uint64_t prev_rawval = ata_get_attr_raw_value(state.smartval.vendor_attributes[i], cfg.attribute_defs);
3465 if (!(!increase_only || prev_rawval < rawval))
3466 return;
3467
3468 // Format message.
3469 std::string s = strprintf("Device: %s, %" PRId64 " %s", cfg.name.c_str(), rawval, msg);
3470 if (prev_rawval > 0 && rawval != prev_rawval)
3471 s += strprintf(" (changed %+" PRId64 ")", rawval - prev_rawval);
3472
3473 PrintOut(LOG_CRIT, "%s\n", s.c_str());
3474 MailWarning(cfg, state, mailtype, "%s", s.c_str());
3475 state.must_write = true;
3476}
3477
3478// Format Temperature value
3479static const char * fmt_temp(unsigned char x, char (& buf)[20])
3480{
3481 if (!x) // unset
3482 return "??";
3483 snprintf(buf, sizeof(buf), "%u", x);
3484 return buf;
3485}
3486
3487// Check Temperature limits
3488static void CheckTemperature(const dev_config & cfg, dev_state & state, unsigned char currtemp, unsigned char triptemp)
3489{
3490 if (!(0 < currtemp && currtemp < 255)) {
3491 PrintOut(LOG_INFO, "Device: %s, failed to read Temperature\n", cfg.name.c_str());
3492 return;
3493 }
3494
3495 // Update Max Temperature
3496 const char * minchg = "", * maxchg = "";
3497 if (currtemp > state.tempmax) {
3498 if (state.tempmax)
3499 maxchg = "!";
3500 state.tempmax = currtemp;
3501 state.must_write = true;
3502 }
3503
3504 char buf[20];
3505 if (!state.temperature) {
3506 // First check
3507 if (!state.tempmin || currtemp < state.tempmin)
3508 // Delay Min Temperature update by ~ 30 minutes.
3509 state.tempmin_delay = time(nullptr) + default_checktime - 60;
3510 PrintOut(LOG_INFO, "Device: %s, initial Temperature is %d Celsius (Min/Max %s/%u%s)\n",
3511 cfg.name.c_str(), (int)currtemp, fmt_temp(state.tempmin, buf), state.tempmax, maxchg);
3512 if (triptemp)
3513 PrintOut(LOG_INFO, " [trip Temperature is %d Celsius]\n", (int)triptemp);
3514 state.temperature = currtemp;
3515 }
3516 else {
3517 if (state.tempmin_delay) {
3518 // End Min Temperature update delay if ...
3519 if ( (state.tempmin && currtemp > state.tempmin) // current temp exceeds recorded min,
3520 || (state.tempmin_delay <= time(nullptr))) { // or delay time is over.
3521 state.tempmin_delay = 0;
3522 if (!state.tempmin)
3523 state.tempmin = 255;
3524 }
3525 }
3526
3527 // Update Min Temperature
3528 if (!state.tempmin_delay && currtemp < state.tempmin) {
3529 state.tempmin = currtemp;
3530 state.must_write = true;
3531 if (currtemp != state.temperature)
3532 minchg = "!";
3533 }
3534
3535 // Track changes
3536 if (cfg.tempdiff && (*minchg || *maxchg || abs((int)currtemp - (int)state.temperature) >= cfg.tempdiff)) {
3537 PrintOut(LOG_INFO, "Device: %s, Temperature changed %+d Celsius to %u Celsius (Min/Max %s%s/%u%s)\n",
3538 cfg.name.c_str(), (int)currtemp-(int)state.temperature, currtemp, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
3539 state.temperature = currtemp;
3540 }
3541 }
3542
3543 // Check limits
3544 if (cfg.tempcrit && currtemp >= cfg.tempcrit) {
3545 PrintOut(LOG_CRIT, "Device: %s, Temperature %u Celsius reached critical limit of %u Celsius (Min/Max %s%s/%u%s)\n",
3546 cfg.name.c_str(), currtemp, cfg.tempcrit, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
3547 MailWarning(cfg, state, 12, "Device: %s, Temperature %d Celsius reached critical limit of %u Celsius (Min/Max %s%s/%u%s)",
3548 cfg.name.c_str(), currtemp, cfg.tempcrit, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
3549 }
3550 else if (cfg.tempinfo && currtemp >= cfg.tempinfo) {
3551 PrintOut(LOG_INFO, "Device: %s, Temperature %u Celsius reached limit of %u Celsius (Min/Max %s%s/%u%s)\n",
3552 cfg.name.c_str(), currtemp, cfg.tempinfo, fmt_temp(state.tempmin, buf), minchg, state.tempmax, maxchg);
3553 }
3554 else if (cfg.tempcrit) {
3555 unsigned char limit = (cfg.tempinfo ? cfg.tempinfo : cfg.tempcrit-5);
3556 if (currtemp < limit)
3557 reset_warning_mail(cfg, state, 12, "Temperature %u Celsius dropped below %u Celsius", currtemp, limit);
3558 }
3559}
3560
3561// Check normalized and raw attribute values.
3562static void check_attribute(const dev_config & cfg, dev_state & state,
3563 const ata_smart_attribute & attr,
3564 const ata_smart_attribute & prev,
3565 int attridx,
3566 const ata_smart_threshold_entry * thresholds)
3567{
3568 // Check attribute and threshold
3569 ata_attr_state attrstate = ata_get_attr_state(attr, attridx, thresholds, cfg.attribute_defs);
3570 if (attrstate == ATTRSTATE_NON_EXISTING)
3571 return;
3572
3573 // If requested, check for usage attributes that have failed.
3574 if ( cfg.usagefailed && attrstate == ATTRSTATE_FAILED_NOW
3576 std::string attrname = ata_get_smart_attr_name(attr.id, cfg.attribute_defs, cfg.dev_rpm);
3577 PrintOut(LOG_CRIT, "Device: %s, Failed SMART usage Attribute: %d %s.\n", cfg.name.c_str(), attr.id, attrname.c_str());
3578 MailWarning(cfg, state, 2, "Device: %s, Failed SMART usage Attribute: %d %s.", cfg.name.c_str(), attr.id, attrname.c_str());
3579 state.must_write = true;
3580 }
3581
3582 // Return if we're not tracking this type of attribute
3583 bool prefail = !!ATTRIBUTE_FLAGS_PREFAILURE(attr.flags);
3584 if (!( ( prefail && cfg.prefail)
3585 || (!prefail && cfg.usage )))
3586 return;
3587
3588 // Return if '-I ID' was specified
3590 return;
3591
3592 // Issue warning if they don't have the same ID in all structures.
3593 if (attr.id != prev.id) {
3594 PrintOut(LOG_INFO,"Device: %s, same Attribute has different ID numbers: %d = %d\n",
3595 cfg.name.c_str(), attr.id, prev.id);
3596 return;
3597 }
3598
3599 // Compare normalized values if valid.
3600 bool valchanged = false;
3601 if (attrstate > ATTRSTATE_NO_NORMVAL) {
3602 if (attr.current != prev.current)
3603 valchanged = true;
3604 }
3605
3606 // Compare raw values if requested.
3607 bool rawchanged = false;
3608 if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW)) {
3611 rawchanged = true;
3612 }
3613
3614 // Return if no change
3615 if (!(valchanged || rawchanged))
3616 return;
3617
3618 // Format value strings
3619 std::string currstr, prevstr;
3620 if (attrstate == ATTRSTATE_NO_NORMVAL) {
3621 // Print raw values only
3622 currstr = strprintf("%s (Raw)",
3623 ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
3624 prevstr = strprintf("%s (Raw)",
3625 ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
3626 }
3627 else if (cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_PRINT)) {
3628 // Print normalized and raw values
3629 currstr = strprintf("%d [Raw %s]", attr.current,
3630 ata_format_attr_raw_value(attr, cfg.attribute_defs).c_str());
3631 prevstr = strprintf("%d [Raw %s]", prev.current,
3632 ata_format_attr_raw_value(prev, cfg.attribute_defs).c_str());
3633 }
3634 else {
3635 // Print normalized values only
3636 currstr = strprintf("%d", attr.current);
3637 prevstr = strprintf("%d", prev.current);
3638 }
3639
3640 // Format message
3641 std::string msg = strprintf("Device: %s, SMART %s Attribute: %d %s changed from %s to %s",
3642 cfg.name.c_str(), (prefail ? "Prefailure" : "Usage"), attr.id,
3643 ata_get_smart_attr_name(attr.id, cfg.attribute_defs, cfg.dev_rpm).c_str(),
3644 prevstr.c_str(), currstr.c_str());
3645
3646 // Report this change as critical ?
3647 if ( (valchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_AS_CRIT))
3648 || (rawchanged && cfg.monitor_attr_flags.is_set(attr.id, MONITOR_RAW_AS_CRIT))) {
3649 PrintOut(LOG_CRIT, "%s\n", msg.c_str());
3650 MailWarning(cfg, state, 2, "%s", msg.c_str());
3651 }
3652 else {
3653 PrintOut(LOG_INFO, "%s\n", msg.c_str());
3654 }
3655 state.must_write = true;
3656}
3657
3658
3659static int ATACheckDevice(const dev_config & cfg, dev_state & state, ata_device * atadev,
3660 bool firstpass, bool allow_selftests)
3661{
3662 if (!open_device(cfg, state, atadev, "ATA"))
3663 return 1;
3664
3665 const char * name = cfg.name.c_str();
3666
3667 // user may have requested (with the -n Directive) to leave the disk
3668 // alone if it is in idle or sleeping mode. In this case check the
3669 // power mode and exit without check if needed
3670 if (cfg.powermode && !state.powermodefail) {
3671 int dontcheck=0, powermode=ataCheckPowerMode(atadev);
3672 const char * mode = 0;
3673 if (0 <= powermode && powermode < 0xff) {
3674 // wait for possible spin up and check again
3675 int powermode2;
3676 sleep(5);
3677 powermode2 = ataCheckPowerMode(atadev);
3678 if (powermode2 > powermode)
3679 PrintOut(LOG_INFO, "Device: %s, CHECK POWER STATUS spins up disk (0x%02x -> 0x%02x)\n", name, powermode, powermode2);
3680 powermode = powermode2;
3681 }
3682
3683 switch (powermode){
3684 case -1:
3685 // SLEEP
3686 mode="SLEEP";
3687 if (cfg.powermode>=1)
3688 dontcheck=1;
3689 break;
3690 case 0x00:
3691 // STANDBY
3692 mode="STANDBY";
3693 if (cfg.powermode>=2)
3694 dontcheck=1;
3695 break;
3696 case 0x01:
3697 // STANDBY_Y
3698 mode="STANDBY_Y";
3699 if (cfg.powermode>=2)
3700 dontcheck=1;
3701 break;
3702 case 0x80:
3703 // IDLE
3704 mode="IDLE";
3705 if (cfg.powermode>=3)
3706 dontcheck=1;
3707 break;
3708 case 0x81:
3709 // IDLE_A
3710 mode="IDLE_A";
3711 if (cfg.powermode>=3)
3712 dontcheck=1;
3713 break;
3714 case 0x82:
3715 // IDLE_B
3716 mode="IDLE_B";
3717 if (cfg.powermode>=3)
3718 dontcheck=1;
3719 break;
3720 case 0x83:
3721 // IDLE_C
3722 mode="IDLE_C";
3723 if (cfg.powermode>=3)
3724 dontcheck=1;
3725 break;
3726 case 0xff:
3727 // ACTIVE/IDLE
3728 case 0x40:
3729 // ACTIVE
3730 case 0x41:
3731 // ACTIVE
3732 mode="ACTIVE or IDLE";
3733 break;
3734 default:
3735 // UNKNOWN
3736 PrintOut(LOG_CRIT, "Device: %s, CHECK POWER STATUS returned %d, not ATA compliant, ignoring -n Directive\n",
3737 name, powermode);
3738 state.powermodefail = true;
3739 break;
3740 }
3741
3742 // if we are going to skip a check, return now
3743 if (dontcheck){
3744 // skip at most powerskipmax checks
3745 if (!cfg.powerskipmax || state.powerskipcnt<cfg.powerskipmax) {
3746 CloseDevice(atadev, name);
3747 // report first only except if state has changed, avoid waking up system disk
3748 if ((!state.powerskipcnt || state.lastpowermodeskipped != powermode) && !cfg.powerquiet) {
3749 PrintOut(LOG_INFO, "Device: %s, is in %s mode, suspending checks\n", name, mode);
3750 state.lastpowermodeskipped = powermode;
3751 }
3752 state.powerskipcnt++;
3753 return 0;
3754 }
3755 else {
3756 PrintOut(LOG_INFO, "Device: %s, %s mode ignored due to reached limit of skipped checks (%d check%s skipped)\n",
3757 name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s"));
3758 }
3759 state.powerskipcnt = 0;
3760 state.tempmin_delay = time(nullptr) + default_checktime - 60; // Delay Min Temperature update
3761 }
3762 else if (state.powerskipcnt) {
3763 PrintOut(LOG_INFO, "Device: %s, is back in %s mode, resuming checks (%d check%s skipped)\n",
3764 name, mode, state.powerskipcnt, (state.powerskipcnt==1?"":"s"));
3765 state.powerskipcnt = 0;
3766 state.tempmin_delay = time(nullptr) + default_checktime - 60; // Delay Min Temperature update
3767 }
3768 }
3769
3770 // check smart status
3771 if (cfg.smartcheck) {
3772 int status=ataSmartStatus2(atadev);
3773 if (status==-1){
3774 PrintOut(LOG_INFO,"Device: %s, not capable of SMART self-check\n",name);
3775 MailWarning(cfg, state, 5, "Device: %s, not capable of SMART self-check", name);
3776 state.must_write = true;
3777 }
3778 else if (status==1){
3779 PrintOut(LOG_CRIT, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!\n", name);
3780 MailWarning(cfg, state, 1, "Device: %s, FAILED SMART self-check. BACK UP DATA NOW!", name);
3781 state.must_write = true;
3782 }
3783 }
3784
3785 // Check everything that depends upon SMART Data (eg, Attribute values)
3786 if ( cfg.usagefailed || cfg.prefail || cfg.usage
3787 || cfg.curr_pending_id || cfg.offl_pending_id
3788 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit
3789 || cfg.selftest || cfg.offlinests || cfg.selfteststs) {
3790
3791 // Read current attribute values.
3792 ata_smart_values curval;
3793 if (ataReadSmartValues(atadev, &curval)){
3794 PrintOut(LOG_CRIT, "Device: %s, failed to read SMART Attribute Data\n", name);
3795 MailWarning(cfg, state, 6, "Device: %s, failed to read SMART Attribute Data", name);
3796 state.must_write = true;
3797 }
3798 else {
3799 reset_warning_mail(cfg, state, 6, "read SMART Attribute Data worked again");
3800
3801 // look for current or offline pending sectors
3802 if (cfg.curr_pending_id)
3803 check_pending(cfg, state, cfg.curr_pending_id, cfg.curr_pending_incr, curval, 10,
3804 (!cfg.curr_pending_incr ? "Currently unreadable (pending) sectors"
3805 : "Total unreadable (pending) sectors" ));
3806
3807 if (cfg.offl_pending_id)
3808 check_pending(cfg, state, cfg.offl_pending_id, cfg.offl_pending_incr, curval, 11,
3809 (!cfg.offl_pending_incr ? "Offline uncorrectable sectors"
3810 : "Total offline uncorrectable sectors"));
3811
3812 // check temperature limits
3813 if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
3814 CheckTemperature(cfg, state, ata_return_temperature_value(&curval, cfg.attribute_defs), 0);
3815
3816 // look for failed usage attributes, or track usage or prefail attributes
3817 if (cfg.usagefailed || cfg.prefail || cfg.usage) {
3818 for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
3819 check_attribute(cfg, state,
3820 curval.vendor_attributes[i],
3821 state.smartval.vendor_attributes[i],
3822 i, state.smartthres.thres_entries);
3823 }
3824 }
3825
3826 // Log changes of offline data collection status
3827 if (cfg.offlinests) {
3830 || state.offline_started // test was started in previous call
3831 || (firstpass && (debugmode || (curval.offline_data_collection_status & 0x7d))))
3833 }
3834
3835 // Log changes of self-test execution status
3836 if (cfg.selfteststs) {
3838 || state.selftest_started // test was started in previous call
3839 || (firstpass && (debugmode || (curval.self_test_exec_status & 0xf0))))
3841 }
3842
3843 // Save the new values for the next time around
3844 state.smartval = curval;
3846 state.attrlog_valid = 1; // ATA attributes valid
3847 }
3848 }
3849 state.offline_started = state.selftest_started = false;
3850
3851 // check if number of selftest errors has increased (note: may also DECREASE)
3852 if (cfg.selftest) {
3853 unsigned hour = 0;
3854 int errcnt = check_ata_self_test_log(atadev, name, cfg.firmwarebugs, hour);
3855 report_self_test_log_changes(cfg, state, errcnt, hour);
3856 }
3857
3858 // check if number of ATA errors has increased
3859 if (cfg.errorlog || cfg.xerrorlog) {
3860
3861 int errcnt1 = -1, errcnt2 = -1;
3862 if (cfg.errorlog)
3863 errcnt1 = read_ata_error_count(atadev, name, cfg.firmwarebugs, false);
3864 if (cfg.xerrorlog)
3865 errcnt2 = read_ata_error_count(atadev, name, cfg.firmwarebugs, true);
3866
3867 // new number of errors is max of both logs
3868 int newc = (errcnt1 >= errcnt2 ? errcnt1 : errcnt2);
3869
3870 // did command fail?
3871 if (newc<0)
3872 // lack of PrintOut here is INTENTIONAL
3873 MailWarning(cfg, state, 7, "Device: %s, Read SMART Error Log Failed", name);
3874
3875 // has error count increased?
3876 int oldc = state.ataerrorcount;
3877 if (newc>oldc){
3878 PrintOut(LOG_CRIT, "Device: %s, ATA error count increased from %d to %d\n",
3879 name, oldc, newc);
3880 MailWarning(cfg, state, 4, "Device: %s, ATA error count increased from %d to %d",
3881 name, oldc, newc);
3882 state.must_write = true;
3883 }
3884
3885 if (newc>=0)
3886 state.ataerrorcount=newc;
3887 }
3888
3889 // if the user has asked, and device is capable (or we're not yet
3890 // sure) check whether a self test should be done now.
3891 if (allow_selftests && !cfg.test_regex.empty()) {
3892 char testtype = next_scheduled_test(cfg, state, false/*!scsi*/);
3893 if (testtype)
3894 DoATASelfTest(cfg, state, atadev, testtype);
3895 }
3896
3897 // Don't leave device open -- the OS/user may want to access it
3898 // before the next smartd cycle!
3899 CloseDevice(atadev, name);
3900 return 0;
3901}
3902
3903static int SCSICheckDevice(const dev_config & cfg, dev_state & state, scsi_device * scsidev, bool allow_selftests)
3904{
3905 if (!open_device(cfg, state, scsidev, "SCSI"))
3906 return 1;
3907
3908 const char * name = cfg.name.c_str();
3909
3910 uint8_t asc = 0, ascq = 0;
3911 uint8_t currenttemp = 0, triptemp = 0;
3912 if (!state.SuppressReport) {
3913 if (scsiCheckIE(scsidev, state.SmartPageSupported, state.TempPageSupported,
3914 &asc, &ascq, &currenttemp, &triptemp)) {
3915 PrintOut(LOG_INFO, "Device: %s, failed to read SMART values\n",
3916 name);
3917 MailWarning(cfg, state, 6, "Device: %s, failed to read SMART values", name);
3918 state.SuppressReport = 1;
3919 }
3920 }
3921 if (asc > 0) {
3922 char b[128];
3923 const char * cp = scsiGetIEString(asc, ascq, b, sizeof(b));
3924
3925 if (cp) {
3926 PrintOut(LOG_CRIT, "Device: %s, SMART Failure: %s\n", name, cp);
3927 MailWarning(cfg, state, 1,"Device: %s, SMART Failure: %s", name, cp);
3928 } else if (asc == 4 && ascq == 9) {
3929 PrintOut(LOG_INFO,"Device: %s, self-test in progress\n", name);
3930 } else if (debugmode)
3931 PrintOut(LOG_INFO,"Device: %s, non-SMART asc,ascq: %d,%d\n",
3932 name, (int)asc, (int)ascq);
3933 } else if (debugmode)
3934 PrintOut(LOG_INFO,"Device: %s, SMART health: passed\n", name);
3935
3936 // check temperature limits
3937 if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)
3938 CheckTemperature(cfg, state, currenttemp, triptemp);
3939
3940 // check if number of selftest errors has increased (note: may also DECREASE)
3941 if (cfg.selftest) {
3942 int retval = scsiCountFailedSelfTests(scsidev, 0);
3943 report_self_test_log_changes(cfg, state, (retval >= 0 ? (retval & 0xff) : -1), retval >> 8);
3944 }
3945
3946 if (allow_selftests && !cfg.test_regex.empty()) {
3947 char testtype = next_scheduled_test(cfg, state);
3948 if (testtype)
3949 DoSCSISelfTest(cfg, state, scsidev, testtype);
3950 }
3951
3952 if (!cfg.attrlog_file.empty()){
3953 state.scsi_error_counters[0] = {};
3954 state.scsi_error_counters[1] = {};
3955 state.scsi_error_counters[2] = {};
3956 state.scsi_nonmedium_error = {};
3957 bool found = false;
3958
3959 // saving error counters to state
3960 uint8_t tBuf[252];
3961 if (state.ReadECounterPageSupported && (0 == scsiLogSense(scsidev,
3962 READ_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
3965 state.scsi_error_counters[0].found=1;
3966 found = true;
3967 }
3968 if (state.WriteECounterPageSupported && (0 == scsiLogSense(scsidev,
3969 WRITE_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
3972 state.scsi_error_counters[1].found=1;
3973 found = true;
3974 }
3975 if (state.VerifyECounterPageSupported && (0 == scsiLogSense(scsidev,
3976 VERIFY_ERROR_COUNTER_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
3979 state.scsi_error_counters[2].found=1;
3980 found = true;
3981 }
3982 if (state.NonMediumErrorPageSupported && (0 == scsiLogSense(scsidev,
3983 NON_MEDIUM_ERROR_LPAGE, 0, tBuf, sizeof(tBuf), 0))) {
3987 found = true;
3988 }
3989 // store temperature if not done by CheckTemperature() above
3990 if (!(cfg.tempdiff || cfg.tempinfo || cfg.tempcrit))
3991 state.temperature = currenttemp;
3992
3993 if (found || state.temperature)
3994 state.attrlog_valid = 2; // SCSI attributes valid
3995 }
3996
3997 CloseDevice(scsidev, name);
3998 return 0;
3999}
4000
4001// Log changes of a NVMe SMART/Health value
4002static void log_nvme_smart_change(const dev_config & cfg, dev_state & state,
4003 const char * valname, uint64_t oldval, uint64_t newval,
4004 bool critical, bool info = true)
4005{
4006 if (!(newval != oldval && (critical || info)))
4007 return;
4008
4009 std::string msg = strprintf("Device: %s, SMART/Health value: %s changed "
4010 "from %" PRIu64 " to %" PRIu64,
4011 cfg.name.c_str(), valname, oldval, newval);
4012 if (!critical)
4013 PrintOut(LOG_INFO, "%s\n", msg.c_str());
4014 else {
4015 PrintOut(LOG_CRIT, "%s\n", msg.c_str());
4016 MailWarning(cfg, state, 2, "%s", msg.c_str());
4017 }
4018 state.must_write = true;
4019}
4020
4021// Log NVMe self-test execution status changes
4022static void log_nvme_self_test_exec_status(const char * name, dev_state & state, bool firstpass,
4023 const nvme_self_test_log & self_test_log)
4024{
4025 uint8_t curr_op = self_test_log.current_operation & 0xf;
4026 uint8_t curr_compl = self_test_log.current_completion & 0x7f;
4027
4028 // Return if no changes and log not forced
4029 if (!( curr_op != state.selftest_op
4030 || curr_compl != state.selftest_compl
4031 || state.selftest_started // test was started in previous call
4032 || (firstpass && (debugmode || curr_op))))
4033 return;
4034
4035 state.selftest_op = curr_op;
4036 state.selftest_compl = curr_compl;
4037
4038 const nvme_self_test_result & r = self_test_log.results[0];
4039 uint8_t op0 = r.self_test_status >> 4, res0 = r.self_test_status & 0xf;
4040
4041 uint8_t op = (curr_op ? curr_op : op0);
4042 const char * t; char tb[32];
4043 switch (op) {
4044 case 0x0: t = ""; break;
4045 case 0x1: t = "short"; break;
4046 case 0x2: t = "extended"; break;
4047 case 0xe: t = "vendor specific"; break;
4048 default: snprintf(tb, sizeof(tb), "unknown (0x%x)", op);
4049 t = tb; break;
4050 }
4051
4052 if (curr_op) {
4053 PrintOut(LOG_INFO, "Device %s, %s self-test in progress, %d%% remaining\n",
4054 name, t, 100 - curr_compl);
4055 }
4056 else if (!op0 || res0 == 0xf) { // First entry unused
4057 PrintOut(LOG_INFO, "Device %s, no self-test has ever been run\n", name);
4058 }
4059 else {
4060 // Report last test result from first log entry
4061 const char * m; char mb[48];
4062 switch (res0) {
4063 case 0x0: m = "completed without error"; break;
4064 case 0x1: m = "was aborted by a self-test command"; break;
4065 case 0x2: m = "was aborted by a controller reset"; break;
4066 case 0x3: m = "was aborted due to a namespace removal"; break;
4067 case 0x4: m = "was aborted by a format NVM command"; break;
4068 case 0x5: m = "completed with error (fatal or unknown error)"; break;
4069 case 0x6: m = "completed with error (unknown failed segment)"; break;
4070 case 0x7: m = "completed with error (failed segments)"; break;
4071 case 0x8: m = "was aborted (unknown reason)"; break;
4072 case 0x9: m = "was aborted due to a sanitize operation"; break;
4073 default: snprintf(mb, sizeof(mb), "returned an unknown result (0x%x)", res0);
4074 m = mb; break;
4075 }
4076
4077 char ns[32] = "";
4078 if (r.valid & 0x01)
4079 snprintf(ns, sizeof(ns), " of NSID 0x%x", r.nsid);
4080
4081 PrintOut((0x5 <= res0 && res0 <= 0x7 ? LOG_CRIT : LOG_INFO),
4082 "Device %s, previous %s self-test%s %s\n", name, t, ns, m);
4083 }
4084}
4085
4086// Count error entries in NVMe self-test log, set HOUR to power on hours of most
4087// recent error. Return the error count.
4088static int check_nvme_self_test_log(uint32_t nsid, const nvme_self_test_log & self_test_log,
4089 uint64_t & hour)
4090{
4091 hour = 0;
4092 int errcnt = 0;
4093
4094 for (unsigned i = 0; i < 20; i++) {
4095 const nvme_self_test_result & r = self_test_log.results[i];
4096 uint8_t op = r.self_test_status >> 4;
4097 uint8_t res = r.self_test_status & 0xf;
4098 if (!op || res == 0xf)
4099 continue; // Unused entry
4100
4101 if (!( nsid == nvme_broadcast_nsid
4102 || !(r.valid & 0x01) /* No NSID */
4103 || r.nsid == nvme_broadcast_nsid || r.nsid == nsid))
4104 continue; // Different individual namespace
4105
4106 if (op == 0x2 /* Extended */ && !res /* Completed without error */)
4107 break; // Stop count at first successful extended test
4108
4109 if (!(0x5 <= res && res <= 0x7))
4110 continue; // No error or aborted
4111
4112 // Error found
4113 if (++errcnt != 1)
4114 continue; // Not most recent error
4115
4116 // Keep track of time of most recent error
4118 }
4119
4120 return errcnt;
4121}
4122
4123static int start_nvme_self_test(const dev_config & cfg, dev_state & state, nvme_device * device,
4124 char testtype, const nvme_self_test_log & self_test_log)
4125{
4126 const char *name = cfg.name.c_str();
4127 unsigned nsid = device->get_nsid();
4128
4129 const char *testname; uint8_t stc;
4130 switch (testtype) {
4131 case 'S': testname = "Short"; stc = 1; break;
4132 case 'L': testname = "Extended"; stc = 2; break;
4133 default: // Should not happen
4134 PrintOut(LOG_INFO, "Device: %s, not capable of %c Self-Test\n", name, testtype);
4135 return 1;
4136 }
4137
4138 // If currently running a self-test, do not try to start another.
4139 if (self_test_log.current_operation & 0xf) {
4140 PrintOut(LOG_INFO, "Device: %s, skip scheduled %s Self-Test (NSID 0x%x); %d%% remaining of current Self-Test.\n",
4141 name, testname, nsid, 100 - (self_test_log.current_completion & 0x7f));
4142 return 1;
4143 }
4144
4145 if (!nvme_self_test(device, stc, nsid)) {
4146 PrintOut(LOG_CRIT, "Device: %s, execute %s Self-Test failed (NSID 0x%x): %s.\n",
4147 name, testname, nsid, device->get_errmsg());
4148 return 1;
4149 }
4150
4151 // Report recent test start to do_disable_standby_check()
4152 // and force log of next test status
4153 // TODO: Add NVMe support to do_disable_standby_check()
4154 state.selftest_started = true;
4155
4156 PrintOut(LOG_INFO, "Device: %s, starting scheduled %s Self-Test (NSID 0x%x).\n",
4157 name, testname, nsid);
4158 return 0;
4159}
4160
4161static int NVMeCheckDevice(const dev_config & cfg, dev_state & state, nvme_device * nvmedev, bool firstpass, bool allow_selftests)
4162{
4163 if (!open_device(cfg, state, nvmedev, "NVMe"))
4164 return 1;
4165
4166 const char * name = cfg.name.c_str();
4167
4168 // Read SMART/Health log
4169 // TODO: Support per namespace SMART/Health log
4170 nvme_smart_log smart_log;
4171 if (!nvme_read_smart_log(nvmedev, nvme_broadcast_nsid, smart_log)) {
4172 CloseDevice(nvmedev, name);
4173 PrintOut(LOG_INFO, "Device: %s, failed to read NVMe SMART/Health Information\n", name);
4174 MailWarning(cfg, state, 6, "Device: %s, failed to read NVMe SMART/Health Information", name);
4175 state.must_write = true;
4176 return 0;
4177 }
4178
4179 // Check Critical Warning bits
4180 uint8_t w = smart_log.critical_warning, wm = w & cfg.smartcheck_nvme;
4181 if (wm) {
4182 std::string msg;
4183 static const char * const wnames[8] = {
4184 "LowSpare", "Temperature", "Reliability", "R/O",
4185 "VolMemBackup", "PersistMem", "Bit_6", "Bit_7"
4186 };
4187
4188 for (unsigned b = 0, cnt = 0; b < 8 ; b++) {
4189 uint8_t mask = 1 << b;
4190 if (!(w & mask))
4191 continue;
4192 if (cnt)
4193 msg += ", ";
4194 if (++cnt > 3) {
4195 msg += "..."; break;
4196 }
4197 if (!(wm & mask))
4198 msg += '[';
4199 msg += wnames[b];
4200 if (!(wm & mask))
4201 msg += ']';
4202 }
4203
4204 PrintOut(LOG_CRIT, "Device: %s, Critical Warning (0x%02x): %s\n", name, w, msg.c_str());
4205 MailWarning(cfg, state, 1, "Device: %s, Critical Warning (0x%02x): %s", name, w, msg.c_str());
4206 state.must_write = true;
4207 }
4208
4209 // Check some SMART/Health values
4210 // Names similar to smartctl plaintext output
4211 if (cfg.prefail) {
4212 log_nvme_smart_change(cfg, state, "Available Spare",
4213 state.nvme_smartval.avail_spare, smart_log.avail_spare,
4214 ( smart_log.avail_spare < smart_log.spare_thresh
4215 && smart_log.spare_thresh <= 100 /* 101-255: "reserved" */));
4216 }
4217
4218 if (cfg.usage || cfg.usagefailed) {
4219 log_nvme_smart_change(cfg, state, "Percentage Used",
4220 state.nvme_smartval.percent_used, smart_log.percent_used,
4221 (cfg.usagefailed && smart_log.percent_used > 95), cfg.usage);
4222
4223 uint64_t old_me = le128_to_uint64(state.nvme_smartval.media_errors);
4224 uint64_t new_me = le128_to_uint64(smart_log.media_errors);
4225 log_nvme_smart_change(cfg, state, "Media and Data Integrity Errors",
4226 old_me, new_me, (cfg.usagefailed && new_me > old_me), cfg.usage);
4227 }
4228
4229 // Check temperature limits
4230 if (cfg.tempdiff || cfg.tempinfo || cfg.tempcrit) {
4231 uint16_t k = sg_get_unaligned_le16(smart_log.temperature);
4232 // Convert Kelvin to positive Celsius (TODO: Allow negative temperatures)
4233 int c = (int)k - 273;
4234 if (c < 1)
4235 c = 1;
4236 else if (c > 0xff)
4237 c = 0xff;
4238 CheckTemperature(cfg, state, c, 0);
4239 }
4240
4241 // Check for test schedule
4242 char testtype = (allow_selftests && !cfg.test_regex.empty()
4243 ? next_scheduled_test(cfg, state) : 0);
4244
4245 // Read the self-test log if required
4246 nvme_self_test_log self_test_log{};
4247 if (testtype || cfg.selftest || cfg.selfteststs) {
4248 if (!nvme_read_self_test_log(nvmedev, nvme_broadcast_nsid, self_test_log)) {
4249 PrintOut(LOG_CRIT, "Device: %s, Read Self-test Log failed: %s\n",
4250 name, nvmedev->get_errmsg());
4251 MailWarning(cfg, state, 8, "Device: %s, Read Self-test Log failed: %s\n",
4252 name, nvmedev->get_errmsg());
4253 testtype = 0;
4254 }
4255 else {
4256 reset_warning_mail(cfg, state, 8, "Read Self-Test Log worked again");
4257
4258 // Log changes of self-test execution status
4259 if (cfg.selfteststs)
4260 log_nvme_self_test_exec_status(name, state, firstpass, self_test_log);
4261
4262 // Check if number of selftest errors has increased (note: may also DECREASE)
4263 if (cfg.selftest) {
4264 uint64_t hour = 0;
4265 int errcnt = check_nvme_self_test_log(nvmedev->get_nsid(), self_test_log, hour);
4266 report_self_test_log_changes(cfg, state, errcnt, hour);
4267 }
4268 }
4269 }
4270 state.selftest_started = false;
4271
4272 // Check if number of errors has increased
4273 if (cfg.errorlog || cfg.xerrorlog) {
4274 uint64_t newcnt = le128_to_uint64(smart_log.num_err_log_entries);
4275 if (newcnt > state.nvme_err_log_entries) {
4276 // Warn only if device related errors are found
4277 check_nvme_error_log(cfg, state, nvmedev, newcnt);
4278 }
4279 // else // TODO: Handle decrease of count?
4280 }
4281
4282 // Start self-test if scheduled
4283 if (testtype)
4284 start_nvme_self_test(cfg, state, nvmedev, testtype, self_test_log);
4285
4286 CloseDevice(nvmedev, name);
4287
4288 // Preserve new SMART/Health info for state file and attribute log
4289 state.nvme_smartval = smart_log;
4290 state.attrlog_valid = 3; // NVMe attributes valid
4291 return 0;
4292}
4293
4294// 0=not used, 1=not disabled, 2=disable rejected by OS, 3=disabled
4296
4298{
4299 // Check for '-l offlinests,ns' or '-l selfteststs,ns' directives
4300 bool sts1 = false, sts2 = false;
4301 for (const auto & cfg : configs) {
4302 if (cfg.offlinests_ns)
4303 sts1 = true;
4304 if (cfg.selfteststs_ns)
4305 sts2 = true;
4306 }
4307
4308 // Check for support of disable auto standby
4309 // Reenable standby if smartd.conf was reread
4310 if (sts1 || sts2 || standby_disable_state == 3) {
4311 if (!smi()->disable_system_auto_standby(false)) {
4312 if (standby_disable_state == 3)
4313 PrintOut(LOG_CRIT, "System auto standby enable failed: %s\n", smi()->get_errmsg());
4314 if (sts1 || sts2) {
4315 PrintOut(LOG_INFO, "Disable auto standby not supported, ignoring ',ns' from %s%s%s\n",
4316 (sts1 ? "-l offlinests,ns" : ""), (sts1 && sts2 ? " and " : ""), (sts2 ? "-l selfteststs,ns" : ""));
4317 sts1 = sts2 = false;
4318 }
4319 }
4320 }
4321
4322 standby_disable_state = (sts1 || sts2 ? 1 : 0);
4323}
4324
4325static void do_disable_standby_check(const dev_config_vector & configs, const dev_state_vector & states)
4326{
4328 return;
4329
4330 // Check for just started or still running self-tests
4331 bool running = false;
4332 for (unsigned i = 0; i < configs.size() && !running; i++) {
4333 const dev_config & cfg = configs.at(i); const dev_state & state = states.at(i);
4334
4335 if ( ( cfg.offlinests_ns
4336 && (state.offline_started ||
4338 || ( cfg.selfteststs_ns
4339 && (state.selftest_started ||
4341 running = true;
4342 // state.offline/selftest_started will be reset after next logging of test status
4343 }
4344
4345 // Disable/enable auto standby and log state changes
4346 if (!running) {
4347 if (standby_disable_state != 1) {
4348 if (!smi()->disable_system_auto_standby(false))
4349 PrintOut(LOG_CRIT, "Self-test(s) completed, system auto standby enable failed: %s\n",
4350 smi()->get_errmsg());
4351 else
4352 PrintOut(LOG_INFO, "Self-test(s) completed, system auto standby enabled\n");
4354 }
4355 }
4356 else if (!smi()->disable_system_auto_standby(true)) {
4357 if (standby_disable_state != 2) {
4358 PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disable rejected: %s\n",
4359 smi()->get_errmsg());
4361 }
4362 }
4363 else {
4364 if (standby_disable_state != 3) {
4365 PrintOut(LOG_INFO, "Self-test(s) in progress, system auto standby disabled\n");
4367 }
4368 }
4369}
4370
4371// Checks the SMART status of all ATA and SCSI devices
4372static void CheckDevicesOnce(const dev_config_vector & configs, dev_state_vector & states,
4373 smart_device_list & devices, bool firstpass, bool allow_selftests)
4374{
4375 for (unsigned i = 0; i < configs.size(); i++) {
4376 const dev_config & cfg = configs.at(i);
4377 dev_state & state = states.at(i);
4378 if (state.skip) {
4379 if (debugmode)
4380 PrintOut(LOG_INFO, "Device: %s, skipped (interval=%d)\n", cfg.name.c_str(),
4381 (cfg.checktime ? cfg.checktime : checktime));
4382 continue;
4383 }
4384
4385 smart_device * dev = devices.at(i);
4386 if (dev->is_ata())
4387 ATACheckDevice(cfg, state, dev->to_ata(), firstpass, allow_selftests);
4388 else if (dev->is_scsi())
4389 SCSICheckDevice(cfg, state, dev->to_scsi(), allow_selftests);
4390 else if (dev->is_nvme())
4391 NVMeCheckDevice(cfg, state, dev->to_nvme(), firstpass, allow_selftests);
4392
4393 // Prevent systemd unit startup timeout when checking many devices on startup
4395 }
4396
4397 do_disable_standby_check(configs, states);
4398}
4399
4400// Install all signal handlers
4402{
4403 // normal and abnormal exit
4406
4407 // in debug mode, <CONTROL-C> ==> HUP
4409
4410 // Catch HUP and USR1
4413#ifdef _WIN32
4414 set_signal_if_not_ignored(SIGUSR2, USR2handler);
4415#endif
4416}
4417
4418#ifdef _WIN32
4419// Toggle debug mode implemented for native windows only
4420// (there is no easy way to reopen tty on *nix)
4421static void ToggleDebugMode()
4422{
4423 if (!debugmode) {
4424 PrintOut(LOG_INFO,"Signal USR2 - enabling debug mode\n");
4425 if (!daemon_enable_console("smartd [Debug]")) {
4426 debugmode = 1;
4427 daemon_signal(SIGINT, HUPhandler);
4428 PrintOut(LOG_INFO,"smartd debug mode enabled, PID=%d\n", getpid());
4429 }
4430 else
4431 PrintOut(LOG_INFO,"enable console failed\n");
4432 }
4433 else if (debugmode == 1) {
4434 daemon_disable_console();
4435 debugmode = 0;
4436 daemon_signal(SIGINT, sighandler);
4437 PrintOut(LOG_INFO,"Signal USR2 - debug mode disabled\n");
4438 }
4439 else
4440 PrintOut(LOG_INFO,"Signal USR2 - debug mode %d not changed\n", debugmode);
4441}
4442#endif
4443
4444static time_t calc_next_wakeuptime(time_t wakeuptime, time_t timenow, int ct)
4445{
4446 if (timenow < wakeuptime)
4447 return wakeuptime;
4448 return timenow + ct - (timenow - wakeuptime) % ct;
4449}
4450
4451static time_t dosleep(time_t wakeuptime, const dev_config_vector & configs,
4452 dev_state_vector & states, bool & sigwakeup)
4453{
4454 // If past wake-up-time, compute next wake-up-time
4455 time_t timenow = time(nullptr);
4456 unsigned n = configs.size();
4457 int ct;
4458 if (!checktime_min) {
4459 // Same for all devices
4460 wakeuptime = calc_next_wakeuptime(wakeuptime, timenow, checktime);
4461 ct = checktime;
4462 }
4463 else {
4464 // Determine wakeuptime of next device(s)
4465 wakeuptime = 0;
4466 for (unsigned i = 0; i < n; i++) {
4467 const dev_config & cfg = configs.at(i);
4468 dev_state & state = states.at(i);
4469 if (!state.skip)
4470 state.wakeuptime = calc_next_wakeuptime((state.wakeuptime ? state.wakeuptime : timenow),
4471 timenow, (cfg.checktime ? cfg.checktime : checktime));
4472 if (!wakeuptime || state.wakeuptime < wakeuptime)
4473 wakeuptime = state.wakeuptime;
4474 }
4475 ct = checktime_min;
4476 }
4477
4478 notify_wait(wakeuptime, n);
4479
4480 // Sleep until we catch a signal or have completed sleeping
4481 bool no_skip = false;
4482 int addtime = 0;
4483 while (timenow < wakeuptime+addtime && !caughtsigUSR1 && !caughtsigHUP && !caughtsigEXIT) {
4484 // Restart if system clock has been adjusted to the past
4485 if (wakeuptime > timenow + ct) {
4486 PrintOut(LOG_INFO, "System clock time adjusted to the past. Resetting next wakeup time.\n");
4487 wakeuptime = timenow + ct;
4488 for (auto & state : states)
4489 state.wakeuptime = 0;
4490 no_skip = true;
4491 }
4492
4493 // Exit sleep when time interval has expired or a signal is received
4494 sleep(wakeuptime+addtime-timenow);
4495
4496#ifdef _WIN32
4497 // toggle debug mode?
4498 if (caughtsigUSR2) {
4499 ToggleDebugMode();
4500 caughtsigUSR2 = 0;
4501 }
4502#endif
4503
4504 timenow = time(nullptr);
4505
4506 // Actual sleep time too long?
4507 if (!addtime && timenow > wakeuptime+60) {
4508 if (debugmode)
4509 PrintOut(LOG_INFO, "Sleep time was %d seconds too long, assuming wakeup from standby mode.\n",
4510 (int)(timenow-wakeuptime));
4511 // Wait another 20 seconds to avoid I/O errors during disk spin-up
4512 addtime = timenow-wakeuptime+20;
4513 // Use next wake-up-time if close
4514 int nextcheck = ct - addtime % ct;
4515 if (nextcheck <= 20)
4516 addtime += nextcheck;
4517 }
4518 }
4519
4520 // if we caught a SIGUSR1 then print message and clear signal
4521 if (caughtsigUSR1){
4522 PrintOut(LOG_INFO,"Signal USR1 - checking devices now rather than in %d seconds.\n",
4523 wakeuptime-timenow>0?(int)(wakeuptime-timenow):0);
4524 caughtsigUSR1=0;
4525 sigwakeup = no_skip = true;
4526 }
4527
4528 // Check which devices must be skipped in this cycle
4529 if (checktime_min) {
4530 for (auto & state : states)
4531 state.skip = (!no_skip && timenow < state.wakeuptime);
4532 }
4533
4534 // return adjusted wakeuptime
4535 return wakeuptime;
4536}
4537
4538// Print out a list of valid arguments for the Directive d
4539static void printoutvaliddirectiveargs(int priority, char d)
4540{
4541 switch (d) {
4542 case 'n':
4543 PrintOut(priority, "never[,N][,q], sleep[,N][,q], standby[,N][,q], idle[,N][,q]");
4544 break;
4545 case 's':
4546 PrintOut(priority, "valid_regular_expression");
4547 break;
4548 case 'd':
4549 PrintOut(priority, "%s", smi()->get_valid_dev_types_str().c_str());
4550 break;
4551 case 'T':
4552 PrintOut(priority, "normal, permissive");
4553 break;
4554 case 'o':
4555 case 'S':
4556 PrintOut(priority, "on, off");
4557 break;
4558 case 'l':
4559 PrintOut(priority, "error, selftest");
4560 break;
4561 case 'M':
4562 PrintOut(priority, "\"once\", \"always\", \"daily\", \"diminishing\", \"test\", \"exec\"");
4563 break;
4564 case 'v':
4565 PrintOut(priority, "\n%s\n", create_vendor_attribute_arg_list().c_str());
4566 break;
4567 case 'P':
4568 PrintOut(priority, "use, ignore, show, showall");
4569 break;
4570 case 'F':
4571 PrintOut(priority, "%s", get_valid_firmwarebug_args());
4572 break;
4573 case 'e':
4574 PrintOut(priority, "aam,[N|off], apm,[N|off], lookahead,[on|off], dsn,[on|off] "
4575 "security-freeze, standby,[N|off], wcache,[on|off]");
4576 break;
4577 case 'c':
4578 PrintOut(priority, "i=N, interval=N");
4579 break;
4580 }
4581}
4582
4583// exits with an error message, or returns integer value of token
4584static int GetInteger(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile,
4585 int min, int max, char * suffix = 0)
4586{
4587 // make sure argument is there
4588 if (!arg) {
4589 PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes integer argument from %d to %d.\n",
4590 cfgfile, lineno, name, token, min, max);
4591 return -1;
4592 }
4593
4594 // get argument value (base 10), check that it's integer, and in-range
4595 char *endptr;
4596 int val = strtol(arg,&endptr,10);
4597
4598 // optional suffix present?
4599 if (suffix) {
4600 if (!strcmp(endptr, suffix))
4601 endptr += strlen(suffix);
4602 else
4603 *suffix = 0;
4604 }
4605
4606 if (!(!*endptr && min <= val && val <= max)) {
4607 PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs integer from %d to %d.\n",
4608 cfgfile, lineno, name, token, arg, min, max);
4609 return -1;
4610 }
4611
4612 // all is well; return value
4613 return val;
4614}
4615
4616
4617// Get 1-3 small integer(s) for '-W' directive
4618static int Get3Integers(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile,
4619 unsigned char *val1, unsigned char *val2, unsigned char *val3)
4620{
4621 unsigned v1 = 0, v2 = 0, v3 = 0;
4622 int n1 = -1, n2 = -1, n3 = -1, len;
4623 if (!arg) {
4624 PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s takes 1-3 integer argument(s) from 0 to 255.\n",
4625 cfgfile, lineno, name, token);
4626 return -1;
4627 }
4628
4629 len = strlen(arg);
4630 if (!( sscanf(arg, "%u%n,%u%n,%u%n", &v1, &n1, &v2, &n2, &v3, &n3) >= 1
4631 && (n1 == len || n2 == len || n3 == len) && v1 <= 255 && v2 <= 255 && v3 <= 255)) {
4632 PrintOut(LOG_CRIT,"File %s line %d (drive %s): Directive: %s has argument: %s; needs 1-3 integer(s) from 0 to 255.\n",
4633 cfgfile, lineno, name, token, arg);
4634 return -1;
4635 }
4636 *val1 = (unsigned char)v1; *val2 = (unsigned char)v2; *val3 = (unsigned char)v3;
4637 return 0;
4638}
4639
4640
4641#ifdef _WIN32
4642
4643// Concatenate strtok() results if quoted with "..."
4644static const char * strtok_dequote(const char * delimiters)
4645{
4646 const char * t = strtok(nullptr, delimiters);
4647 if (!t || t[0] != '"')
4648 return t;
4649
4650 static std::string token;
4651 token = t+1;
4652 for (;;) {
4653 t = strtok(nullptr, delimiters);
4654 if (!t || !*t)
4655 return "\"";
4656 token += ' ';
4657 int len = strlen(t);
4658 if (t[len-1] == '"') {
4659 token += std::string(t, len-1);
4660 break;
4661 }
4662 token += t;
4663 }
4664 return token.c_str();
4665}
4666
4667#endif // _WIN32
4668
4669
4670// This function returns 1 if it has correctly parsed one token (and
4671// any arguments), else zero if no tokens remain. It returns -1 if an
4672// error was encountered.
4673static int ParseToken(char * & token, dev_config & cfg, smart_devtype_list & scan_types)
4674{
4675 char sym;
4676 const char * name = cfg.name.c_str();
4677 int lineno=cfg.lineno;
4678 const char *delim = " \n\t";
4679 int badarg = 0;
4680 int missingarg = 0;
4681 const char *arg = 0;
4682
4683 // Get next token unless lookahead (from '-H') is available
4684 if (!token) {
4685 token = strtok(nullptr, delim);
4686 if (!token)
4687 return 0;
4688 }
4689
4690 // is the rest of the line a comment
4691 if (*token=='#')
4692 return 1;
4693
4694 // is the token not recognized?
4695 if (*token!='-' || strlen(token)!=2) {
4696 PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
4697 configfile, lineno, name, token);
4698 PrintOut(LOG_CRIT, "Run smartd -D to print a list of valid Directives.\n");
4699 return -1;
4700 }
4701
4702 // token we will be parsing:
4703 sym=token[1];
4704
4705 // parse the token and swallow its argument
4706 int val;
4707 char plus[] = "+", excl[] = "!";
4708
4709 switch (sym) {
4710 case 'C':
4711 // monitor current pending sector count (default 197)
4712 if ((val = GetInteger((arg = strtok(nullptr, delim)), name, token, lineno, configfile, 0, 255, plus)) < 0)
4713 return -1;
4714 cfg.curr_pending_id = (unsigned char)val;
4715 cfg.curr_pending_incr = (*plus == '+');
4716 cfg.curr_pending_set = true;
4717 break;
4718 case 'U':
4719 // monitor offline uncorrectable sectors (default 198)
4720 if ((val = GetInteger((arg = strtok(nullptr, delim)), name, token, lineno, configfile, 0, 255, plus)) < 0)
4721 return -1;
4722 cfg.offl_pending_id = (unsigned char)val;
4723 cfg.offl_pending_incr = (*plus == '+');
4724 cfg.offl_pending_set = true;
4725 break;
4726 case 'T':
4727 // Set tolerance level for SMART command failures
4728 if (!(arg = strtok(nullptr, delim))) {
4729 missingarg = 1;
4730 } else if (!strcmp(arg, "normal")) {
4731 // Normal mode: exit on failure of a mandatory S.M.A.R.T. command, but
4732 // not on failure of an optional S.M.A.R.T. command.
4733 // This is the default so we don't need to actually do anything here.
4734 cfg.permissive = false;
4735 } else if (!strcmp(arg, "permissive")) {
4736 // Permissive mode; ignore errors from Mandatory SMART commands
4737 cfg.permissive = true;
4738 } else {
4739 badarg = 1;
4740 }
4741 break;
4742 case 'd':
4743 // specify the device type
4744 if (!(arg = strtok(nullptr, delim))) {
4745 missingarg = 1;
4746 } else if (!strcmp(arg, "ignore")) {
4747 cfg.ignore = true;
4748 } else if (!strcmp(arg, "removable")) {
4749 cfg.removable = true;
4750 } else if (!strcmp(arg, "auto")) {
4751 cfg.dev_type = "";
4752 scan_types.clear();
4753 } else {
4754 cfg.dev_type = arg;
4755 scan_types.push_back(arg);
4756 }
4757 break;
4758 case 'F':
4759 // fix firmware bug
4760 if (!(arg = strtok(nullptr, delim)))
4761 missingarg = 1;
4762 else if (!parse_firmwarebug_def(arg, cfg.firmwarebugs))
4763 badarg = 1;
4764 break;
4765 case 'H':
4766 // check SMART status
4767 cfg.smartcheck = true;
4768 cfg.smartcheck_nvme = 0xff;
4769 // Lookahead for optional NVMe bitmask
4770 {
4771 char * next_token = strtok(nullptr, delim);
4772 if (!next_token)
4773 return 0;
4774 if (*next_token == '-') {
4775 // Continue with next directive
4776 token = next_token;
4777 return 1;
4778 }
4779 arg = next_token;
4780 unsigned u = ~0; int nc = -1;
4781 sscanf(arg, "0x%x%n", &u, &nc);
4782 if (nc == (int)strlen(arg) && u <= 0xff)
4783 cfg.smartcheck_nvme = (uint8_t)u;
4784 else
4785 badarg = 1;
4786 }
4787 break;
4788 case 'f':
4789 // check for failure of usage attributes
4790 cfg.usagefailed = true;
4791 break;
4792 case 't':
4793 // track changes in all vendor attributes
4794 cfg.prefail = true;
4795 cfg.usage = true;
4796 break;
4797 case 'p':
4798 // track changes in prefail vendor attributes
4799 cfg.prefail = true;
4800 break;
4801 case 'u':
4802 // track changes in usage vendor attributes
4803 cfg.usage = true;
4804 break;
4805 case 'l':
4806 // track changes in SMART logs
4807 if (!(arg = strtok(nullptr, delim))) {
4808 missingarg = 1;
4809 } else if (!strcmp(arg, "selftest")) {
4810 // track changes in self-test log
4811 cfg.selftest = true;
4812 } else if (!strcmp(arg, "error")) {
4813 // track changes in ATA error log
4814 cfg.errorlog = true;
4815 } else if (!strcmp(arg, "xerror")) {
4816 // track changes in Extended Comprehensive SMART error log
4817 cfg.xerrorlog = true;
4818 } else if (!strcmp(arg, "offlinests")) {
4819 // track changes in offline data collection status
4820 cfg.offlinests = true;
4821 } else if (!strcmp(arg, "offlinests,ns")) {
4822 // track changes in offline data collection status, disable auto standby
4823 cfg.offlinests = cfg.offlinests_ns = true;
4824 } else if (!strcmp(arg, "selfteststs")) {
4825 // track changes in self-test execution status
4826 cfg.selfteststs = true;
4827 } else if (!strcmp(arg, "selfteststs,ns")) {
4828 // track changes in self-test execution status, disable auto standby
4829 cfg.selfteststs = cfg.selfteststs_ns = true;
4830 } else if (!strncmp(arg, "scterc,", sizeof("scterc,")-1)) {
4831 // set SCT Error Recovery Control
4832 unsigned rt = ~0, wt = ~0; int nc = -1;
4833 sscanf(arg,"scterc,%u,%u%n", &rt, &wt, &nc);
4834 if (nc == (int)strlen(arg) && rt <= 999 && wt <= 999) {
4835 cfg.sct_erc_set = true;
4836 cfg.sct_erc_readtime = rt;
4837 cfg.sct_erc_writetime = wt;
4838 }
4839 else
4840 badarg = 1;
4841 } else {
4842 badarg = 1;
4843 }
4844 break;
4845 case 'a':
4846 // monitor everything
4847 cfg.smartcheck = true;
4848 cfg.smartcheck_nvme = 0xff;
4849 cfg.prefail = true;
4850 cfg.usagefailed = true;
4851 cfg.usage = true;
4852 cfg.selftest = true;
4853 cfg.errorlog = true;
4854 cfg.selfteststs = true;
4855 break;
4856 case 'o':
4857 // automatic offline testing enable/disable
4858 if (!(arg = strtok(nullptr, delim))) {
4859 missingarg = 1;
4860 } else if (!strcmp(arg, "on")) {
4861 cfg.autoofflinetest = 2;
4862 } else if (!strcmp(arg, "off")) {
4863 cfg.autoofflinetest = 1;
4864 } else {
4865 badarg = 1;
4866 }
4867 break;
4868 case 'n':
4869 // skip disk check if in idle or standby mode
4870 if (!(arg = strtok(nullptr, delim)))
4871 missingarg = 1;
4872 else {
4873 char *endptr = nullptr;
4874 char *next = strchr(const_cast<char*>(arg), ',');
4875
4876 cfg.powerquiet = false;
4877 cfg.powerskipmax = 0;
4878
4879 if (next)
4880 *next = '\0';
4881 if (!strcmp(arg, "never"))
4882 cfg.powermode = 0;
4883 else if (!strcmp(arg, "sleep"))
4884 cfg.powermode = 1;
4885 else if (!strcmp(arg, "standby"))
4886 cfg.powermode = 2;
4887 else if (!strcmp(arg, "idle"))
4888 cfg.powermode = 3;
4889 else
4890 badarg = 1;
4891
4892 // if optional arguments are present
4893 if (!badarg && next) {
4894 next++;
4895 cfg.powerskipmax = strtol(next, &endptr, 10);
4896 if (endptr == next)
4897 cfg.powerskipmax = 0;
4898 else {
4899 next = endptr + (*endptr != '\0');
4900 if (cfg.powerskipmax <= 0)
4901 badarg = 1;
4902 }
4903 if (*next != '\0') {
4904 if (!strcmp("q", next))
4905 cfg.powerquiet = true;
4906 else {
4907 badarg = 1;
4908 }
4909 }
4910 }
4911 }
4912 break;
4913 case 'S':
4914 // automatic attribute autosave enable/disable
4915 if (!(arg = strtok(nullptr, delim))) {
4916 missingarg = 1;
4917 } else if (!strcmp(arg, "on")) {
4918 cfg.autosave = 2;
4919 } else if (!strcmp(arg, "off")) {
4920 cfg.autosave = 1;
4921 } else {
4922 badarg = 1;
4923 }
4924 break;
4925 case 's':
4926 // warn user, and delete any previously given -s REGEXP Directives
4927 if (!cfg.test_regex.empty()){
4928 PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Test Directive -s %s\n",
4929 configfile, lineno, name, cfg.test_regex.get_pattern());
4931 }
4932 // check for missing argument
4933 if (!(arg = strtok(nullptr, delim))) {
4934 missingarg = 1;
4935 }
4936 // Compile regex
4937 else {
4938 if (!cfg.test_regex.compile(arg)) {
4939 // not a valid regular expression!
4940 PrintOut(LOG_CRIT, "File %s line %d (drive %s): -s argument \"%s\" is INVALID extended regular expression. %s.\n",
4941 configfile, lineno, name, arg, cfg.test_regex.get_errmsg());
4942 return -1;
4943 }
4944 // Do a bit of sanity checking and warn user if we think that
4945 // their regexp is "strange". User probably confused about shell
4946 // glob(3) syntax versus regular expression syntax regexp(7).
4947 // Check also for possible invalid number of digits in ':NNN[-LLL]' suffix.
4948 static const regular_expression syntax_check(
4949 "[^]$()*+./:?^[|0-9LSCOncr-]+|"
4950 ":[0-9]{0,2}($|[^0-9])|:[0-9]{4,}|"
4951 ":[0-9]{3}-(000|[0-9]{0,2}($|[^0-9])|[0-9]{4,})"
4952 );
4954 if (syntax_check.execute(arg, 1, &range) && 0 <= range.rm_so && range.rm_so < range.rm_eo)
4955 PrintOut(LOG_INFO, "File %s line %d (drive %s): warning, \"%.*s\" looks odd in "
4956 "extended regular expression \"%s\"\n",
4957 configfile, lineno, name, (int)(range.rm_eo - range.rm_so), arg + range.rm_so, arg);
4958 }
4959 break;
4960 case 'm':
4961 // send email to address that follows
4962 if (!(arg = strtok(nullptr, delim)))
4963 missingarg = 1;
4964 else {
4965 if (!cfg.emailaddress.empty())
4966 PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous Address Directive -m %s\n",
4967 configfile, lineno, name, cfg.emailaddress.c_str());
4968 cfg.emailaddress = arg;
4969 }
4970 break;
4971 case 'M':
4972 // email warning options
4973 if (!(arg = strtok(nullptr, delim)))
4974 missingarg = 1;
4975 else if (!strcmp(arg, "once"))
4977 else if (!strcmp(arg, "always"))
4979 else if (!strcmp(arg, "daily"))
4981 else if (!strcmp(arg, "diminishing"))
4983 else if (!strcmp(arg, "test"))
4984 cfg.emailtest = true;
4985 else if (!strcmp(arg, "exec")) {
4986 // Get the next argument (the command line)
4987#ifdef _WIN32
4988 // Allow "/path name/with spaces/..." on Windows
4989 arg = strtok_dequote(delim);
4990 if (arg && arg[0] == '"') {
4991 PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive %s 'exec' argument: missing closing quote\n",
4992 configfile, lineno, name, token);
4993 return -1;
4994 }
4995#else
4996 arg = strtok(nullptr, delim);
4997#endif
4998 if (!arg) {
4999 PrintOut(LOG_CRIT, "File %s line %d (drive %s): Directive %s 'exec' argument must be followed by executable path.\n",
5000 configfile, lineno, name, token);
5001 return -1;
5002 }
5003 // Free the last cmd line given if any, and copy new one
5004 if (!cfg.emailcmdline.empty())
5005 PrintOut(LOG_INFO, "File %s line %d (drive %s): ignoring previous mail Directive -M exec %s\n",
5006 configfile, lineno, name, cfg.emailcmdline.c_str());
5007 cfg.emailcmdline = arg;
5008 }
5009 else
5010 badarg = 1;
5011 break;
5012 case 'i':
5013 // ignore failure of usage attribute
5014 if ((val = GetInteger((arg = strtok(nullptr, delim)), name, token, lineno, configfile, 1, 255)) < 0)
5015 return -1;
5017 break;
5018 case 'I':
5019 // ignore attribute for tracking purposes
5020 if ((val = GetInteger((arg = strtok(nullptr, delim)), name, token, lineno, configfile, 1, 255)) < 0)
5021 return -1;
5023 break;
5024 case 'r':
5025 // print raw value when tracking
5026 if ((val = GetInteger((arg = strtok(nullptr, delim)), name, token, lineno, configfile, 1, 255, excl)) < 0)
5027 return -1;
5029 if (*excl == '!') // attribute change is critical
5031 break;
5032 case 'R':
5033 // track changes in raw value (forces printing of raw value)
5034 if ((val = GetInteger((arg = strtok(nullptr, delim)), name, token, lineno, configfile, 1, 255, excl)) < 0)
5035 return -1;
5037 if (*excl == '!') // raw value change is critical
5039 break;
5040 case 'W':
5041 // track Temperature
5042 if (Get3Integers((arg = strtok(nullptr, delim)), name, token, lineno, configfile,
5043 &cfg.tempdiff, &cfg.tempinfo, &cfg.tempcrit) < 0)
5044 return -1;
5045 break;
5046 case 'v':
5047 // non-default vendor-specific attribute meaning
5048 if (!(arg = strtok(nullptr, delim))) {
5049 missingarg = 1;
5050 } else if (!parse_attribute_def(arg, cfg.attribute_defs, PRIOR_USER)) {
5051 badarg = 1;
5052 }
5053 break;
5054 case 'P':
5055 // Define use of drive-specific presets.
5056 if (!(arg = strtok(nullptr, delim))) {
5057 missingarg = 1;
5058 } else if (!strcmp(arg, "use")) {
5059 cfg.ignorepresets = false;
5060 } else if (!strcmp(arg, "ignore")) {
5061 cfg.ignorepresets = true;
5062 } else if (!strcmp(arg, "show")) {
5063 cfg.showpresets = true;
5064 } else if (!strcmp(arg, "showall")) {
5066 } else {
5067 badarg = 1;
5068 }
5069 break;
5070
5071 case 'e':
5072 // Various ATA settings
5073 if (!(arg = strtok(nullptr, delim))) {
5074 missingarg = true;
5075 }
5076 else {
5077 char arg2[16+1]; unsigned uval;
5078 int n1 = -1, n2 = -1, n3 = -1, len = strlen(arg);
5079 if (sscanf(arg, "%16[^,=]%n%*[,=]%n%u%n", arg2, &n1, &n2, &uval, &n3) >= 1
5080 && (n1 == len || n2 > 0)) {
5081 bool on = (n2 > 0 && !strcmp(arg+n2, "on"));
5082 bool off = (n2 > 0 && !strcmp(arg+n2, "off"));
5083 if (n3 != len)
5084 uval = ~0U;
5085
5086 if (!strcmp(arg2, "aam")) {
5087 if (off)
5088 cfg.set_aam = -1;
5089 else if (uval <= 254)
5090 cfg.set_aam = uval + 1;
5091 else
5092 badarg = true;
5093 }
5094 else if (!strcmp(arg2, "apm")) {
5095 if (off)
5096 cfg.set_apm = -1;
5097 else if (1 <= uval && uval <= 254)
5098 cfg.set_apm = uval + 1;
5099 else
5100 badarg = true;
5101 }
5102 else if (!strcmp(arg2, "lookahead")) {
5103 if (off)
5104 cfg.set_lookahead = -1;
5105 else if (on)
5106 cfg.set_lookahead = 1;
5107 else
5108 badarg = true;
5109 }
5110 else if (!strcmp(arg, "security-freeze")) {
5111 cfg.set_security_freeze = true;
5112 }
5113 else if (!strcmp(arg2, "standby")) {
5114 if (off)
5115 cfg.set_standby = 0 + 1;
5116 else if (uval <= 255)
5117 cfg.set_standby = uval + 1;
5118 else
5119 badarg = true;
5120 }
5121 else if (!strcmp(arg2, "wcache")) {
5122 if (off)
5123 cfg.set_wcache = -1;
5124 else if (on)
5125 cfg.set_wcache = 1;
5126 else
5127 badarg = true;
5128 }
5129 else if (!strcmp(arg2, "dsn")) {
5130 if (off)
5131 cfg.set_dsn = -1;
5132 else if (on)
5133 cfg.set_dsn = 1;
5134 else
5135 badarg = true;
5136 }
5137 else
5138 badarg = true;
5139 }
5140 else
5141 badarg = true;
5142 }
5143 break;
5144
5145 case 'c':
5146 // Override command line options
5147 {
5148 if (!(arg = strtok(nullptr, delim))) {
5149 missingarg = true;
5150 break;
5151 }
5152 int n = 0, nc = -1, len = strlen(arg);
5153 if ( ( sscanf(arg, "i=%d%n", &n, &nc) == 1
5154 || sscanf(arg, "interval=%d%n", &n, &nc) == 1)
5155 && nc == len && n >= 10)
5156 cfg.checktime = n;
5157 else
5158 badarg = true;
5159 }
5160 break;
5161
5162 default:
5163 // Directive not recognized
5164 PrintOut(LOG_CRIT,"File %s line %d (drive %s): unknown Directive: %s\n",
5165 configfile, lineno, name, token);
5166 PrintOut(LOG_CRIT, "Run smartd -D to print a list of valid Directives.\n");
5167 return -1;
5168 }
5169 if (missingarg) {
5170 PrintOut(LOG_CRIT, "File %s line %d (drive %s): Missing argument to %s Directive\n",
5171 configfile, lineno, name, token);
5172 }
5173 if (badarg) {
5174 PrintOut(LOG_CRIT, "File %s line %d (drive %s): Invalid argument to %s Directive: %s\n",
5175 configfile, lineno, name, token, arg);
5176 }
5177 if (missingarg || badarg) {
5178 PrintOut(LOG_CRIT, "Valid arguments to %s Directive are: ", token);
5179 printoutvaliddirectiveargs(LOG_CRIT, sym);
5180 PrintOut(LOG_CRIT, "\n");
5181 return -1;
5182 }
5183
5184 // Continue with no lookahead
5185 token = nullptr;
5186 return 1;
5187}
5188
5189// Scan directive for configuration file
5190#define SCANDIRECTIVE "DEVICESCAN"
5191
5192// This is the routine that adds things to the conf_entries list.
5193//
5194// Return values are:
5195// 1: parsed a normal line
5196// 0: found DEFAULT setting or comment or blank line
5197// -1: found SCANDIRECTIVE line
5198// -2: found an error
5199//
5200// Note: this routine modifies *line from the caller!
5201static int ParseConfigLine(dev_config_vector & conf_entries, dev_config & default_conf,
5202 smart_devtype_list & scan_types, int lineno, /*const*/ char * line)
5203{
5204 const char *delim = " \n\t";
5205
5206 // get first token: device name. If a comment, skip line
5207 const char * name = strtok(line, delim);
5208 if (!name || *name == '#')
5209 return 0;
5210
5211 // Check device name for DEFAULT or DEVICESCAN
5212 int retval;
5213 if (!strcmp("DEFAULT", name)) {
5214 retval = 0;
5215 // Restart with empty defaults
5216 default_conf = dev_config();
5217 }
5218 else {
5219 retval = (!strcmp(SCANDIRECTIVE, name) ? -1 : 1);
5220 // Init new entry with current defaults
5221 conf_entries.push_back(default_conf);
5222 }
5223 dev_config & cfg = (retval ? conf_entries.back() : default_conf);
5224
5225 cfg.name = name; // Later replaced by dev->get_info().info_name
5226 cfg.dev_name = name; // If DEVICESCAN later replaced by get->dev_info().dev_name
5227 cfg.lineno = lineno;
5228
5229 // parse tokens one at a time from the file.
5230 int rc;
5231 for (char * token = nullptr; (rc = ParseToken(token, cfg, scan_types)) != 0; ) {
5232 if (rc < 0)
5233 // error found on the line
5234 return -2;
5235 }
5236
5237 // Check for multiple -d TYPE directives
5238 if (retval != -1 && scan_types.size() > 1) {
5239 PrintOut(LOG_CRIT, "Drive: %s, invalid multiple -d TYPE Directives on line %d of file %s\n",
5240 cfg.name.c_str(), cfg.lineno, configfile);
5241 return -2;
5242 }
5243
5244 // Don't perform checks below for DEFAULT entries
5245 if (retval == 0)
5246 return retval;
5247
5248 // If NO monitoring directives are set, then set all of them.
5249 if (!( cfg.smartcheck || cfg.selftest
5250 || cfg.errorlog || cfg.xerrorlog
5251 || cfg.offlinests || cfg.selfteststs
5252 || cfg.usagefailed || cfg.prefail || cfg.usage
5253 || cfg.tempdiff || cfg.tempinfo || cfg.tempcrit)) {
5254
5255 PrintOut(LOG_INFO,"Drive: %s, implied '-a' Directive on line %d of file %s\n",
5256 cfg.name.c_str(), cfg.lineno, configfile);
5257
5258 cfg.smartcheck = true;
5259 cfg.smartcheck_nvme = 0xff;
5260 cfg.usagefailed = true;
5261 cfg.prefail = true;
5262 cfg.usage = true;
5263 cfg.selftest = true;
5264 cfg.errorlog = true;
5265 cfg.selfteststs = true;
5266 }
5267
5268 // additional sanity check. Has user set -M options without -m?
5269 if ( cfg.emailaddress.empty()
5270 && (!cfg.emailcmdline.empty() || cfg.emailfreq != emailfreqs::unknown || cfg.emailtest)) {
5271 PrintOut(LOG_CRIT,"Drive: %s, -M Directive(s) on line %d of file %s need -m ADDRESS Directive\n",
5272 cfg.name.c_str(), cfg.lineno, configfile);
5273 return -2;
5274 }
5275
5276 // has the user has set <nomailer>?
5277 if (cfg.emailaddress == "<nomailer>") {
5278 // check that -M exec is also set
5279 if (cfg.emailcmdline.empty()){
5280 PrintOut(LOG_CRIT,"Drive: %s, -m <nomailer> Directive on line %d of file %s needs -M exec Directive\n",
5281 cfg.name.c_str(), cfg.lineno, configfile);
5282 return -2;
5283 }
5284 // From here on the sign of <nomailer> is cfg.emailaddress.empty() and !cfg.emailcmdline.empty()
5285 cfg.emailaddress.clear();
5286 }
5287
5288 return retval;
5289}
5290
5291// Parses a configuration file. Return values are:
5292// N=>0: found N entries
5293// -1: syntax error in config file
5294// -2: config file does not exist
5295// -3: config file exists but cannot be read
5296//
5297// In the case where the return value is 0, there are three
5298// possibilities:
5299// Empty configuration file ==> conf_entries.empty()
5300// No configuration file ==> conf_entries[0].lineno == 0
5301// SCANDIRECTIVE found ==> conf_entries.back().lineno != 0 (size >= 1)
5302static int ParseConfigFile(dev_config_vector & conf_entries, smart_devtype_list & scan_types)
5303{
5304 // maximum line length in configuration file
5305 const int MAXLINELEN = 256;
5306 // maximum length of a continued line in configuration file
5307 const int MAXCONTLINE = 1023;
5308
5309 stdio_file f;
5310 // Open config file, if it exists and is not <stdin>
5311 if (!(configfile == configfile_stdin)) { // pointer comparison ok here
5312 if (!f.open(configfile,"r") && (errno!=ENOENT || !configfile_alt.empty())) {
5313 // file exists but we can't read it or it should exist due to '-c' option
5314 int ret = (errno!=ENOENT ? -3 : -2);
5315 PrintOut(LOG_CRIT,"%s: Unable to open configuration file %s\n",
5316 strerror(errno),configfile);
5317 return ret;
5318 }
5319 }
5320 else // read from stdin ('-c -' option)
5321 f.open(stdin);
5322
5323 // Start with empty defaults
5324 dev_config default_conf;
5325
5326 // No configuration file found -- use fake one
5327 int entry = 0;
5328 if (!f) {
5329 char fakeconfig[] = SCANDIRECTIVE " -a"; // TODO: Remove this hack, build cfg_entry.
5330
5331 if (ParseConfigLine(conf_entries, default_conf, scan_types, 0, fakeconfig) != -1)
5332 throw std::logic_error("Internal error parsing " SCANDIRECTIVE);
5333 return 0;
5334 }
5335
5336#ifdef __CYGWIN__
5337 setmode(fileno(f), O_TEXT); // Allow files with \r\n
5338#endif
5339
5340 // configuration file exists
5341 PrintOut(LOG_INFO,"Opened configuration file %s\n",configfile);
5342
5343 // parse config file line by line
5344 int lineno = 1, cont = 0, contlineno = 0;
5345 char line[MAXLINELEN+2];
5346 char fullline[MAXCONTLINE+1];
5347
5348 for (;;) {
5349 int len=0,scandevice;
5350 char *lastslash;
5351 char *comment;
5352 char *code;
5353
5354 // make debugging simpler
5355 memset(line,0,sizeof(line));
5356
5357 // get a line
5358 code=fgets(line, MAXLINELEN+2, f);
5359
5360 // are we at the end of the file?
5361 if (!code){
5362 if (cont) {
5363 scandevice = ParseConfigLine(conf_entries, default_conf, scan_types, contlineno, fullline);
5364 // See if we found a SCANDIRECTIVE directive
5365 if (scandevice==-1)
5366 return 0;
5367 // did we find a syntax error
5368 if (scandevice==-2)
5369 return -1;
5370 // the final line is part of a continuation line
5371 entry+=scandevice;
5372 }
5373 break;
5374 }
5375
5376 // input file line number
5377 contlineno++;
5378
5379 // See if line is too long
5380 len=strlen(line);
5381 if (len>MAXLINELEN){
5382 const char *warn;
5383 if (line[len-1]=='\n')
5384 warn="(including newline!) ";
5385 else
5386 warn="";
5387 PrintOut(LOG_CRIT,"Error: line %d of file %s %sis more than MAXLINELEN=%d characters.\n",
5388 (int)contlineno,configfile,warn,(int)MAXLINELEN);
5389 return -1;
5390 }
5391
5392 // Ignore anything after comment symbol
5393 if ((comment=strchr(line,'#'))){
5394 *comment='\0';
5395 len=strlen(line);
5396 }
5397
5398 // is the total line (made of all continuation lines) too long?
5399 if (cont+len>MAXCONTLINE){
5400 PrintOut(LOG_CRIT,"Error: continued line %d (actual line %d) of file %s is more than MAXCONTLINE=%d characters.\n",
5401 lineno, (int)contlineno, configfile, (int)MAXCONTLINE);
5402 return -1;
5403 }
5404
5405 // copy string so far into fullline, and increment length
5406 snprintf(fullline+cont, sizeof(fullline)-cont, "%s" ,line);
5407 cont+=len;
5408
5409 // is this a continuation line. If so, replace \ by space and look at next line
5410 if ( (lastslash=strrchr(line,'\\')) && !strtok(lastslash+1," \n\t")){
5411 *(fullline+(cont-len)+(lastslash-line))=' ';
5412 continue;
5413 }
5414
5415 // Not a continuation line. Parse it
5416 scan_types.clear();
5417 scandevice = ParseConfigLine(conf_entries, default_conf, scan_types, contlineno, fullline);
5418
5419 // did we find a scandevice directive?
5420 if (scandevice==-1)
5421 return 0;
5422 // did we find a syntax error
5423 if (scandevice==-2)
5424 return -1;
5425
5426 entry+=scandevice;
5427 lineno++;
5428 cont=0;
5429 }
5430
5431 // note -- may be zero if syntax of file OK, but no valid entries!
5432 return entry;
5433}
5434
5435/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> <=======\n", where
5436 <LIST> is the list of valid arguments for option opt. */
5437static void PrintValidArgs(char opt)
5438{
5439 const char *s;
5440
5441 PrintOut(LOG_CRIT, "=======> VALID ARGUMENTS ARE: ");
5442 if (!(s = GetValidArgList(opt)))
5443 PrintOut(LOG_CRIT, "Error constructing argument list for option %c", opt);
5444 else
5445 PrintOut(LOG_CRIT, "%s", (char *)s);
5446 PrintOut(LOG_CRIT, " <=======\n");
5447}
5448
5449#ifndef _WIN32
5450// Report error and return false if specified path is not absolute.
5451static bool check_abs_path(char option, const std::string & path)
5452{
5453 if (path.empty() || path[0] == '/')
5454 return true;
5455
5456 debugmode = 1;
5457 PrintHead();
5458 PrintOut(LOG_CRIT, "=======> INVALID ARGUMENT TO -%c: %s <=======\n\n", option, path.c_str());
5459 PrintOut(LOG_CRIT, "Error: relative path names are not allowed\n\n");
5460 return false;
5461}
5462#endif // !_WIN32
5463
5464// Parses input line, prints usage message and
5465// version/license/copyright messages
5466static int parse_options(int argc, char **argv)
5467{
5468 // Init default path names
5469#ifndef _WIN32
5470 configfile = SMARTMONTOOLS_SYSCONFDIR "/smartd.conf";
5471 warning_script = SMARTMONTOOLS_SMARTDSCRIPTDIR "/smartd_warning.sh";
5472#else
5473 std::string exedir = get_exe_dir();
5474 static std::string configfile_str = exedir + "/smartd.conf";
5475 configfile = configfile_str.c_str();
5476 warning_script = exedir + "/smartd_warning.cmd";
5477#endif
5478
5479 // Please update GetValidArgList() if you edit shortopts
5480 static const char shortopts[] = "c:l:q:dDni:p:r:s:A:B:w:Vh?"
5481#if defined(HAVE_POSIX_API) || defined(_WIN32)
5482 "u:"
5483#endif
5484#ifdef HAVE_LIBCAP_NG
5485 "C"
5486#endif
5487 ;
5488 // Please update GetValidArgList() if you edit longopts
5489 struct option longopts[] = {
5490 { "configfile", required_argument, 0, 'c' },
5491 { "logfacility", required_argument, 0, 'l' },
5492 { "quit", required_argument, 0, 'q' },
5493 { "debug", no_argument, 0, 'd' },
5494 { "showdirectives", no_argument, 0, 'D' },
5495 { "interval", required_argument, 0, 'i' },
5496#ifndef _WIN32
5497 { "no-fork", no_argument, 0, 'n' },
5498#else
5499 { "service", no_argument, 0, 'n' },
5500#endif
5501 { "pidfile", required_argument, 0, 'p' },
5502 { "report", required_argument, 0, 'r' },
5503 { "savestates", required_argument, 0, 's' },
5504 { "attributelog", required_argument, 0, 'A' },
5505 { "drivedb", required_argument, 0, 'B' },
5506 { "warnexec", required_argument, 0, 'w' },
5507 { "version", no_argument, 0, 'V' },
5508 { "license", no_argument, 0, 'V' },
5509 { "copyright", no_argument, 0, 'V' },
5510 { "help", no_argument, 0, 'h' },
5511 { "usage", no_argument, 0, 'h' },
5512#if defined(HAVE_POSIX_API) || defined(_WIN32)
5513 { "warn-as-user", required_argument, 0, 'u' },
5514#endif
5515#ifdef HAVE_LIBCAP_NG
5516 { "capabilities", optional_argument, 0, 'C' },
5517#endif
5518 { 0, 0, 0, 0 }
5519 };
5520
5521 opterr=optopt=0;
5522 bool badarg = false;
5523 const char * badarg_msg = nullptr;
5524 bool use_default_db = true; // set false on '-B FILE'
5525
5526 // Parse input options.
5527 int optchar;
5528 while ((optchar = getopt_long(argc, argv, shortopts, longopts, nullptr)) != -1) {
5529 char *arg;
5530 char *tailptr;
5531 long lchecktime;
5532
5533 switch(optchar) {
5534 case 'q':
5535 // when to quit
5536 quit_nodev0 = false;
5537 if (!strcmp(optarg, "nodev"))
5538 quit = QUIT_NODEV;
5539 else if (!strcmp(optarg, "nodev0")) {
5540 quit = QUIT_NODEV;
5541 quit_nodev0 = true;
5542 }
5543 else if (!strcmp(optarg, "nodevstartup"))
5545 else if (!strcmp(optarg, "nodev0startup")) {
5547 quit_nodev0 = true;
5548 }
5549 else if (!strcmp(optarg, "errors"))
5550 quit = QUIT_ERRORS;
5551 else if (!strcmp(optarg, "errors,nodev0")) {
5552 quit = QUIT_ERRORS;
5553 quit_nodev0 = true;
5554 }
5555 else if (!strcmp(optarg, "never"))
5556 quit = QUIT_NEVER;
5557 else if (!strcmp(optarg, "onecheck")) {
5559 debugmode = 1;
5560 }
5561 else if (!strcmp(optarg, "showtests")) {
5563 debugmode = 1;
5564 }
5565 else
5566 badarg = true;
5567 break;
5568 case 'l':
5569 // set the log facility level
5570 if (!strcmp(optarg, "daemon"))
5571 facility=LOG_DAEMON;
5572 else if (!strcmp(optarg, "local0"))
5573 facility=LOG_LOCAL0;
5574 else if (!strcmp(optarg, "local1"))
5575 facility=LOG_LOCAL1;
5576 else if (!strcmp(optarg, "local2"))
5577 facility=LOG_LOCAL2;
5578 else if (!strcmp(optarg, "local3"))
5579 facility=LOG_LOCAL3;
5580 else if (!strcmp(optarg, "local4"))
5581 facility=LOG_LOCAL4;
5582 else if (!strcmp(optarg, "local5"))
5583 facility=LOG_LOCAL5;
5584 else if (!strcmp(optarg, "local6"))
5585 facility=LOG_LOCAL6;
5586 else if (!strcmp(optarg, "local7"))
5587 facility=LOG_LOCAL7;
5588 else
5589 badarg = true;
5590 break;
5591 case 'd':
5592 // enable debug mode
5593 debugmode = 1;
5594 break;
5595 case 'n':
5596 // don't fork()
5597#ifndef _WIN32 // On Windows, --service is already handled by daemon_main()
5598 do_fork = false;
5599#endif
5600 break;
5601 case 'D':
5602 // print summary of all valid directives
5603 debugmode = 1;
5604 Directives();
5605 return 0;
5606 case 'i':
5607 // Period (time interval) for checking
5608 // strtol will set errno in the event of overflow, so we'll check it.
5609 errno = 0;
5610 lchecktime = strtol(optarg, &tailptr, 10);
5611 if (*tailptr != '\0' || lchecktime < 10 || lchecktime > INT_MAX || errno) {
5612 debugmode=1;
5613 PrintHead();
5614 PrintOut(LOG_CRIT, "======> INVALID INTERVAL: %s <=======\n", optarg);
5615 PrintOut(LOG_CRIT, "======> INTERVAL MUST BE INTEGER BETWEEN %d AND %d <=======\n", 10, INT_MAX);
5616 PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
5617 return EXIT_BADCMD;
5618 }
5619 checktime = (int)lchecktime;
5620 break;
5621 case 'r':
5622 // report IOCTL transactions
5623 {
5624 int n1 = -1, n2 = -1, len = strlen(optarg);
5625 char s[9+1]; unsigned i = 1;
5626 sscanf(optarg, "%9[a-z]%n,%u%n", s, &n1, &i, &n2);
5627 if (!((n1 == len || n2 == len) && 1 <= i && i <= 4)) {
5628 badarg = true;
5629 } else if (!strcmp(s,"ioctl")) {
5631 } else if (!strcmp(s,"ataioctl")) {
5632 ata_debugmode = i;
5633 } else if (!strcmp(s,"scsiioctl")) {
5634 scsi_debugmode = i;
5635 } else if (!strcmp(s,"nvmeioctl")) {
5636 nvme_debugmode = i;
5637 } else {
5638 badarg = true;
5639 }
5640 }
5641 break;
5642 case 'c':
5643 // alternate configuration file
5644 if (strcmp(optarg,"-"))
5645 configfile = (configfile_alt = optarg).c_str();
5646 else // read from stdin
5648 break;
5649 case 'p':
5650 // output file with PID number
5651 pid_file = optarg;
5652 break;
5653 case 's':
5654 // path prefix of persistent state file
5655 state_path_prefix = (strcmp(optarg, "-") ? optarg : "");
5656 break;
5657 case 'A':
5658 // path prefix of attribute log file
5659 attrlog_path_prefix = (strcmp(optarg, "-") ? optarg : "");
5660 break;
5661 case 'B':
5662 {
5663 const char * path = optarg;
5664 if (*path == '+' && path[1])
5665 path++;
5666 else
5667 use_default_db = false;
5668 unsigned char savedebug = debugmode; debugmode = 1;
5669 if (!read_drive_database(path))
5670 return EXIT_BADCMD;
5671 debugmode = savedebug;
5672 }
5673 break;
5674 case 'w':
5675 warning_script = optarg;
5676 break;
5677#ifdef HAVE_POSIX_API
5678 case 'u':
5679 warn_as_user = false;
5680 if (strcmp(optarg, "-")) {
5681 warn_uname = warn_gname = "unknown";
5682 badarg_msg = parse_ugid(optarg, warn_uid, warn_gid,
5683 warn_uname, warn_gname );
5684 if (badarg_msg)
5685 break;
5686 warn_as_user = true;
5687 }
5688 break;
5689#elif defined(_WIN32)
5690 case 'u':
5691 if (!strcmp(optarg, "restricted"))
5692 warn_as_restr_user = true;
5693 else if (!strcmp(optarg, "unchanged"))
5694 warn_as_restr_user = false;
5695 else
5696 badarg = true;
5697 break;
5698#endif // HAVE_POSIX_API ||_WIN32
5699 case 'V':
5700 // print version and CVS info
5701 debugmode = 1;
5702 PrintOut(LOG_INFO, "%s", format_version_info("smartd", 3 /*full*/).c_str());
5703 return 0;
5704#ifdef HAVE_LIBCAP_NG
5705 case 'C':
5706 // enable capabilities
5707 if (!optarg)
5708 capabilities_mode = 1;
5709 else if (!strcmp(optarg, "mail"))
5710 capabilities_mode = 2;
5711 else
5712 badarg = true;
5713 break;
5714#endif
5715 case 'h':
5716 // help: print summary of command-line options
5717 debugmode=1;
5718 PrintHead();
5719 Usage();
5720 return 0;
5721 case '?':
5722 default:
5723 // unrecognized option
5724 debugmode=1;
5725 PrintHead();
5726 // Point arg to the argument in which this option was found.
5727 // Note: getopt_long() may set optind > argc (e.g. musl libc)
5728 arg = argv[optind <= argc ? optind - 1 : argc - 1];
5729 // Check whether the option is a long option that doesn't map to -h.
5730 if (arg[1] == '-' && optchar != 'h') {
5731 // Iff optopt holds a valid option then argument must be missing.
5732 if (optopt && strchr(shortopts, optopt)) {
5733 PrintOut(LOG_CRIT, "=======> ARGUMENT REQUIRED FOR OPTION: %s <=======\n",arg+2);
5734 PrintValidArgs(optopt);
5735 } else {
5736 PrintOut(LOG_CRIT, "=======> UNRECOGNIZED OPTION: %s <=======\n\n",arg+2);
5737 }
5738 PrintOut(LOG_CRIT, "\nUse smartd --help to get a usage summary\n\n");
5739 return EXIT_BADCMD;
5740 }
5741 if (optopt) {
5742 // Iff optopt holds a valid option then argument must be missing.
5743 if (strchr(shortopts, optopt)){
5744 PrintOut(LOG_CRIT, "=======> ARGUMENT REQUIRED FOR OPTION: %c <=======\n",optopt);
5745 PrintValidArgs(optopt);
5746 } else {
5747 PrintOut(LOG_CRIT, "=======> UNRECOGNIZED OPTION: %c <=======\n\n",optopt);
5748 }
5749 PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
5750 return EXIT_BADCMD;
5751 }
5752 Usage();
5753 return 0;
5754 }
5755
5756 // Check to see if option had an unrecognized or incorrect argument.
5757 if (badarg || badarg_msg) {
5758 debugmode=1;
5759 PrintHead();
5760 // It would be nice to print the actual option name given by the user
5761 // here, but we just print the short form. Please fix this if you know
5762 // a clean way to do it.
5763 PrintOut(LOG_CRIT, "=======> INVALID ARGUMENT TO -%c: %s <======= \n", optchar, optarg);
5764 if (badarg_msg)
5765 PrintOut(LOG_CRIT, "%s\n", badarg_msg);
5766 else
5767 PrintValidArgs(optchar);
5768 PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
5769 return EXIT_BADCMD;
5770 }
5771 }
5772
5773 // non-option arguments are not allowed
5774 if (argc > optind) {
5775 debugmode=1;
5776 PrintHead();
5777 PrintOut(LOG_CRIT, "=======> UNRECOGNIZED ARGUMENT: %s <=======\n\n", argv[optind]);
5778 PrintOut(LOG_CRIT, "\nUse smartd -h to get a usage summary\n\n");
5779 return EXIT_BADCMD;
5780 }
5781
5782 // no pidfile in debug mode
5783 if (debugmode && !pid_file.empty()) {
5784 debugmode=1;
5785 PrintHead();
5786 PrintOut(LOG_CRIT, "=======> INVALID CHOICE OF OPTIONS: -d and -p <======= \n\n");
5787 PrintOut(LOG_CRIT, "Error: pid file %s not written in debug (-d) mode\n\n", pid_file.c_str());
5788 return EXIT_BADCMD;
5789 }
5790
5791#ifndef _WIN32
5792 if (!debugmode) {
5793 // absolute path names are required due to chdir('/') in daemon_init()
5794 if (!( check_abs_path('p', pid_file)
5797 return EXIT_BADCMD;
5798 }
5799#endif
5800
5801#ifdef _WIN32
5802 if (warn_as_restr_user && !popen_as_restr_check()) {
5803 // debugmode=1 // would suppress messages to eventlog or log file
5804 PrintHead();
5805 PrintOut(LOG_CRIT, "Option '--warn-as-user=restricted' is not effective if the current user\n");
5806 PrintOut(LOG_CRIT, "is the local 'SYSTEM' or 'Administrator' account\n\n");
5807 return EXIT_BADCMD;
5808 }
5809#endif
5810
5811 // Read or init drive database
5812 {
5813 unsigned char savedebug = debugmode; debugmode = 1;
5814 if (!init_drive_database(use_default_db))
5815 return EXIT_BADCMD;
5816 debugmode = savedebug;
5817 }
5818
5819 // Check option compatibility of notify support
5820 // cppcheck-suppress knownConditionTrueFalse
5821 if (!notify_post_init())
5822 return EXIT_BADCMD;
5823
5824 // print header, don't write Copyright line to syslog
5825 PrintOut(LOG_INFO, "%s\n", format_version_info("smartd", (debugmode ? 2 : 1)).c_str());
5826
5827 // No error, continue in main_worker()
5828 return -1;
5829}
5830
5831// Function we call if no configuration file was found or if the
5832// SCANDIRECTIVE Directive was found. It makes entries for device
5833// names returned by scan_smart_devices() in os_OSNAME.cpp
5834static int MakeConfigEntries(const dev_config & base_cfg,
5835 dev_config_vector & conf_entries, smart_device_list & scanned_devs,
5836 const smart_devtype_list & types)
5837{
5838 // make list of devices
5839 smart_device_list devlist;
5840 if (!smi()->scan_smart_devices(devlist, types)) {
5841 PrintOut(LOG_CRIT, "DEVICESCAN failed: %s\n", smi()->get_errmsg());
5842 return 0;
5843 }
5844
5845 // if no devices, return
5846 if (devlist.size() == 0)
5847 return 0;
5848
5849 // add empty device slots for existing config entries
5850 while (scanned_devs.size() < conf_entries.size())
5851 scanned_devs.push_back((smart_device *)0);
5852
5853 // loop over entries to create
5854 for (unsigned i = 0; i < devlist.size(); i++) {
5855 // Move device pointer
5856 smart_device * dev = devlist.release(i);
5857 scanned_devs.push_back(dev);
5858
5859 // Append configuration and update names
5860 conf_entries.push_back(base_cfg);
5861 dev_config & cfg = conf_entries.back();
5862 cfg.name = dev->get_info().info_name;
5863 cfg.dev_name = dev->get_info().dev_name;
5864
5865 // Set type only if scanning is limited to specific types
5866 // This is later used to set SMARTD_DEVICETYPE environment variable
5867 if (!types.empty())
5868 cfg.dev_type = dev->get_info().dev_type;
5869 else // SMARTD_DEVICETYPE=auto
5870 cfg.dev_type.clear();
5871 }
5872
5873 return devlist.size();
5874}
5875
5876// Returns negative value (see ParseConfigFile()) if config file
5877// had errors, else number of entries which may be zero or positive.
5878static int ReadOrMakeConfigEntries(dev_config_vector & conf_entries, smart_device_list & scanned_devs)
5879{
5880 // parse configuration file configfile (normally /etc/smartd.conf)
5881 smart_devtype_list scan_types;
5882 int entries = ParseConfigFile(conf_entries, scan_types);
5883
5884 if (entries < 0) {
5885 // There was an error reading the configuration file.
5886 conf_entries.clear();
5887 if (entries == -1)
5888 PrintOut(LOG_CRIT, "Configuration file %s has fatal syntax errors.\n", configfile);
5889 return entries;
5890 }
5891
5892 // no error parsing config file.
5893 if (entries) {
5894 // we did not find a SCANDIRECTIVE and did find valid entries
5895 PrintOut(LOG_INFO, "Configuration file %s parsed.\n", configfile);
5896 }
5897 else if (!conf_entries.empty()) {
5898 // we found a SCANDIRECTIVE or there was no configuration file so
5899 // scan. Configuration file's last entry contains all options
5900 // that were set
5901 dev_config first = conf_entries.back();
5902 conf_entries.pop_back();
5903
5904 if (first.lineno)
5905 PrintOut(LOG_INFO,"Configuration file %s was parsed, found %s, scanning devices\n", configfile, SCANDIRECTIVE);
5906 else
5907 PrintOut(LOG_INFO,"No configuration file %s found, scanning devices\n", configfile);
5908
5909 // make config list of devices to search for
5910 MakeConfigEntries(first, conf_entries, scanned_devs, scan_types);
5911
5912 // warn user if scan table found no devices
5913 if (conf_entries.empty())
5914 PrintOut(LOG_CRIT,"In the system's table of devices NO devices found to scan\n");
5915 }
5916 else
5917 PrintOut(LOG_CRIT, "Configuration file %s parsed but has no entries\n", configfile);
5918
5919 return conf_entries.size();
5920}
5921
5922// Register one device, return false on error
5924 const dev_config_vector * prev_cfgs)
5925{
5926 bool scanning;
5927 if (!dev) {
5928 // Get device of appropriate type
5929 dev = smi()->get_smart_device(cfg.name.c_str(), cfg.dev_type.c_str());
5930 if (!dev) {
5931 if (cfg.dev_type.empty())
5932 PrintOut(LOG_INFO, "Device: %s, unable to autodetect device type\n", cfg.name.c_str());
5933 else
5934 PrintOut(LOG_INFO, "Device: %s, unsupported device type '%s'\n", cfg.name.c_str(), cfg.dev_type.c_str());
5935 return false;
5936 }
5937 scanning = false;
5938 }
5939 else {
5940 // Use device from device scan
5941 scanning = true;
5942 }
5943
5944 // Save old info
5945 smart_device::device_info oldinfo = dev->get_info();
5946
5947 // Open with autodetect support, may return 'better' device
5948 dev.replace( dev->autodetect_open() );
5949
5950 // Report if type has changed
5951 if (oldinfo.dev_type != dev->get_dev_type())
5952 PrintOut(LOG_INFO, "Device: %s, type changed from '%s' to '%s'\n",
5953 cfg.name.c_str(), oldinfo.dev_type.c_str(), dev->get_dev_type());
5954
5955 // Return if autodetect_open() failed
5956 if (!dev->is_open()) {
5957 if (debugmode || !scanning)
5958 PrintOut(LOG_INFO, "Device: %s, open() failed: %s\n", dev->get_info_name(), dev->get_errmsg());
5959 return false;
5960 }
5961
5962 // Update informal name
5963 cfg.name = dev->get_info().info_name;
5964 PrintOut(LOG_INFO, "Device: %s, opened\n", cfg.name.c_str());
5965
5966 int status;
5967 const char * typemsg;
5968 // register ATA device
5969 if (dev->is_ata()){
5970 typemsg = "ATA";
5971 status = ATADeviceScan(cfg, state, dev->to_ata(), prev_cfgs);
5972 }
5973 // or register SCSI device
5974 else if (dev->is_scsi()){
5975 typemsg = "SCSI";
5976 status = SCSIDeviceScan(cfg, state, dev->to_scsi(), prev_cfgs);
5977 }
5978 // or register NVMe device
5979 else if (dev->is_nvme()) {
5980 typemsg = "NVMe";
5981 status = NVMeDeviceScan(cfg, state, dev->to_nvme(), prev_cfgs);
5982 }
5983 else {
5984 PrintOut(LOG_INFO, "Device: %s, neither ATA, SCSI nor NVMe device\n", cfg.name.c_str());
5985 return false;
5986 }
5987
5988 if (status) {
5989 if (!scanning || debugmode) {
5990 if (cfg.lineno)
5991 PrintOut(scanning ? LOG_INFO : LOG_CRIT,
5992 "Unable to register %s device %s at line %d of file %s\n",
5993 typemsg, cfg.name.c_str(), cfg.lineno, configfile);
5994 else
5995 PrintOut(LOG_INFO, "Unable to register %s device %s\n",
5996 typemsg, cfg.name.c_str());
5997 }
5998
5999 return false;
6000 }
6001
6002 return true;
6003}
6004
6005// This function tries devices from conf_entries. Each one that can be
6006// registered is moved onto the [ata|scsi]devices lists and removed
6007// from the conf_entries list.
6008static bool register_devices(const dev_config_vector & conf_entries, smart_device_list & scanned_devs,
6010{
6011 // start by clearing lists/memory of ALL existing devices
6012 configs.clear();
6013 devices.clear();
6014 states.clear();
6015
6016 // Map of already seen non-DEVICESCAN devices (unique_name -> cfg.name)
6017 typedef std::map<std::string, std::string> prev_unique_names_map;
6018 prev_unique_names_map prev_unique_names;
6019
6020 // Register entries
6021 for (unsigned i = 0; i < conf_entries.size(); i++) {
6022 dev_config cfg = conf_entries[i];
6023
6024 // Get unique device "name [type]" (with symlinks resolved) for duplicate detection
6025 std::string unique_name = smi()->get_unique_dev_name(cfg.dev_name.c_str(), cfg.dev_type.c_str());
6026 if (debugmode && unique_name != cfg.dev_name) {
6027 pout("Device: %s%s%s%s, unique name: %s\n", cfg.name.c_str(),
6028 (!cfg.dev_type.empty() ? " [" : ""), cfg.dev_type.c_str(),
6029 (!cfg.dev_type.empty() ? "]" : ""), unique_name.c_str());
6030 }
6031
6032 if (cfg.ignore) {
6033 // Store for duplicate detection and ignore
6034 PrintOut(LOG_INFO, "Device: %s%s%s%s, ignored\n", cfg.name.c_str(),
6035 (!cfg.dev_type.empty() ? " [" : ""), cfg.dev_type.c_str(),
6036 (!cfg.dev_type.empty() ? "]" : ""));
6037 prev_unique_names[unique_name] = cfg.name;
6038 continue;
6039 }
6040
6042
6043 // Device may already be detected during devicescan
6044 bool scanning = false;
6045 if (i < scanned_devs.size()) {
6046 dev = scanned_devs.release(i);
6047 if (dev) {
6048 // Check for a preceding non-DEVICESCAN entry for the same device
6049 prev_unique_names_map::iterator ui = prev_unique_names.find(unique_name);
6050 if (ui != prev_unique_names.end()) {
6051 bool ne = (ui->second != cfg.name);
6052 PrintOut(LOG_INFO, "Device: %s, %s%s, ignored\n", dev->get_info_name(),
6053 (ne ? "same as " : "duplicate"), (ne ? ui->second.c_str() : ""));
6054 continue;
6055 }
6056 scanning = true;
6057 }
6058 }
6059
6060 // Prevent systemd unit startup timeout when registering many devices
6062
6063 // Register device
6064 // If scanning, pass dev_idinfo of previous devices for duplicate check
6065 dev_state state;
6066 if (!register_device(cfg, state, dev, (scanning ? &configs : 0))) {
6067 // if device is explicitly listed and we can't register it, then
6068 // exit unless the user has specified that the device is removable
6069 if (!scanning) {
6070 if (!(cfg.removable || quit == QUIT_NEVER)) {
6071 PrintOut(LOG_CRIT, "Unable to register device %s (no Directive -d removable). Exiting.\n",
6072 cfg.name.c_str());
6073 return false;
6074 }
6075 PrintOut(LOG_INFO, "Device: %s, not available\n", cfg.name.c_str());
6076 // Prevent retry of registration
6077 prev_unique_names[unique_name] = cfg.name;
6078 }
6079 continue;
6080 }
6081
6082 // move onto the list of devices
6083 configs.push_back(cfg);
6084 states.push_back(state);
6085 devices.push_back(dev);
6086 if (!scanning)
6087 // Store for duplicate detection
6088 prev_unique_names[unique_name] = cfg.name;
6089 }
6090
6091 // Set minimum check time and factors for staggered tests
6092 checktime_min = 0;
6093 unsigned factor = 0;
6094 for (auto & cfg : configs) {
6095 if (cfg.checktime && (!checktime_min || checktime_min > cfg.checktime))
6096 checktime_min = cfg.checktime;
6097 if (!cfg.test_regex.empty())
6098 cfg.test_offset_factor = factor++;
6099 }
6102
6104 return true;
6105}
6106
6107
6108// Main program without exception handling
6109static int main_worker(int argc, char **argv)
6110{
6111 // Initialize interface
6113 if (!smi())
6114 return 1;
6115
6116 // Check whether systemd notify is supported and enabled
6117 notify_init();
6118
6119 // parse input and print header and usage info if needed
6120 int status = parse_options(argc,argv);
6121 if (status >= 0)
6122 return status;
6123
6124 // Configuration for each device
6125 dev_config_vector configs;
6126 // Device states
6127 dev_state_vector states;
6128 // Devices to monitor
6130
6131 // Drop capabilities if supported and enabled
6133
6134 notify_msg("Initializing ...");
6135
6136 // the main loop of the code
6137 bool firstpass = true, write_states_always = true;
6138 time_t wakeuptime = 0;
6139 // assert(status < 0);
6140 do {
6141 // Should we (re)read the config file?
6142 if (firstpass || caughtsigHUP){
6143 if (!firstpass) {
6144 // Write state files
6145 if (!state_path_prefix.empty())
6146 write_all_dev_states(configs, states);
6147
6148 PrintOut(LOG_INFO,
6149 caughtsigHUP==1?
6150 "Signal HUP - rereading configuration file %s\n":
6151 "\a\nSignal INT - rereading configuration file %s (" SIGQUIT_KEYNAME " quits)\n\n",
6152 configfile);
6153 notify_msg("Reloading ...");
6154 }
6155
6156 {
6157 dev_config_vector conf_entries; // Entries read from smartd.conf
6158 smart_device_list scanned_devs; // Devices found during scan
6159 // (re)reads config file, makes >=0 entries
6160 int entries = ReadOrMakeConfigEntries(conf_entries, scanned_devs);
6161
6162 if (entries>=0) {
6163 // checks devices, then moves onto ata/scsi list or deallocates.
6164 if (!register_devices(conf_entries, scanned_devs, configs, states, devices)) {
6165 status = EXIT_BADDEV;
6166 break;
6167 }
6168 if (!(configs.size() == devices.size() && configs.size() == states.size()))
6169 throw std::logic_error("Invalid result from RegisterDevices");
6170 }
6171 else if ( quit == QUIT_NEVER
6172 || ((quit == QUIT_NODEV || quit == QUIT_NODEVSTARTUP) && !firstpass)) {
6173 // user has asked to continue on error in configuration file
6174 if (!firstpass)
6175 PrintOut(LOG_INFO,"Reusing previous configuration\n");
6176 }
6177 else {
6178 // exit with configuration file error status
6179 status = (entries == -3 ? EXIT_READCONF : entries == -2 ? EXIT_NOCONF : EXIT_BADCONF);
6180 break;
6181 }
6182 }
6183
6184 if (!( devices.size() > 0 || quit == QUIT_NEVER
6185 || (quit == QUIT_NODEVSTARTUP && !firstpass))) {
6186 status = (!quit_nodev0 ? EXIT_NODEV : 0);
6187 PrintOut((status ? LOG_CRIT : LOG_INFO),
6188 "Unable to monitor any SMART enabled devices. Exiting.\n");
6189 break;
6190 }
6191
6192 // Log number of devices we are monitoring...
6193 int numata = 0, numscsi = 0;
6194 for (unsigned i = 0; i < devices.size(); i++) {
6195 const smart_device * dev = devices.at(i);
6196 if (dev->is_ata())
6197 numata++;
6198 else if (dev->is_scsi())
6199 numscsi++;
6200 }
6201 PrintOut(LOG_INFO, "Monitoring %d ATA/SATA, %d SCSI/SAS and %d NVMe devices\n",
6202 numata, numscsi, (int)devices.size() - numata - numscsi);
6203
6204 if (quit == QUIT_SHOWTESTS) {
6205 // user has asked to print test schedule
6206 PrintTestSchedule(configs, states, devices);
6207 // assert(firstpass);
6208 return 0;
6209 }
6210
6211 // reset signal
6212 caughtsigHUP=0;
6213
6214 // Always write state files after (re)configuration
6215 write_states_always = true;
6216 }
6217
6218 // check all devices once,
6219 // self tests are not started in first pass unless '-q onecheck' is specified
6220 notify_check((int)devices.size());
6221 CheckDevicesOnce(configs, states, devices, firstpass, (!firstpass || quit == QUIT_ONECHECK));
6222
6223 // Write state files
6224 if (!state_path_prefix.empty())
6225 write_all_dev_states(configs, states, write_states_always);
6226 write_states_always = false;
6227
6228 // Write attribute logs
6229 if (!attrlog_path_prefix.empty())
6230 write_all_dev_attrlogs(configs, states);
6231
6232 // user has asked us to exit after first check
6233 if (quit == QUIT_ONECHECK) {
6234 PrintOut(LOG_INFO,"Started with '-q onecheck' option. All devices successfully checked once.\n"
6235 "smartd is exiting (exit status 0)\n");
6236 // assert(firstpass);
6237 return 0;
6238 }
6239
6240 if (firstpass) {
6241 if (!debugmode) {
6242 // fork() into background if needed, close ALL file descriptors,
6243 // redirect stdin, stdout, and stderr, chdir to "/".
6244 status = daemon_init();
6245 if (status >= 0)
6246 return status;
6247
6248 // Write PID file if configured
6249 if (!write_pid_file())
6250 return EXIT_PID;
6251 }
6252
6253 // Set exit and signal handlers
6255
6256 // Initialize wakeup time to CURRENT time
6257 wakeuptime = time(nullptr);
6258
6259 firstpass = false;
6260 }
6261
6262 // sleep until next check time, or a signal arrives
6263 wakeuptime = dosleep(wakeuptime, configs, states, write_states_always);
6264
6265 } while (!caughtsigEXIT);
6266
6267 if (caughtsigEXIT && status < 0) {
6268 // Loop exited on signal
6269 if (caughtsigEXIT == SIGTERM || (debugmode && caughtsigEXIT == SIGQUIT)) {
6270 PrintOut(LOG_INFO, "smartd received signal %d: %s\n",
6271 caughtsigEXIT, strsignal(caughtsigEXIT));
6272 }
6273 else {
6274 // Unexpected SIGINT or SIGQUIT
6275 PrintOut(LOG_CRIT, "smartd received unexpected signal %d: %s\n",
6276 caughtsigEXIT, strsignal(caughtsigEXIT));
6277 status = EXIT_SIGNAL;
6278 }
6279 }
6280
6281 // Status unset above implies success
6282 if (status < 0)
6283 status = 0;
6284
6285 if (!firstpass) {
6286 // Loop exited after daemon_init() and write_pid_file()
6287
6288 // Write state files only on normal exit
6289 if (!status && !state_path_prefix.empty())
6290 write_all_dev_states(configs, states);
6291
6292 // Delete PID file, if one was created
6293 if (!pid_file.empty() && unlink(pid_file.c_str()))
6294 PrintOut(LOG_CRIT,"Can't unlink PID file %s (%s).\n",
6295 pid_file.c_str(), strerror(errno));
6296 }
6297
6298 PrintOut((status ? LOG_CRIT : LOG_INFO), "smartd is exiting (exit status %d)\n", status);
6299 return status;
6300}
6301
6302
6303#ifndef _WIN32
6304// Main program
6305int main(int argc, char **argv)
6306#else
6307// Windows: internal main function started direct or by service control manager
6308static int smartd_main(int argc, char **argv)
6309#endif
6310{
6311 int status;
6312 try {
6313 // Do the real work ...
6314 status = main_worker(argc, argv);
6315 }
6316 catch (const std::bad_alloc & /*ex*/) {
6317 // Memory allocation failed (also thrown by std::operator new)
6318 PrintOut(LOG_CRIT, "Smartd: Out of memory\n");
6319 status = EXIT_NOMEM;
6320 }
6321 catch (const std::exception & ex) {
6322 // Other fatal errors
6323 PrintOut(LOG_CRIT, "Smartd: Exception: %s\n", ex.what());
6324 status = EXIT_BADCODE;
6325 }
6326
6327 // Check for remaining device objects
6328 if (smart_device::get_num_objects() != 0) {
6329 PrintOut(LOG_CRIT, "Smartd: Internal Error: %d device object(s) left at exit.\n",
6331 status = EXIT_BADCODE;
6332 }
6333
6334 if (status == EXIT_BADCODE)
6335 PrintOut(LOG_CRIT, "Please inform " PACKAGE_BUGREPORT ", including output of smartd -V.\n");
6336
6337 notify_exit(status);
6338#ifdef _WIN32
6339 daemon_winsvc_exitcode = status;
6340#endif
6341 return status;
6342}
6343
6344
6345#ifdef _WIN32
6346// Main function for Windows
6347int main(int argc, char **argv){
6348 // Options for smartd windows service
6349 static const daemon_winsvc_options svc_opts = {
6350 "--service", // cmd_opt
6351 "smartd", "SmartD Service", // servicename, displayname
6352 // description
6353 "Controls and monitors storage devices using the Self-Monitoring, "
6354 "Analysis and Reporting Technology System (SMART) built into "
6355 "ATA/SATA and SCSI/SAS hard drives and solid-state drives. "
6356 "www.smartmontools.org"
6357 };
6358 // daemon_main() handles daemon and service specific commands
6359 // and starts smartd_main() direct, from a new process,
6360 // or via service control manager
6361 return daemon_main("smartd", &svc_opts , smartd_main, argc, argv);
6362}
6363#endif
bool ata_nodata_command(ata_device *device, unsigned char command, int sector_count)
Definition: atacmds.cpp:787
int ataDisableAutoOffline(ata_device *device)
Definition: atacmds.cpp:1581
unsigned char ata_return_temperature_value(const ata_smart_values *data, const ata_vendor_attr_defs &defs)
Definition: atacmds.cpp:2159
bool isSmartErrorLogCapable(const ata_smart_values *data, const ata_identify_device *identity)
Definition: atacmds.cpp:1731
int ata_get_wwn(const ata_identify_device *id, unsigned &oui, uint64_t &unique_id)
Definition: atacmds.cpp:900
int ataEnableAutoOffline(ata_device *device)
Definition: atacmds.cpp:1570
int ataSmartStatus2(ata_device *device)
Definition: atacmds.cpp:1604
int ataSmartSupport(const ata_identify_device *drive)
Definition: atacmds.cpp:936
int ataDisableAutoSave(ata_device *device)
Definition: atacmds.cpp:1558
int ata_get_rotation_rate(const ata_identify_device *id)
Definition: atacmds.cpp:920
unsigned char get_unc_attr_id(bool offline, const ata_vendor_attr_defs &defs, bool &increase)
Definition: atacmds.cpp:53
bool parse_attribute_def(const char *opt, ata_vendor_attr_defs &defs, ata_vendor_def_prior priority)
Definition: atacmds.cpp:149
int ataEnableAutoSave(ata_device *device)
Definition: atacmds.cpp:1551
int ataReadSelfTestLog(ata_device *device, ata_smart_selftestlog *data, firmwarebug_defs firmwarebugs)
Definition: atacmds.cpp:1013
std::string ata_format_attr_raw_value(const ata_smart_attribute &attr, const ata_vendor_attr_defs &defs)
Definition: atacmds.cpp:1920
int ata_find_attr_index(unsigned char id, const ata_smart_values &smartval)
Definition: atacmds.cpp:2146
int ataReadErrorLog(ata_device *device, ata_smart_errorlog *data, firmwarebug_defs firmwarebugs)
Definition: atacmds.cpp:1424
void ata_get_size_info(const ata_identify_device *id, ata_size_info &sizes)
Definition: atacmds.cpp:658
int ata_read_identity(ata_device *device, ata_identify_device *buf, bool fix_swapped_id, unsigned char *raw_buf)
Definition: atacmds.cpp:817
int ataEnableSmart(ata_device *device)
Definition: atacmds.cpp:1536
int smartcommandhandler(ata_device *device, smart_command_set command, int select, char *data)
Definition: atacmds.cpp:431
bool isGeneralPurposeLoggingCapable(const ata_identify_device *identity)
Definition: atacmds.cpp:1769
int ataCheckPowerMode(ata_device *device)
Definition: atacmds.cpp:777
std::string create_vendor_attribute_arg_list()
Definition: atacmds.cpp:262
bool isSmartTestLogCapable(const ata_smart_values *data, const ata_identify_device *identity)
Definition: atacmds.cpp:1750
int ataReadSmartValues(ata_device *device, struct ata_smart_values *data)
Definition: atacmds.cpp:967
bool parse_firmwarebug_def(const char *opt, firmwarebug_defs &firmwarebugs)
Definition: atacmds.cpp:277
int ataSetSCTErrorRecoveryControltime(ata_device *device, unsigned type, unsigned short time_limit, bool power_on, bool mfg_default)
Definition: atacmds.cpp:2516
unsigned char ata_debugmode
Definition: atacmds.cpp:33
const char * get_valid_firmwarebug_args()
Definition: atacmds.cpp:297
uint64_t ata_get_attr_raw_value(const ata_smart_attribute &attr, const ata_vendor_attr_defs &defs)
Definition: atacmds.cpp:1846
bool ataReadExtErrorLog(ata_device *device, ata_smart_exterrlog *log, unsigned page, unsigned nsectors, firmwarebug_defs firmwarebugs)
Definition: atacmds.cpp:1491
int ataWriteSelectiveSelfTestLog(ata_device *device, ata_selective_selftest_args &args, const ata_smart_values *sv, uint64_t num_sectors, const ata_selective_selftest_args *prev_args)
Definition: atacmds.cpp:1213
std::string ata_get_smart_attr_name(unsigned char id, const ata_vendor_attr_defs &defs, int rpm)
Definition: atacmds.cpp:2127
int ataReadSmartThresholds(ata_device *device, struct ata_smart_thresholds_pvt *data)
Definition: atacmds.cpp:1518
int ataIsSmartEnabled(const ata_identify_device *drive)
Definition: atacmds.cpp:951
void ata_format_id_string(char *out, const unsigned char *in, int n)
Definition: atacmds.cpp:762
int ataReadLogDirectory(ata_device *device, ata_smart_log_directory *data, bool gpl)
Definition: atacmds.cpp:1164
bool ata_set_features(ata_device *device, unsigned char features, int sector_count)
Definition: atacmds.cpp:799
ata_attr_state ata_get_attr_state(const ata_smart_attribute &attr, int attridx, const ata_smart_threshold_entry *thresholds, const ata_vendor_attr_defs &defs, unsigned char *threshval)
Definition: atacmds.cpp:1796
#define ATA_ENABLE_READ_LOOK_AHEAD
Definition: atacmds.h:72
#define ATA_DISABLE_WRITE_CACHE
Definition: atacmds.h:67
bool isSupportSelfTest(const ata_smart_values *data)
Definition: atacmds.h:877
#define SELECTIVE_SELF_TEST
Definition: atacmds.h:101
bool isSCTErrorRecoveryControlCapable(const ata_identify_device *drive)
Definition: atacmds.h:889
#define ATA_ENABLE_APM
Definition: atacmds.h:70
#define ATA_DISABLE_AAM
Definition: atacmds.h:65
#define OFFLINE_FULL_SCAN
Definition: atacmds.h:97
#define SHORT_SELF_TEST
Definition: atacmds.h:98
bool isSupportConveyanceSelfTest(const ata_smart_values *data)
Definition: atacmds.h:880
#define ATA_ENABLE_DISABLE_DSN
Definition: atacmds.h:73
#define ATA_IDLE
Definition: atacmds.h:55
bool isSupportAutomaticTimer(const ata_smart_values *data)
Definition: atacmds.h:868
#define EXTEND_SELF_TEST
Definition: atacmds.h:99
#define ATA_ENABLE_WRITE_CACHE
Definition: atacmds.h:71
bool isSupportSelectiveSelfTest(const ata_smart_values *data)
Definition: atacmds.h:883
#define ATA_DISABLE_READ_LOOK_AHEAD
Definition: atacmds.h:68
#define ATTRIBUTE_FLAGS_PREFAILURE(x)
Definition: atacmds.h:164
@ PRIOR_USER
Definition: atacmds.h:644
#define ATA_ENABLE_AAM
Definition: atacmds.h:69
bool isSupportExecuteOfflineImmediate(const ata_smart_values *data)
Definition: atacmds.h:862
@ IMMEDIATE_OFFLINE
Definition: atacmds.h:34
#define CONVEYANCE_SELF_TEST
Definition: atacmds.h:100
@ BUG_SAMSUNG3
Definition: atacmds.h:717
@ BUG_NOLOGDIR
Definition: atacmds.h:714
#define ATA_SECURITY_FREEZE_LOCK
Definition: atacmds.h:57
@ SEL_REDO
Definition: atacmds.h:607
@ SEL_NEXT
Definition: atacmds.h:608
@ SEL_CONT
Definition: atacmds.h:609
#define ATA_DISABLE_APM
Definition: atacmds.h:66
#define NUMBER_ATA_SMART_ATTRIBUTES
Definition: atacmds.h:110
ata_attr_state
Definition: atacmds.h:902
@ ATTRSTATE_FAILED_NOW
Definition: atacmds.h:908
@ ATTRSTATE_NON_EXISTING
Definition: atacmds.h:903
@ ATTRSTATE_NO_NORMVAL
Definition: atacmds.h:904
Smart pointer class for device pointers.
void replace(device_type *dev)
Replace the pointer.
ATA device access.
unsigned char m_flags[256]
Definition: smartd.cpp:370
bool is_set(int id, unsigned char flag) const
Definition: smartd.cpp:360
void set(int id, unsigned char flags)
Definition: smartd.cpp:363
env_buffer()=default
env_buffer(const env_buffer &)=delete
char * m_buf
Definition: smartd.cpp:1098
void set(const char *name, const char *value)
Definition: smartd.cpp:1101
void operator=(const env_buffer &)=delete
bool is_set(firmwarebug_t bug) const
Definition: atacmds.h:728
NVMe device access.
unsigned get_nsid() const
Get namespace id.
unsigned char * data()
Definition: utility.h:148
Wrapper class for POSIX regex(3) or std::regex Supports copy & assignment and is compatible with STL ...
Definition: utility.h:222
bool full_match(const char *str) const
Return true if full string matches pattern.
Definition: utility.cpp:593
regmatch_t match_range
Definition: utility.h:262
const char * get_errmsg() const
Get error message from last compile().
Definition: utility.h:249
bool empty() const
Definition: utility.h:253
const char * get_pattern() const
Definition: utility.h:245
bool compile(const char *pattern)
Set and compile new pattern, return false on error.
Definition: utility.cpp:547
bool execute(const char *str, unsigned nmatch, match_range *pmatch) const
Return true if substring matches pattern, fill match_range array.
Definition: utility.cpp:604
SCSI device access.
bool use_rcap16() const
List of devices for DEVICESCAN.
unsigned size() const
void push_back(smart_device *dev)
smart_device * release(unsigned i)
Base class for all devices.
Definition: dev_interface.h:33
bool is_scsi() const
Return true if SCSI device.
Definition: dev_interface.h:89
virtual bool is_powered_down()
Early test if device is powered up or down.
bool is_nvme() const
Return true if NVMe device.
Definition: dev_interface.h:92
const device_info & get_info() const
Get device info struct.
const char * get_errmsg() const
Get last error message.
virtual bool close()=0
Close device, return false on error.
nvme_device * to_nvme()
Downcast to NVMe device.
ata_device * to_ata()
Downcast to ATA device.
Definition: dev_interface.h:96
scsi_device * to_scsi()
Downcast to SCSI device.
static int get_num_objects()
Get current number of allocated 'smart_device' objects.
bool is_ata() const
Return true if ATA device.
Definition: dev_interface.h:86
virtual bool open()=0
Open device, return false on error.
virtual std::string get_unique_dev_name(const char *name, const char *type) const
Return unique device name which is (only) suitable for duplicate detection.
virtual smart_device * get_smart_device(const char *name, const char *type)
Return device object for device 'name' with some 'type'.
static void init()
Initialize platform interface and register with smi().
Definition: dev_legacy.cpp:334
Wrapper class for FILE *.
Definition: utility.h:163
bool close()
Definition: utility.h:194
bool open(const char *name, const char *mode)
Definition: utility.h:177
std::vector< std::string > smart_devtype_list
List of types for DEVICESCAN.
smart_interface * smi()
Global access to the (usually singleton) smart_interface.
const drive_settings * lookup_drive_apply_presets(const ata_identify_device *drive, ata_vendor_attr_defs &defs, firmwarebug_defs &firmwarebugs, std::string &dbversion)
bool init_drive_database(bool use_default_db)
const char * get_drivedb_path_add()
static bool match(const char *pattern, const char *str)
void show_presets(const ata_identify_device *drive)
bool read_drive_database(const char *path)
int showallpresets()
u16 flags
Definition: megaraid.h:14
u32 count
Definition: megaraid.h:1
u32 w[3]
Definition: megaraid.h:19
u8 b[12]
Definition: megaraid.h:17
ptr_t buffer
Definition: megaraid.h:3
u16 s[6]
Definition: megaraid.h:18
ptr_t data
Definition: megaraid.h:15
u32 size
Definition: megaraid.h:0
uint8_t id
uint32_t nsid
union @43 entry
bool nvme_read_self_test_log(nvme_device *device, uint32_t nsid, smartmontools::nvme_self_test_log &self_test_log)
Definition: nvmecmds.cpp:270
int nvme_status_to_errno(uint16_t status)
Definition: nvmecmds.cpp:472
bool nvme_read_id_ctrl(nvme_device *device, nvme_id_ctrl &id_ctrl)
Definition: nvmecmds.cpp:132
unsigned char nvme_debugmode
Definition: nvmecmds.cpp:27
bool nvme_self_test(nvme_device *device, uint8_t stc, uint32_t nsid)
Definition: nvmecmds.cpp:285
unsigned nvme_read_error_log(nvme_device *device, nvme_error_log_page *error_log, unsigned num_entries, bool lpo_sup)
Definition: nvmecmds.cpp:231
bool nvme_read_smart_log(nvme_device *device, uint32_t nsid, nvme_smart_log &smart_log)
Definition: nvmecmds.cpp:254
const char * nvme_status_to_info_str(char *buf, size_t bufsize, uint16_t status)
Definition: nvmecmds.cpp:490
constexpr bool nvme_status_is_error(uint16_t status)
Definition: nvmecmds.h:288
constexpr uint32_t nvme_broadcast_nsid
Definition: nvmecmds.h:257
static struct @44 devices[20]
std::string get_exe_dir()
Definition: os_win32.cpp:4844
#define _WIN32
Definition: os_win32.cpp:54
FILE * popen_as_ugid(const char *cmd, const char *mode, uid_t uid, gid_t gid)
int pclose_as_ugid(FILE *f)
const char * parse_ugid(const char *s, uid_t &uid, gid_t &gid, std::string &uname, std::string &gname)
void scsiDecodeErrCounterPage(unsigned char *resp, struct scsiErrorCounter *ecp, int allocLen)
Definition: scsicmds.cpp:2628
int scsiFetchIECmpage(scsi_device *device, struct scsi_iec_mode_page *iecp, int modese_len)
Definition: scsicmds.cpp:1857
int scsi_decode_lu_dev_id(const unsigned char *b, int blen, char *s, int slen, int *transport)
Definition: scsicmds.cpp:748
int scsiTestUnitReady(scsi_device *device)
Definition: scsicmds.cpp:1475
int scsiInquiryVpd(scsi_device *device, int vpd_page, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1229
int scsiSmartExtendSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2528
void scsiDecodeNonMediumErrPage(unsigned char *resp, struct scsiNonMediumError *nmep, int allocLen)
Definition: scsicmds.cpp:2673
int scsiCheckIE(scsi_device *device, int hasIELogPage, int hasTempLogPage, uint8_t *asc, uint8_t *ascq, uint8_t *currenttemp, uint8_t *triptemp)
Definition: scsicmds.cpp:2047
uint64_t scsiGetSize(scsi_device *device, bool avoid_rcap16, struct scsi_readcap_resp *srrp)
Definition: scsicmds.cpp:1732
int scsiSelfTestInProgress(scsi_device *fd, int *inProgress)
Definition: scsicmds.cpp:2792
char * scsiGetIEString(uint8_t asc, uint8_t ascq, char *b, int blen)
Definition: scsicmds.cpp:3217
supported_vpd_pages * supported_vpd_pages_p
Definition: scsicmds.cpp:47
void scsi_format_id_string(char *out, const uint8_t *in, int n)
Definition: scsicmds.cpp:3136
int scsiStdInquiry(scsi_device *device, uint8_t *pBuf, int bufLen)
Definition: scsicmds.cpp:1182
int scsiCountFailedSelfTests(scsi_device *fd, int noisy)
Definition: scsicmds.cpp:2741
int scsiSetControlGLTSD(scsi_device *device, int enabled, int modese_len)
Definition: scsicmds.cpp:3006
int scsi_IsExceptionControlEnabled(const struct scsi_iec_mode_page *iecp)
Definition: scsicmds.cpp:1904
int scsiSmartShortSelfTest(scsi_device *device)
Definition: scsicmds.cpp:2517
int scsiLogSense(scsi_device *device, int pagenum, int subpagenum, uint8_t *pBuf, int bufLen, int known_resp_len)
Definition: scsicmds.cpp:892
unsigned char scsi_debugmode
Definition: scsicmds.cpp:45
#define SIMPLE_ERR_BECOMING_READY
Definition: scsicmds.h:354
#define SIMPLE_ERR_BAD_FIELD
Definition: scsicmds.h:350
#define LOGPAGEHDRSIZE
Definition: scsicmds.h:385
#define SIMPLE_ERR_NOT_READY
Definition: scsicmds.h:348
#define SCSI_VPD_DEVICE_IDENTIFICATION
Definition: scsicmds.h:309
#define SIMPLE_ERR_NO_MEDIUM
Definition: scsicmds.h:353
#define SCSI_PT_CDROM
Definition: scsicmds.h:194
#define VERIFY_ERROR_COUNTER_LPAGE
Definition: scsicmds.h:223
#define SUPPORTED_LPAGES
Definition: scsicmds.h:218
#define SIMPLE_ERR_BAD_OPCODE
Definition: scsicmds.h:349
#define NON_MEDIUM_ERROR_LPAGE
Definition: scsicmds.h:224
#define SCSI_VPD_UNIT_SERIAL_NUMBER
Definition: scsicmds.h:308
#define SCSI_PT_HOST_MANAGED
Definition: scsicmds.h:199
#define SCSI_PT_WO
Definition: scsicmds.h:193
#define SCSI_PT_RBC
Definition: scsicmds.h:198
#define TEMPERATURE_LPAGE
Definition: scsicmds.h:229
#define WRITE_ERROR_COUNTER_LPAGE
Definition: scsicmds.h:220
#define SCSI_PT_DIRECT_ACCESS
Definition: scsicmds.h:191
#define READ_ERROR_COUNTER_LPAGE
Definition: scsicmds.h:221
#define IE_LPAGE
Definition: scsicmds.h:241
#define SCSI_PT_OPTICAL
Definition: scsicmds.h:195
static uint64_t sg_get_unaligned_le64(const void *p)
Definition: sg_unaligned.h:303
static void sg_put_unaligned_le64(uint64_t val, void *p)
Definition: sg_unaligned.h:321
static uint16_t sg_get_unaligned_le16(const void *p)
Definition: sg_unaligned.h:292
#define EXIT_BADCONF
Definition: smartd.cpp:127
static int CloseDevice(smart_device *device, const char *name)
Definition: smartd.cpp:1795
#define EXIT_SIGNAL
Definition: smartd.cpp:139
static bool is_duplicate_dev_idinfo(const dev_config &cfg, const dev_config_vector &prev_cfgs)
Definition: smartd.cpp:2018
static void reset_warning_mail(const dev_config &cfg, dev_state &state, int which, const char *fmt,...) __attribute_format_printf(4
Definition: smartd.cpp:1365
unsigned char failuretest_permissive
Definition: smartd.cpp:205
#define SIGQUIT_KEYNAME
Definition: smartd.cpp:90
const bool fix_swapped_id
Definition: smartd.cpp:2041
static std::string state_path_prefix
Definition: smartd.cpp:158
static bool write_dev_state(const char *path, const persistent_dev_state &state)
Definition: smartd.cpp:798
static int NVMeDeviceScan(dev_config &cfg, dev_state &state, nvme_device *nvmedev, const dev_config_vector *prev_cfgs)
Definition: smartd.cpp:2825
static std::string configfile_alt
Definition: smartd.cpp:172
static int Get3Integers(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile, unsigned char *val1, unsigned char *val2, unsigned char *val3)
Definition: smartd.cpp:4618
static int facility
Definition: smartd.cpp:197
static void log_nvme_smart_change(const dev_config &cfg, dev_state &state, const char *valname, uint64_t oldval, uint64_t newval, bool critical, bool info=true)
Definition: smartd.cpp:4002
#define EXIT_BADDEV
Definition: smartd.cpp:136
#define EXIT_NODEV
Definition: smartd.cpp:137
static void sighandler(int sig)
Definition: smartd.cpp:1028
static int check_ata_self_test_log(ata_device *device, const char *name, firmwarebug_defs firmwarebugs, unsigned &hour)
Definition: smartd.cpp:1855
static const int MAILTYPE_TEST
Definition: smartd.cpp:452
static void do_disable_standby_check(const dev_config_vector &configs, const dev_state_vector &states)
Definition: smartd.cpp:4325
static void log_self_test_exec_status(const char *name, unsigned char status)
Definition: smartd.cpp:1932
const char * fmt
Definition: smartd.cpp:1394
static void check_attribute(const dev_config &cfg, dev_state &state, const ata_smart_attribute &attr, const ata_smart_attribute &prev, int attridx, const ata_smart_threshold_entry *thresholds)
Definition: smartd.cpp:3562
static void log_offline_data_coll_status(const char *name, unsigned char status)
Definition: smartd.cpp:1909
static void notify_exit(int)
Definition: smartd.cpp:336
static void write_all_dev_attrlogs(const dev_config_vector &configs, dev_state_vector &states)
Definition: smartd.cpp:979
int main(int argc, char **argv)
Definition: smartd.cpp:6305
static int ReadOrMakeConfigEntries(dev_config_vector &conf_entries, smart_device_list &scanned_devs)
Definition: smartd.cpp:5878
static void report_self_test_log_changes(const dev_config &cfg, dev_state &state, int errcnt, uint64_t hour)
Definition: smartd.cpp:3035
static quit_t quit
Definition: smartd.cpp:193
static void write_dev_state_line(FILE *f, const char *name, uint64_t val)
Definition: smartd.cpp:785
static time_t dosleep(time_t wakeuptime, const dev_config_vector &configs, dev_state_vector &states, bool &sigwakeup)
Definition: smartd.cpp:4451
static void notify_extend_timeout()
Definition: smartd.cpp:332
static void check_pending(const dev_config &cfg, dev_state &state, unsigned char id, bool increase_only, const ata_smart_values &smartval, int mailtype, const char *msg)
Definition: smartd.cpp:3446
static void PrintTestSchedule(const dev_config_vector &configs, dev_state_vector &states, const smart_device_list &devices)
Definition: smartd.cpp:3214
static bool check_abs_path(char option, const std::string &path)
Definition: smartd.cpp:5451
static bool register_device(dev_config &cfg, dev_state &state, smart_device_auto_ptr &dev, const dev_config_vector *prev_cfgs)
Definition: smartd.cpp:5923
static void MailWarning(const dev_config &cfg, dev_state &state, int which, const char *fmt,...) __attribute_format_printf(4
Definition: smartd.cpp:1122
static void init_disable_standby_check(const dev_config_vector &configs)
Definition: smartd.cpp:4297
static void notify_init()
Definition: smartd.cpp:331
static void install_signal_handlers()
Definition: smartd.cpp:4401
static void capabilities_drop_now()
Definition: smartd.cpp:1074
static void PrintValidArgs(char opt)
Definition: smartd.cpp:5437
#define EXIT_BADCMD
Definition: smartd.cpp:126
#define EXIT_NOCONF
Definition: smartd.cpp:130
const char * smartd_cpp_cvsid
Definition: smartd.cpp:93
static int NVMeCheckDevice(const dev_config &cfg, dev_state &state, nvme_device *nvmedev, bool firstpass, bool allow_selftests)
Definition: smartd.cpp:4161
static void notify_check(int)
Definition: smartd.cpp:334
#define SCANDIRECTIVE
Definition: smartd.cpp:5190
static std::string attrlog_path_prefix
Definition: smartd.cpp:165
static bool WaitForPidFile()
Definition: smartd.cpp:1482
static void notify_wait(time_t, int)
Definition: smartd.cpp:335
void checksumwarning(const char *string)
Definition: smartd.cpp:1473
static volatile int caughtsigEXIT
Definition: smartd.cpp:220
static int ParseConfigFile(dev_config_vector &conf_entries, smart_devtype_list &scan_types)
Definition: smartd.cpp:5302
static uint64_t le128_to_uint64(const unsigned char(&val)[16])
Definition: smartd.cpp:626
void(* signal_handler_type)(int)
Definition: smartd.cpp:97
static void write_scsi_attrlog(FILE *f, const dev_state &state)
Definition: smartd.cpp:863
#define EXIT_PID
Definition: smartd.cpp:129
vsnprintf(buf, sizeof(buf), fmt, ap)
static int standby_disable_state
Definition: smartd.cpp:4295
static void notify_msg(const char *)
Definition: smartd.cpp:333
static int checktime
Definition: smartd.cpp:147
static void write_nvme_attrlog(FILE *f, const dev_state &state)
Definition: smartd.cpp:893
static int SCSICheckDevice(const dev_config &cfg, dev_state &state, scsi_device *scsidev, bool allow_selftests)
Definition: smartd.cpp:3903
static int ParseConfigLine(dev_config_vector &conf_entries, dev_config &default_conf, smart_devtype_list &scan_types, int lineno, char *line)
Definition: smartd.cpp:5201
static const char * GetValidArgList(char opt)
Definition: smartd.cpp:1665
static const char test_type_chars[]
Definition: smartd.cpp:3086
static void write_ata_attrlog(FILE *f, const dev_state &state)
Definition: smartd.cpp:854
static bool write_dev_attrlog(const char *path, const dev_state &state)
Definition: smartd.cpp:932
static void CheckDevicesOnce(const dev_config_vector &configs, dev_state_vector &states, smart_device_list &devices, bool firstpass, bool allow_selftests)
Definition: smartd.cpp:4372
static const char * configfile
Definition: smartd.cpp:168
static const char *const configfile_stdin
Definition: smartd.cpp:170
static const char * fmt_temp(unsigned char x, char(&buf)[20])
Definition: smartd.cpp:3479
static void write_all_dev_states(const dev_config_vector &configs, dev_state_vector &states, bool write_always=true)
Definition: smartd.cpp:958
static void static bool notify_post_init()
Definition: smartd.cpp:320
static void uint64_to_le128(unsigned char(&destval)[16], uint64_t srcval)
Definition: smartd.cpp:634
static bool check_pending_id(const dev_config &cfg, const dev_state &state, unsigned char id, const char *msg)
Definition: smartd.cpp:1960
quit_t
Definition: smartd.cpp:189
@ QUIT_NODEVSTARTUP
Definition: smartd.cpp:190
@ QUIT_NEVER
Definition: smartd.cpp:190
@ QUIT_ERRORS
Definition: smartd.cpp:191
@ QUIT_ONECHECK
Definition: smartd.cpp:190
@ QUIT_SHOWTESTS
Definition: smartd.cpp:191
@ QUIT_NODEV
Definition: smartd.cpp:190
static bool not_allowed_in_filename(char c)
Definition: smartd.cpp:1822
static int SCSIDeviceScan(dev_config &cfg, dev_state &state, scsi_device *scsidev, const dev_config_vector *prev_cfgs)
Definition: smartd.cpp:2492
static bool do_fork
Definition: smartd.cpp:201
static void capabilities_log_error_hint()
Definition: smartd.cpp:1075
static void PrintHead()
Definition: smartd.cpp:1610
static char next_scheduled_test(const dev_config &cfg, dev_state &state, time_t usetime=0)
Definition: smartd.cpp:3091
static void CheckTemperature(const dev_config &cfg, dev_state &state, unsigned char currtemp, unsigned char triptemp)
Definition: smartd.cpp:3488
static int parse_options(int argc, char **argv)
Definition: smartd.cpp:5466
static unsigned char debugmode
Definition: smartd.cpp:143
static bool read_dev_state(const char *path, persistent_dev_state &state)
Definition: smartd.cpp:747
static int DoATASelfTest(const dev_config &cfg, dev_state &state, ata_device *device, char testtype)
Definition: smartd.cpp:3327
static void printoutvaliddirectiveargs(int priority, char d)
Definition: smartd.cpp:4539
static bool write_pid_file()
Definition: smartd.cpp:1586
#define EXIT_BADCODE
Definition: smartd.cpp:134
static time_t calc_next_wakeuptime(time_t wakeuptime, time_t timenow, int ct)
Definition: smartd.cpp:4444
static std::string pid_file
Definition: smartd.cpp:151
static int daemon_init()
Definition: smartd.cpp:1505
static bool is_offl_coll_in_progress(unsigned char status)
Definition: smartd.cpp:1897
static void USR1handler(int sig)
Definition: smartd.cpp:1000
static bool open_device(const dev_config &cfg, dev_state &state, smart_device *device, const char *type)
Definition: smartd.cpp:2972
static int ATACheckDevice(const dev_config &cfg, dev_state &state, ata_device *atadev, bool firstpass, bool allow_selftests)
Definition: smartd.cpp:3659
const char va_list ap
Definition: smartd.cpp:1395
static int check_nvme_self_test_log(uint32_t nsid, const nvme_self_test_log &self_test_log, uint64_t &hour)
Definition: smartd.cpp:4088
static int main_worker(int argc, char **argv)
Definition: smartd.cpp:6109
static bool quit_nodev0
Definition: smartd.cpp:194
static void Directives()
Definition: smartd.cpp:1616
static bool register_devices(const dev_config_vector &conf_entries, smart_device_list &scanned_devs, dev_config_vector &configs, dev_state_vector &states, smart_device_list &devices)
Definition: smartd.cpp:6008
std::vector< dev_config > dev_config_vector
Container for configuration info for each device.
Definition: smartd.cpp:573
static void HUPhandler(int sig)
Definition: smartd.cpp:1018
static int read_ata_error_count(ata_device *device, const char *name, firmwarebug_defs firmwarebugs, bool extended)
Definition: smartd.cpp:1831
static constexpr int default_checktime
Definition: smartd.cpp:146
static int GetInteger(const char *arg, const char *name, const char *token, int lineno, const char *cfgfile, int min, int max, char *suffix=0)
Definition: smartd.cpp:4584
static const int SMARTD_NMAIL
Definition: smartd.cpp:450
#define EXIT_READCONF
Definition: smartd.cpp:131
static void PrintOut(int priority, const char *fmt,...) __attribute_format_printf(2
Definition: smartd.cpp:1447
static void log_nvme_self_test_exec_status(const char *name, dev_state &state, bool firstpass, const nvme_self_test_log &self_test_log)
Definition: smartd.cpp:4022
emailfreqs
Definition: smartd.cpp:341
static const unsigned num_test_types
Definition: smartd.cpp:3087
static void Usage()
Definition: smartd.cpp:1703
static void format_set_result_msg(std::string &msg, const char *name, bool ok, int set_option=0, bool has_value=false)
Definition: smartd.cpp:2001
static int checktime_min
Definition: smartd.cpp:148
static int DoSCSISelfTest(const dev_config &cfg, dev_state &state, scsi_device *device, char testtype)
Definition: smartd.cpp:3268
static void set_signal_if_not_ignored(int sig, signal_handler_type handler)
Definition: smartd.cpp:100
@ MONITOR_RAW
Definition: smartd.cpp:351
@ MONITOR_RAW_PRINT
Definition: smartd.cpp:350
@ MONITOR_RAW_AS_CRIT
Definition: smartd.cpp:353
@ MONITOR_IGN_FAILUSE
Definition: smartd.cpp:348
@ MONITOR_IGNORE
Definition: smartd.cpp:349
@ MONITOR_AS_CRIT
Definition: smartd.cpp:352
static int ATADeviceScan(dev_config &cfg, dev_state &state, ata_device *atadev, const dev_config_vector *prev_cfgs)
Definition: smartd.cpp:2044
std::vector< dev_state > dev_state_vector
Container for state info for each device.
Definition: smartd.cpp:576
void pout(const char *fmt,...)
Definition: smartd.cpp:1419
static bool is_self_test_in_progress(unsigned char status)
Definition: smartd.cpp:1903
#define EXIT_NOMEM
Definition: smartd.cpp:133
static void finish_device_scan(dev_config &cfg, dev_state &state)
Definition: smartd.cpp:1984
#define EBUFLEN
Definition: smartd.cpp:1115
static bool check_nvme_error_log(const dev_config &cfg, dev_state &state, nvme_device *nvmedev, uint64_t newcnt=0)
Definition: smartd.cpp:2758
static bool parse_dev_state_line(const char *line, persistent_dev_state &state)
Definition: smartd.cpp:641
static const int scsiLogRespLen
Definition: smartd.cpp:123
static std::string warning_script
Definition: smartd.cpp:175
#define EXIT_STARTUP
Definition: smartd.cpp:128
static volatile int caughtsigUSR1
Definition: smartd.cpp:208
static int MakeConfigEntries(const dev_config &base_cfg, dev_config_vector &conf_entries, smart_device_list &scanned_devs, const smart_devtype_list &types)
Definition: smartd.cpp:5834
static int start_nvme_self_test(const dev_config &cfg, dev_state &state, nvme_device *device, char testtype, const nvme_self_test_log &self_test_log)
Definition: smartd.cpp:4123
static int ParseToken(char *&token, dev_config &cfg, smart_devtype_list &scan_types)
Definition: smartd.cpp:4673
static bool sanitize_dev_idinfo(std::string &s)
Definition: smartd.cpp:1806
static volatile int caughtsigHUP
Definition: smartd.cpp:217
#define STATIC_ASSERT(x)
Definition: static_assert.h:24
unsigned char model[40]
Definition: atacmds.h:120
unsigned short words088_255[168]
Definition: atacmds.h:130
unsigned char fw_rev[8]
Definition: atacmds.h:119
unsigned char serial_no[20]
Definition: atacmds.h:117
uint64_t capacity
Definition: atacmds.h:986
uint64_t sectors
Definition: atacmds.h:985
unsigned char id
Definition: atacmds.h:138
unsigned char current
Definition: atacmds.h:142
unsigned short flags
Definition: atacmds.h:141
unsigned char reserv
Definition: atacmds.h:145
unsigned char worst
Definition: atacmds.h:143
unsigned char raw[6]
Definition: atacmds.h:144
unsigned short int ata_error_count
Definition: atacmds.h:302
unsigned char error_log_pointer
Definition: atacmds.h:300
unsigned short error_log_index
Definition: atacmds.h:383
unsigned char reserved1
Definition: atacmds.h:382
unsigned short device_error_count
Definition: atacmds.h:385
struct ata_smart_log_entry entry[255]
Definition: atacmds.h:467
unsigned char numsectors
Definition: atacmds.h:458
unsigned char mostrecenttest
Definition: atacmds.h:412
struct ata_smart_selftestlog_struct selftest_struct[21]
Definition: atacmds.h:410
Definition: atacmds.h:231
struct ata_smart_threshold_entry thres_entries[NUMBER_ATA_SMART_ATTRIBUTES]
Definition: atacmds.h:244
unsigned char self_test_exec_status
Definition: atacmds.h:202
unsigned char offline_data_collection_capability
Definition: atacmds.h:205
unsigned char offline_data_collection_status
Definition: atacmds.h:201
struct ata_smart_attribute vendor_attributes[NUMBER_ATA_SMART_ATTRIBUTES]
Definition: atacmds.h:200
Configuration data for a device.
Definition: smartd.cpp:377
bool ignorepresets
Definition: smartd.cpp:405
std::string emailcmdline
Definition: smartd.cpp:417
bool offlinests
Definition: smartd.cpp:397
char powermode
Definition: smartd.cpp:408
bool ignore
Definition: smartd.cpp:387
ata_vendor_attr_defs attribute_defs
Definition: smartd.cpp:443
bool smartcheck
Definition: smartd.cpp:389
int set_wcache
Definition: smartd.cpp:429
int powerskipmax
Definition: smartd.cpp:410
char autoofflinetest
Definition: smartd.cpp:403
unsigned char tempdiff
Definition: smartd.cpp:411
int set_standby
Definition: smartd.cpp:427
int dev_rpm
Definition: smartd.cpp:423
unsigned short sct_erc_readtime
Definition: smartd.cpp:433
uint8_t smartcheck_nvme
Definition: smartd.cpp:390
std::string state_file
Definition: smartd.cpp:384
int set_dsn
Definition: smartd.cpp:430
bool errorlog
Definition: smartd.cpp:395
std::string dev_idinfo_bc
Definition: smartd.cpp:383
std::string dev_idinfo
Definition: smartd.cpp:382
bool powerquiet
Definition: smartd.cpp:409
attribute_flags monitor_attr_flags
Definition: smartd.cpp:441
unsigned nvme_err_log_max_entries
Definition: smartd.cpp:446
unsigned test_offset_factor
Definition: smartd.cpp:414
firmwarebug_defs firmwarebugs
Definition: smartd.cpp:404
bool showpresets
Definition: smartd.cpp:406
bool removable
Definition: smartd.cpp:407
unsigned char offl_pending_id
Definition: smartd.cpp:437
unsigned char tempcrit
Definition: smartd.cpp:412
bool offlinests_ns
Definition: smartd.cpp:398
bool curr_pending_set
Definition: smartd.cpp:439
unsigned short sct_erc_writetime
Definition: smartd.cpp:434
bool sct_erc_set
Definition: smartd.cpp:432
int set_aam
Definition: smartd.cpp:424
bool selfteststs
Definition: smartd.cpp:399
unsigned char curr_pending_id
Definition: smartd.cpp:436
bool selftest
Definition: smartd.cpp:394
bool id_is_unique
Definition: smartd.cpp:388
std::string name
Definition: smartd.cpp:379
std::string emailaddress
Definition: smartd.cpp:418
bool offl_pending_incr
Definition: smartd.cpp:438
int lineno
Definition: smartd.cpp:378
int checktime
Definition: smartd.cpp:386
bool prefail
Definition: smartd.cpp:392
bool xerrorlog
Definition: smartd.cpp:396
int set_lookahead
Definition: smartd.cpp:426
bool usage
Definition: smartd.cpp:393
std::string attrlog_file
Definition: smartd.cpp:385
regular_expression test_regex
Definition: smartd.cpp:413
bool emailtest
Definition: smartd.cpp:420
bool set_security_freeze
Definition: smartd.cpp:428
bool usagefailed
Definition: smartd.cpp:391
std::string dev_name
Definition: smartd.cpp:380
emailfreqs emailfreq
Definition: smartd.cpp:419
bool selfteststs_ns
Definition: smartd.cpp:400
unsigned char tempinfo
Definition: smartd.cpp:412
bool permissive
Definition: smartd.cpp:401
char autosave
Definition: smartd.cpp:402
int set_apm
Definition: smartd.cpp:425
bool offl_pending_set
Definition: smartd.cpp:439
std::string dev_type
Definition: smartd.cpp:381
bool curr_pending_incr
Definition: smartd.cpp:438
Runtime state data for a device.
Definition: smartd.cpp:567
void update_temp_state()
Definition: smartd.cpp:602
void update_persistent_state()
Definition: smartd.cpp:579
const char * modelfamily
Definition: knowndrives.h:19
const char * warningmsg
Definition: knowndrives.h:22
time_t lastsent
Definition: smartd.cpp:458
int logged
Definition: smartd.cpp:456
time_t firstsent
Definition: smartd.cpp:457
Persistent state data for a device.
Definition: smartd.cpp:463
scsi_nonmedium_error_t scsi_nonmedium_error
Definition: smartd.cpp:502
nvme_smart_log nvme_smartval
Definition: smartd.cpp:509
unsigned char selflogcount
Definition: smartd.cpp:466
uint64_t selfloghour
Definition: smartd.cpp:467
unsigned char tempmax
Definition: smartd.cpp:464
uint64_t nvme_err_log_entries
Definition: smartd.cpp:505
uint64_t selective_test_last_end
Definition: smartd.cpp:473
ata_attribute ata_attributes[NUMBER_ATA_SMART_ATTRIBUTES]
Definition: smartd.cpp:488
uint64_t selective_test_last_start
Definition: smartd.cpp:472
unsigned char tempmin
Definition: smartd.cpp:464
mailinfo maillog[SMARTD_NMAIL]
Definition: smartd.cpp:475
time_t scheduled_test_next_check
Definition: smartd.cpp:470
scsi_error_counter_t scsi_error_counters[3]
Definition: smartd.cpp:496
uint64_t counter[8]
Definition: scsicmds.h:158
uint8_t modese_len
Definition: scsicmds.h:149
Device info strings.
Definition: dev_interface.h:37
std::string info_name
Informal name.
Definition: dev_interface.h:46
std::string dev_type
Actual device type.
Definition: dev_interface.h:47
std::string dev_name
Device (path)name.
Definition: dev_interface.h:45
unsigned char tnvmcap[16]
Definition: nvmecmds.h:97
unsigned short oacs
Definition: nvmecmds.h:83
nvme_self_test_result results[20]
Definition: nvmecmds.h:248
unsigned char spare_thresh
Definition: nvmecmds.h:180
unsigned char critical_warning
Definition: nvmecmds.h:177
unsigned char temperature[2]
Definition: nvmecmds.h:178
unsigned char media_errors[16]
Definition: nvmecmds.h:191
unsigned char percent_used
Definition: nvmecmds.h:181
unsigned char num_err_log_entries[16]
Definition: nvmecmds.h:192
Non-persistent state data for a device.
Definition: smartd.cpp:514
int attrlog_valid
Definition: smartd.cpp:535
bool not_cap_selective
Definition: smartd.cpp:524
bool not_cap_long
Definition: smartd.cpp:523
ata_smart_values smartval
Definition: smartd.cpp:551
bool not_cap_conveyance
Definition: smartd.cpp:521
unsigned char NonMediumErrorPageSupported
Definition: smartd.cpp:545
bool offline_started
Definition: smartd.cpp:553
unsigned char WriteECounterPageSupported
Definition: smartd.cpp:543
bool powermodefail
Definition: smartd.cpp:531
unsigned char temperature
Definition: smartd.cpp:526
ata_smart_thresholds_pvt smartthres
Definition: smartd.cpp:552
bool not_cap_short
Definition: smartd.cpp:522
bool not_cap_offline
Definition: smartd.cpp:520
uint64_t num_sectors
Definition: smartd.cpp:550
time_t tempmin_delay
Definition: smartd.cpp:527
time_t wakeuptime
Definition: smartd.cpp:518
unsigned char SuppressReport
Definition: smartd.cpp:546
unsigned char VerifyECounterPageSupported
Definition: smartd.cpp:544
bool selftest_started
Definition: smartd.cpp:556
unsigned char modese_len
Definition: smartd.cpp:547
bool must_write
Definition: smartd.cpp:515
unsigned char ReadECounterPageSupported
Definition: smartd.cpp:542
uint8_t selftest_op
Definition: smartd.cpp:559
unsigned char TempPageSupported
Definition: smartd.cpp:541
int lastpowermodeskipped
Definition: smartd.cpp:533
uint8_t selftest_compl
Definition: smartd.cpp:560
unsigned char SmartPageSupported
Definition: smartd.cpp:540
int powerskipcnt
Definition: smartd.cpp:532
void FixGlibcTimeZoneBug()
Definition: utility.cpp:214
const char * format_char_array(char *str, int strsize, const char *chr, int chrsize)
Definition: utility.cpp:692
std::string format_version_info(const char *prog_name, int lines)
Definition: utility.cpp:87
void dateandtimezoneepoch(char(&buffer)[DATEANDEPOCHLEN], time_t tval)
Definition: utility.cpp:349
const char * format_capacity(char *str, int strsize, uint64_t val, const char *decimal_point)
Definition: utility.cpp:748
std::string strprintf(const char *fmt,...)
Definition: utility.cpp:799
bool nonempty(const void *data, int size)
Definition: utility.cpp:682
const char * packetdevicetype(int type)
Definition: utility.cpp:315
struct tm * time_to_tm_local(struct tm *tp, time_t t)
Definition: utility.cpp:326
#define DATEANDEPOCHLEN
Definition: utility.h:64
#define __attribute_format_printf(x, y)
Definition: utility.h:34