smartmontools  SVN Rev 4440
Utility to control and monitor storage systems with "S.M.A.R.T."
smartctl.cpp
Go to the documentation of this file.
1 /*
2  * smartctl.cpp
3  *
4  * Home page of code is: http://www.smartmontools.org
5  *
6  * Copyright (C) 2002-11 Bruce Allen
7  * Copyright (C) 2008-17 Christian Franke
8  * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2, or (at your option)
13  * any later version.
14  *
15  * You should have received a copy of the GNU General Public License
16  * (for example COPYING); If not, see <http://www.gnu.org/licenses/>.
17  *
18  * This code was originally developed as a Senior Thesis by Michael Cornwell
19  * at the Concurrent Systems Laboratory (now part of the Storage Systems
20  * Research Center), Jack Baskin School of Engineering, University of
21  * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
22  *
23  */
24 
25 #include <errno.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdarg.h>
31 #include <stdexcept>
32 #include <getopt.h>
33 
34 #include "config.h"
35 
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 
40 #if defined(__FreeBSD__)
41 #include <sys/param.h>
42 #endif
43 
44 #include "int64.h"
45 #include "atacmds.h"
46 #include "dev_interface.h"
47 #include "ataprint.h"
48 #include "knowndrives.h"
49 #include "scsicmds.h"
50 #include "scsiprint.h"
51 #include "nvmeprint.h"
52 #include "smartctl.h"
53 #include "utility.h"
54 
55 const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 4406 2017-03-11 15:12:56Z chrfranke $"
56  CONFIG_H_CVSID SMARTCTL_H_CVSID;
57 
58 // Globals to control printing
60 bool printing_is_off = false;
61 
62 static void printslogan()
63 {
64  pout("%s\n", format_version_info("smartctl").c_str());
65 }
66 
67 static void UsageSummary()
68 {
69  pout("\nUse smartctl -h to get a usage summary\n\n");
70  return;
71 }
72 
73 static std::string getvalidarglist(int opt);
74 
75 /* void prints help information for command syntax */
76 static void Usage()
77 {
78  printf("Usage: smartctl [options] device\n\n");
79  printf(
80 "============================================ SHOW INFORMATION OPTIONS =====\n\n"
81 " -h, --help, --usage\n"
82 " Display this help and exit\n\n"
83 " -V, --version, --copyright, --license\n"
84 " Print license, copyright, and version information and exit\n\n"
85 " -i, --info\n"
86 " Show identity information for device\n\n"
87 " --identify[=[w][nvb]]\n"
88 " Show words and bits from IDENTIFY DEVICE data (ATA)\n\n"
89 " -g NAME, --get=NAME\n"
90 " Get device setting: all, aam, apm, dsn, lookahead, security, wcache, rcache, wcreorder, wcache-sct\n\n"
91 " -a, --all\n"
92 " Show all SMART information for device\n\n"
93 " -x, --xall\n"
94 " Show all information for device\n\n"
95 " --scan\n"
96 " Scan for devices\n\n"
97 " --scan-open\n"
98 " Scan for devices and try to open each device\n\n"
99  );
100  printf(
101 "================================== SMARTCTL RUN-TIME BEHAVIOR OPTIONS =====\n\n"
102 " -q TYPE, --quietmode=TYPE (ATA)\n"
103 " Set smartctl quiet mode to one of: errorsonly, silent, noserial\n\n"
104 " -d TYPE, --device=TYPE\n"
105 " Specify device type to one of: %s\n\n"
106 " -T TYPE, --tolerance=TYPE (ATA)\n"
107 " Tolerance: normal, conservative, permissive, verypermissive\n\n"
108 " -b TYPE, --badsum=TYPE (ATA)\n"
109 " Set action on bad checksum to one of: warn, exit, ignore\n\n"
110 " -r TYPE, --report=TYPE\n"
111 " Report transactions (see man page)\n\n"
112 " -n MODE[,STATUS], --nocheck=MODE[,STATUS] (ATA)\n"
113 " No check if: never, sleep, standby, idle (see man page)\n\n",
114  getvalidarglist('d').c_str()); // TODO: Use this function also for other options ?
115  printf(
116 "============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n"
117 " -s VALUE, --smart=VALUE\n"
118 " Enable/disable SMART on device (on/off)\n\n"
119 " -o VALUE, --offlineauto=VALUE (ATA)\n"
120 " Enable/disable automatic offline testing on device (on/off)\n\n"
121 " -S VALUE, --saveauto=VALUE (ATA)\n"
122 " Enable/disable Attribute autosave on device (on/off)\n\n"
123 " -s NAME[,VALUE], --set=NAME[,VALUE]\n"
124 " Enable/disable/change device setting: aam,[N|off], apm,[N|off],\n"
125 " dsn,[on|off], lookahead,[on|off], security-freeze, standby,[N|off|now],\n"
126 " wcache,[on|off], rcache,[on|off], wcreorder,[on|off[,p]]\n"
127 " wcache-sct,[ata|on|off[,p]]\n\n"
128  );
129  printf(
130 "======================================= READ AND DISPLAY DATA OPTIONS =====\n\n"
131 " -H, --health\n"
132 " Show device SMART health status\n\n"
133 " -c, --capabilities (ATA, NVMe)\n"
134 " Show device SMART capabilities\n\n"
135 " -A, --attributes\n"
136 " Show device SMART vendor-specific Attributes and values\n\n"
137 " -f FORMAT, --format=FORMAT (ATA)\n"
138 " Set output format for attributes: old, brief, hex[,id|val]\n\n"
139 " -l TYPE, --log=TYPE\n"
140 " Show device log. TYPE: error, selftest, selective, directory[,g|s],\n"
141 " xerror[,N][,error], xselftest[,N][,selftest],\n"
142 " background, sasphy[,reset], sataphy[,reset],\n"
143 " scttemp[sts,hist], scttempint,N[,p],\n"
144 " scterc[,N,M], devstat[,N], ssd,\n"
145 " gplog,N[,RANGE], smartlog,N[,RANGE],\n"
146 " nvmelog,N,SIZE\n\n"
147 " -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n"
148 " Set display OPTION for vendor Attribute N (see man page)\n\n"
149 " -F TYPE, --firmwarebug=TYPE (ATA)\n"
150 " Use firmware bug workaround:\n"
151 " %s, swapid\n\n"
152 " -P TYPE, --presets=TYPE (ATA)\n"
153 " Drive-specific presets: use, ignore, show, showall\n\n"
154 " -B [+]FILE, --drivedb=[+]FILE (ATA)\n"
155 " Read and replace [add] drive database from FILE\n"
156 " [default is +%s",
159  );
160 #ifdef SMARTMONTOOLS_DRIVEDBDIR
161  printf(
162  "\n"
163 " and then %s",
164  get_drivedb_path_default()
165  );
166 #endif
167  printf(
168  "]\n\n"
169 "============================================ DEVICE SELF-TEST OPTIONS =====\n\n"
170 " -t TEST, --test=TEST\n"
171 " Run test. TEST: offline, short, long, conveyance, force, vendor,N,\n"
172 " select,M-N, pending,N, afterselect,[on|off]\n\n"
173 " -C, --captive\n"
174 " Do test in captive mode (along with -t)\n\n"
175 " -X, --abort\n"
176 " Abort any non-captive test on device\n\n"
177 );
178  std::string examples = smi()->get_app_examples("smartctl");
179  if (!examples.empty())
180  printf("%s\n", examples.c_str());
181 }
182 
183 // Values for --long only options, see parse_options()
185 
186 /* Returns a string containing a formatted list of the valid arguments
187  to the option opt or empty on failure. Note 'v' case different */
188 static std::string getvalidarglist(int opt)
189 {
190  switch (opt) {
191  case 'q':
192  return "errorsonly, silent, noserial";
193  case 'd':
194  return smi()->get_valid_dev_types_str() + ", auto, test";
195  case 'T':
196  return "normal, conservative, permissive, verypermissive";
197  case 'b':
198  return "warn, exit, ignore";
199  case 'B':
200  return "[+]<FILE_NAME>";
201  case 'r':
202  return "ioctl[,N], ataioctl[,N], scsiioctl[,N], nvmeioctl[,N]";
203  case opt_smart:
204  case 'o':
205  case 'S':
206  return "on, off";
207  case 'l':
208  return "error, selftest, selective, directory[,g|s], "
209  "xerror[,N][,error], xselftest[,N][,selftest], "
210  "background, sasphy[,reset], sataphy[,reset], "
211  "scttemp[sts,hist], scttempint,N[,p], "
212  "scterc[,N,M], devstat[,N], ssd, "
213  "gplog,N[,RANGE], smartlog,N[,RANGE], "
214  "nvmelog,N,SIZE";
215  case 'P':
216  return "use, ignore, show, showall";
217  case 't':
218  return "offline, short, long, conveyance, force, vendor,N, select,M-N, "
219  "pending,N, afterselect,[on|off]";
220  case 'F':
221  return std::string(get_valid_firmwarebug_args()) + ", swapid";
222  case 'n':
223  return "never, sleep[,STATUS], standby[,STATUS], idle[,STATUS]";
224  case 'f':
225  return "old, brief, hex[,id|val]";
226  case 'g':
227  return "aam, apm, dsn, lookahead, security, wcache, rcache, wcreorder, wcache-sct";
228  case opt_set:
229  return "aam,[N|off], apm,[N|off], dsn,[on|off], lookahead,[on|off], security-freeze, "
230  "standby,[N|off|now], wcache,[on|off], rcache,[on|off], wcreorder,[on|off[,p]], "
231  "wcache-sct,[ata|on|off[,p]]";
232  case 's':
234  case opt_identify:
235  return "n, wn, w, v, wv, wb";
236  case 'v':
237  default:
238  return "";
239  }
240 }
241 
242 /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where
243  <LIST> is the list of valid arguments for option opt. */
244 static void printvalidarglistmessage(int opt)
245 {
246  if (opt=='v'){
247  pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n",
249  }
250  else {
251  // getvalidarglist() might produce a multiline or single line string. We
252  // need to figure out which to get the formatting right.
253  std::string s = getvalidarglist(opt);
254  char separator = strchr(s.c_str(), '\n') ? '\n' : ' ';
255  pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, s.c_str(), separator);
256  }
257 
258  return;
259 }
260 
261 // Checksum error mode
264 };
265 
267 
268 static void scan_devices(const smart_devtype_list & types, bool with_open, char ** argv);
269 
270 
271 /* Takes command options and sets features to be run */
272 static const char * parse_options(int argc, char** argv,
273  ata_print_options & ataopts, scsi_print_options & scsiopts,
274  nvme_print_options & nvmeopts, bool & print_type_only)
275 {
276  // Please update getvalidarglist() if you edit shortopts
277  const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iaxv:P:t:CXF:n:B:f:g:";
278  // Please update getvalidarglist() if you edit longopts
279  struct option longopts[] = {
280  { "help", no_argument, 0, 'h' },
281  { "usage", no_argument, 0, 'h' },
282  { "version", no_argument, 0, 'V' },
283  { "copyright", no_argument, 0, 'V' },
284  { "license", no_argument, 0, 'V' },
285  { "quietmode", required_argument, 0, 'q' },
286  { "device", required_argument, 0, 'd' },
287  { "tolerance", required_argument, 0, 'T' },
288  { "badsum", required_argument, 0, 'b' },
289  { "report", required_argument, 0, 'r' },
290  { "smart", required_argument, 0, opt_smart },
291  { "offlineauto", required_argument, 0, 'o' },
292  { "saveauto", required_argument, 0, 'S' },
293  { "health", no_argument, 0, 'H' },
294  { "capabilities", no_argument, 0, 'c' },
295  { "attributes", no_argument, 0, 'A' },
296  { "log", required_argument, 0, 'l' },
297  { "info", no_argument, 0, 'i' },
298  { "all", no_argument, 0, 'a' },
299  { "xall", no_argument, 0, 'x' },
300  { "vendorattribute", required_argument, 0, 'v' },
301  { "presets", required_argument, 0, 'P' },
302  { "test", required_argument, 0, 't' },
303  { "captive", no_argument, 0, 'C' },
304  { "abort", no_argument, 0, 'X' },
305  { "firmwarebug", required_argument, 0, 'F' },
306  { "nocheck", required_argument, 0, 'n' },
307  { "drivedb", required_argument, 0, 'B' },
308  { "format", required_argument, 0, 'f' },
309  { "get", required_argument, 0, 'g' },
310  { "identify", optional_argument, 0, opt_identify },
311  { "set", required_argument, 0, opt_set },
312  { "scan", no_argument, 0, opt_scan },
313  { "scan-open", no_argument, 0, opt_scan_open },
314  { 0, 0, 0, 0 }
315  };
316 
317  char extraerror[256];
318  memset(extraerror, 0, sizeof(extraerror));
319  opterr=optopt=0;
320 
321  const char * type = 0; // set to -d optarg
322  smart_devtype_list scan_types; // multiple -d TYPE options for --scan
323  bool use_default_db = true; // set false on '-B FILE'
324  bool output_format_set = false; // set true on '-f FORMAT'
325  int scan = 0; // set by --scan, --scan-open
326  bool badarg = false, captive = false;
327  int testcnt = 0; // number of self-tests requested
328 
329  int optchar;
330  char *arg;
331 
332  while ((optchar = getopt_long(argc, argv, shortopts, longopts, 0)) != -1) {
333  switch (optchar){
334  case 'V':
335  printing_is_off = false;
336  pout("%s", format_version_info("smartctl", true /*full*/).c_str());
337  EXIT(0);
338  break;
339  case 'q':
340  if (!strcmp(optarg,"errorsonly")) {
341  printing_is_switchable = true;
342  printing_is_off = false;
343  } else if (!strcmp(optarg,"silent")) {
344  printing_is_switchable = false;
345  printing_is_off = true;
346  } else if (!strcmp(optarg,"noserial")) {
348  } else {
349  badarg = true;
350  }
351  break;
352  case 'd':
353  if (!strcmp(optarg, "test"))
354  print_type_only = true;
355  else if (!strcmp(optarg, "auto")) {
356  type = 0;
357  scan_types.clear();
358  }
359  else {
360  type = optarg;
361  scan_types.push_back(optarg);
362  }
363  break;
364  case 'T':
365  if (!strcmp(optarg,"normal")) {
366  failuretest_conservative = false;
368  } else if (!strcmp(optarg,"conservative")) {
370  } else if (!strcmp(optarg,"permissive")) {
371  if (failuretest_permissive < 0xff)
373  } else if (!strcmp(optarg,"verypermissive")) {
374  failuretest_permissive = 0xff;
375  } else {
376  badarg = true;
377  }
378  break;
379  case 'b':
380  if (!strcmp(optarg,"warn")) {
382  } else if (!strcmp(optarg,"exit")) {
384  } else if (!strcmp(optarg,"ignore")) {
386  } else {
387  badarg = true;
388  }
389  break;
390  case 'r':
391  {
392  int n1 = -1, n2 = -1, len = strlen(optarg);
393  char s[9+1]; unsigned i = 1;
394  sscanf(optarg, "%9[a-z]%n,%u%n", s, &n1, &i, &n2);
395  if (!((n1 == len || n2 == len) && 1 <= i && i <= 4)) {
396  badarg = true;
397  } else if (!strcmp(s,"ioctl")) {
399  } else if (!strcmp(s,"ataioctl")) {
400  ata_debugmode = i;
401  } else if (!strcmp(s,"scsiioctl")) {
402  scsi_debugmode = i;
403  } else if (!strcmp(s,"nvmeioctl")) {
404  nvme_debugmode = i;
405  } else {
406  badarg = true;
407  }
408  }
409  break;
410 
411  case 's':
412  case opt_smart: // --smart
413  if (!strcmp(optarg,"on")) {
414  ataopts.smart_enable = scsiopts.smart_enable = true;
415  ataopts.smart_disable = scsiopts.smart_disable = false;
416  } else if (!strcmp(optarg,"off")) {
417  ataopts.smart_disable = scsiopts.smart_disable = true;
418  ataopts.smart_enable = scsiopts.smart_enable = false;
419  } else if (optchar == 's') {
420  goto case_s_continued; // --set, see below
421  } else {
422  badarg = true;
423  }
424  break;
425 
426  case 'o':
427  if (!strcmp(optarg,"on")) {
428  ataopts.smart_auto_offl_enable = true;
429  ataopts.smart_auto_offl_disable = false;
430  } else if (!strcmp(optarg,"off")) {
431  ataopts.smart_auto_offl_disable = true;
432  ataopts.smart_auto_offl_enable = false;
433  } else {
434  badarg = true;
435  }
436  break;
437  case 'S':
438  if (!strcmp(optarg,"on")) {
439  ataopts.smart_auto_save_enable = scsiopts.smart_auto_save_enable = true;
440  ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = false;
441  } else if (!strcmp(optarg,"off")) {
442  ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = true;
443  ataopts.smart_auto_save_enable = scsiopts.smart_auto_save_enable = false;
444  } else {
445  badarg = true;
446  }
447  break;
448  case 'H':
449  ataopts.smart_check_status = scsiopts.smart_check_status = nvmeopts.smart_check_status = true;
450  scsiopts.smart_ss_media_log = true;
451  break;
452  case 'F':
453  if (!strcmp(optarg, "swapid"))
454  ataopts.fix_swapped_id = true;
455  else if (!parse_firmwarebug_def(optarg, ataopts.firmwarebugs))
456  badarg = true;
457  break;
458  case 'c':
459  ataopts.smart_general_values = nvmeopts.drive_capabilities = true;
460  break;
461  case 'A':
462  ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = nvmeopts.smart_vendor_attrib = true;
463  break;
464  case 'l':
465  if (str_starts_with(optarg, "error")) {
466  int n1 = -1, n2 = -1, len = strlen(optarg);
467  unsigned val = ~0;
468  sscanf(optarg, "error%n,%u%n", &n1, &val, &n2);
469  ataopts.smart_error_log = scsiopts.smart_error_log = true;
470  if (n1 == len)
471  nvmeopts.error_log_entries = 16;
472  else if (n2 == len && val > 0)
473  nvmeopts.error_log_entries = val;
474  else
475  badarg = true;
476  } else if (!strcmp(optarg,"selftest")) {
477  ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true;
478  } else if (!strcmp(optarg, "selective")) {
479  ataopts.smart_selective_selftest_log = true;
480  } else if (!strcmp(optarg,"directory")) {
481  ataopts.smart_logdir = ataopts.gp_logdir = true; // SMART+GPL
482  } else if (!strcmp(optarg,"directory,s")) {
483  ataopts.smart_logdir = true; // SMART
484  } else if (!strcmp(optarg,"directory,g")) {
485  ataopts.gp_logdir = true; // GPL
486  } else if (!strcmp(optarg,"sasphy")) {
487  scsiopts.sasphy = true;
488  } else if (!strcmp(optarg,"sasphy,reset")) {
489  scsiopts.sasphy = scsiopts.sasphy_reset = true;
490  } else if (!strcmp(optarg,"sataphy")) {
491  ataopts.sataphy = true;
492  } else if (!strcmp(optarg,"sataphy,reset")) {
493  ataopts.sataphy = ataopts.sataphy_reset = true;
494  } else if (!strcmp(optarg,"background")) {
495  scsiopts.smart_background_log = true;
496  } else if (!strcmp(optarg,"ssd")) {
497  ataopts.devstat_ssd_page = true;
498  scsiopts.smart_ss_media_log = true;
499  } else if (!strcmp(optarg,"scterc")) {
500  ataopts.sct_erc_get = true;
501  } else if (!strcmp(optarg,"scttemp")) {
502  ataopts.sct_temp_sts = ataopts.sct_temp_hist = true;
503  } else if (!strcmp(optarg,"scttempsts")) {
504  ataopts.sct_temp_sts = true;
505  } else if (!strcmp(optarg,"scttemphist")) {
506  ataopts.sct_temp_hist = true;
507 
508  } else if (!strncmp(optarg, "scttempint,", sizeof("scstempint,")-1)) {
509  unsigned interval = 0; int n1 = -1, n2 = -1, len = strlen(optarg);
510  if (!( sscanf(optarg,"scttempint,%u%n,p%n", &interval, &n1, &n2) == 1
511  && 0 < interval && interval <= 0xffff && (n1 == len || n2 == len))) {
512  snprintf(extraerror, sizeof(extraerror), "Option -l scttempint,N[,p] must have positive integer N\n");
513  badarg = true;
514  }
515  ataopts.sct_temp_int = interval;
516  ataopts.sct_temp_int_pers = (n2 == len);
517 
518  } else if (!strncmp(optarg, "devstat", sizeof("devstat")-1)) {
519  int n1 = -1, n2 = -1, len = strlen(optarg);
520  unsigned val = ~0;
521  sscanf(optarg, "devstat%n,%u%n", &n1, &val, &n2);
522  if (n1 == len)
523  ataopts.devstat_all_pages = true;
524  else {
525  if (n2 != len) // retry with hex
526  sscanf(optarg, "devstat,0x%x%n", &val, &n2);
527  if (n2 == len && val <= 0xff)
528  ataopts.devstat_pages.push_back(val);
529  else
530  badarg = true;
531  }
532 
533  } else if (!strncmp(optarg, "xerror", sizeof("xerror")-1)) {
534  int n1 = -1, n2 = -1, len = strlen(optarg);
535  unsigned val = 8;
536  sscanf(optarg, "xerror%n,error%n", &n1, &n2);
537  if (!(n1 == len || n2 == len)) {
538  n1 = n2 = -1;
539  sscanf(optarg, "xerror,%u%n,error%n", &val, &n1, &n2);
540  }
541  if ((n1 == len || n2 == len) && val > 0) {
542  ataopts.smart_ext_error_log = val;
543  ataopts.retry_error_log = (n2 == len);
544  }
545  else
546  badarg = true;
547 
548  } else if (!strncmp(optarg, "xselftest", sizeof("xselftest")-1)) {
549  int n1 = -1, n2 = -1, len = strlen(optarg);
550  unsigned val = 25;
551  sscanf(optarg, "xselftest%n,selftest%n", &n1, &n2);
552  if (!(n1 == len || n2 == len)) {
553  n1 = n2 = -1;
554  sscanf(optarg, "xselftest,%u%n,selftest%n", &val, &n1, &n2);
555  }
556  if ((n1 == len || n2 == len) && val > 0) {
557  ataopts.smart_ext_selftest_log = val;
558  ataopts.retry_selftest_log = (n2 == len);
559  }
560  else
561  badarg = true;
562 
563  } else if (!strncmp(optarg, "scterc,", sizeof("scterc,")-1)) {
564  unsigned rt = ~0, wt = ~0; int n = -1;
565  sscanf(optarg,"scterc,%u,%u%n", &rt, &wt, &n);
566  if (n == (int)strlen(optarg) && rt <= 999 && wt <= 999) {
567  ataopts.sct_erc_set = true;
568  ataopts.sct_erc_readtime = rt;
569  ataopts.sct_erc_writetime = wt;
570  }
571  else {
572  snprintf(extraerror, sizeof(extraerror), "Option -l scterc,[READTIME,WRITETIME] syntax error\n");
573  badarg = true;
574  }
575  } else if ( !strncmp(optarg, "gplog," , sizeof("gplog," )-1)
576  || !strncmp(optarg, "smartlog,", sizeof("smartlog,")-1)) {
577  unsigned logaddr = ~0U; unsigned page = 0, nsectors = 1; char sign = 0;
578  int n1 = -1, n2 = -1, n3 = -1, len = strlen(optarg);
579  sscanf(optarg, "%*[a-z],0x%x%n,%u%n%c%u%n",
580  &logaddr, &n1, &page, &n2, &sign, &nsectors, &n3);
581  if (len > n2 && n3 == -1 && !strcmp(optarg+n2, "-max")) {
582  nsectors = ~0U; sign = '+'; n3 = len;
583  }
584  bool gpl = (optarg[0] == 'g');
585  const char * erropt = (gpl ? "gplog" : "smartlog");
586  if (!( n1 == len || n2 == len
587  || (n3 == len && (sign == '+' || sign == '-')))) {
588  snprintf(extraerror, sizeof(extraerror), "Option -l %s,ADDR[,FIRST[-LAST|+SIZE]] syntax error\n", erropt);
589  badarg = true;
590  }
591  else if (!( logaddr <= 0xff && page <= (gpl ? 0xffffU : 0x00ffU)
592  && 0 < nsectors
593  && (nsectors <= (gpl ? 0xffffU : 0xffU) || nsectors == ~0U)
594  && (sign != '-' || page <= nsectors) )) {
595  snprintf(extraerror, sizeof(extraerror), "Option -l %s,ADDR[,FIRST[-LAST|+SIZE]] parameter out of range\n", erropt);
596  badarg = true;
597  }
598  else {
599  ata_log_request req;
600  req.gpl = gpl; req.logaddr = logaddr; req.page = page;
601  req.nsectors = (sign == '-' ? nsectors-page+1 : nsectors);
602  ataopts.log_requests.push_back(req);
603  }
604  }
605 
606  else if (str_starts_with(optarg, "nvmelog,")) {
607  int n = -1, len = strlen(optarg);
608  unsigned page = 0, size = 0;
609  sscanf(optarg, "nvmelog,0x%x,0x%x%n", &page, &size, &n);
610  if (n == len && page <= 0xff && 0 < size && size <= 0x4000) {
611  nvmeopts.log_page = page; nvmeopts.log_page_size = size;
612  }
613  else
614  badarg = true;
615  }
616 
617  else {
618  badarg = true;
619  }
620  break;
621  case 'i':
622  ataopts.drive_info = scsiopts.drive_info = nvmeopts.drive_info = true;
623  break;
624 
625  case opt_identify:
626  ataopts.identify_word_level = ataopts.identify_bit_level = 0;
627  if (optarg) {
628  for (int i = 0; optarg[i]; i++) {
629  switch (optarg[i]) {
630  case 'w': ataopts.identify_word_level = 1; break;
631  case 'n': ataopts.identify_bit_level = -1; break;
632  case 'v': ataopts.identify_bit_level = 1; break;
633  case 'b': ataopts.identify_bit_level = 2; break;
634  default: badarg = true;
635  }
636  }
637  }
638  break;
639 
640  case 'a':
641  ataopts.drive_info = scsiopts.drive_info = nvmeopts.drive_info = true;
642  ataopts.smart_check_status = scsiopts.smart_check_status = nvmeopts.smart_check_status = true;
643  ataopts.smart_general_values = nvmeopts.drive_capabilities = true;
644  ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = nvmeopts.smart_vendor_attrib = true;
645  ataopts.smart_error_log = scsiopts.smart_error_log = true;
646  nvmeopts.error_log_entries = 16;
647  ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true;
648  ataopts.smart_selective_selftest_log = true;
649  /* scsiopts.smart_background_log = true; */
650  scsiopts.smart_ss_media_log = true;
651  break;
652  case 'x':
653  ataopts.drive_info = scsiopts.drive_info = nvmeopts.drive_info = true;
654  ataopts.smart_check_status = scsiopts.smart_check_status = nvmeopts.smart_check_status = true;
655  ataopts.smart_general_values = nvmeopts.drive_capabilities = true;
656  ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = nvmeopts.smart_vendor_attrib = true;
657  ataopts.smart_ext_error_log = 8;
658  ataopts.retry_error_log = true;
659  nvmeopts.error_log_entries = 16;
660  ataopts.smart_ext_selftest_log = 25;
661  ataopts.retry_selftest_log = true;
662  scsiopts.smart_error_log = scsiopts.smart_selftest_log = true;
663  ataopts.smart_selective_selftest_log = true;
664  ataopts.smart_logdir = ataopts.gp_logdir = true;
665  ataopts.sct_temp_sts = ataopts.sct_temp_hist = true;
666  ataopts.sct_erc_get = true;
667  ataopts.sct_wcache_reorder_get = true;
668  ataopts.devstat_all_pages = true;
669  ataopts.sataphy = true;
670  ataopts.get_set_used = true;
671  ataopts.get_aam = ataopts.get_apm = true;
672  ataopts.get_security = true;
673  ataopts.get_lookahead = ataopts.get_wcache = true;
674  ataopts.get_dsn = true;
675  scsiopts.get_rcd = scsiopts.get_wce = true;
676  scsiopts.smart_background_log = true;
677  scsiopts.smart_ss_media_log = true;
678  scsiopts.sasphy = true;
679  if (!output_format_set)
681  break;
682  case 'v':
683  // parse vendor-specific definitions of attributes
684  if (!strcmp(optarg,"help")) {
685  printing_is_off = false;
686  printslogan();
687  pout("The valid arguments to -v are:\n\thelp\n%s\n",
689  EXIT(0);
690  }
691  if (!parse_attribute_def(optarg, ataopts.attribute_defs, PRIOR_USER))
692  badarg = true;
693  break;
694  case 'P':
695  if (!strcmp(optarg, "use")) {
696  ataopts.ignore_presets = false;
697  } else if (!strcmp(optarg, "ignore")) {
698  ataopts.ignore_presets = true;
699  } else if (!strcmp(optarg, "show")) {
700  ataopts.show_presets = true;
701  } else if (!strcmp(optarg, "showall")) {
702  if (!init_drive_database(use_default_db))
703  EXIT(FAILCMD);
704  if (optind < argc) { // -P showall MODEL [FIRMWARE]
705  int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL));
706  EXIT(cnt); // report #matches
707  }
708  if (showallpresets())
709  EXIT(FAILCMD); // report regexp syntax error
710  EXIT(0);
711  } else {
712  badarg = true;
713  }
714  break;
715  case 't':
716  if (!strcmp(optarg,"offline")) {
717  testcnt++;
719  scsiopts.smart_default_selftest = true;
720  } else if (!strcmp(optarg,"short")) {
721  testcnt++;
723  scsiopts.smart_short_selftest = true;
724  } else if (!strcmp(optarg,"long")) {
725  testcnt++;
727  scsiopts.smart_extend_selftest = true;
728  } else if (!strcmp(optarg,"conveyance")) {
729  testcnt++;
731  } else if (!strcmp(optarg,"force")) {
732  ataopts.smart_selftest_force = true;
733  scsiopts.smart_selftest_force = true;
734  } else if (!strcmp(optarg,"afterselect,on")) {
735  // scan remainder of disk after doing selected segment
737  } else if (!strcmp(optarg,"afterselect,off")) {
738  // don't scan remainder of disk after doing selected segments
740  } else if (!strncmp(optarg,"pending,",strlen("pending,"))) {
741  // parse number of minutes that test should be pending
742  int i;
743  char *tailptr=NULL;
744  errno=0;
745  i=(int)strtol(optarg+strlen("pending,"), &tailptr, 10);
746  if (errno || *tailptr != '\0') {
747  snprintf(extraerror, sizeof(extraerror), "Option -t pending,N requires N to be a non-negative integer\n");
748  badarg = true;
749  } else if (i<0 || i>65535) {
750  snprintf(extraerror, sizeof(extraerror), "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i);
751  badarg = true;
752  } else {
753  ataopts.smart_selective_args.pending_time = i+1;
754  }
755  } else if (!strncmp(optarg,"select",strlen("select"))) {
756  if (ataopts.smart_selective_args.num_spans == 0)
757  testcnt++;
758  // parse range of LBAs to test
759  uint64_t start, stop; int mode;
760  if (split_selective_arg(optarg, &start, &stop, &mode)) {
761  snprintf(extraerror, sizeof(extraerror), "Option -t select,M-N must have non-negative integer M and N\n");
762  badarg = true;
763  } else {
764  if (ataopts.smart_selective_args.num_spans >= 5 || start > stop) {
765  if (start > stop) {
766  snprintf(extraerror, sizeof(extraerror), "ERROR: Start LBA (%" PRIu64 ") > ending LBA (%" PRId64 ") in argument \"%s\"\n",
767  start, stop, optarg);
768  } else {
769  snprintf(extraerror, sizeof(extraerror),"ERROR: No more than five selective self-test spans may be"
770  " defined\n");
771  }
772  badarg = true;
773  }
779  }
780  } else if (!strncmp(optarg, "scttempint", sizeof("scstempint")-1)) {
781  snprintf(extraerror, sizeof(extraerror), "-t scttempint is no longer supported, use -l scttempint instead\n");
782  badarg = true;
783  } else if (!strncmp(optarg, "vendor,", sizeof("vendor,")-1)) {
784  unsigned subcmd = ~0U; int n = -1;
785  if (!( sscanf(optarg, "%*[a-z],0x%x%n", &subcmd, &n) == 1
786  && subcmd <= 0xff && n == (int)strlen(optarg))) {
787  snprintf(extraerror, sizeof(extraerror), "Option -t vendor,0xNN syntax error\n");
788  badarg = true;
789  }
790  else
791  ataopts.smart_selftest_type = subcmd;
792  } else {
793  badarg = true;
794  }
795  break;
796  case 'C':
797  captive = true;
798  break;
799  case 'X':
800  testcnt++;
801  scsiopts.smart_selftest_abort = true;
803  break;
804  case 'n':
805  // skip disk check if in low-power mode
806  if (!strcmp(optarg, "never")) {
807  ataopts.powermode = 1; // do not skip, but print mode
808  }
809  else {
810  int n1 = -1, n2 = -1, len = strlen(optarg);
811  char s[7+1]; unsigned i = FAILPOWER;
812  sscanf(optarg, "%9[a-z]%n,%u%n", s, &n1, &i, &n2);
813  if (!((n1 == len || n2 == len) && i <= 255))
814  badarg = true;
815  else if (!strcmp(s, "sleep"))
816  ataopts.powermode = 2;
817  else if (!strcmp(s, "standby"))
818  ataopts.powermode = 3;
819  else if (!strcmp(s, "idle"))
820  ataopts.powermode = 4;
821  else
822  badarg = true;
823  ataopts.powerexit = i;
824  }
825  break;
826  case 'f':
827  if (!strcmp(optarg, "old")) {
828  ataopts.output_format &= ~ata_print_options::FMT_BRIEF;
829  output_format_set = true;
830  }
831  else if (!strcmp(optarg, "brief")) {
833  output_format_set = true;
834  }
835  else if (!strcmp(optarg, "hex"))
838  else if (!strcmp(optarg, "hex,id"))
840  else if (!strcmp(optarg, "hex,val"))
842  else
843  badarg = true;
844  break;
845  case 'B':
846  {
847  const char * path = optarg;
848  if (*path == '+' && path[1])
849  path++;
850  else
851  use_default_db = false;
852  if (!read_drive_database(path))
853  EXIT(FAILCMD);
854  }
855  break;
856  case 'h':
857  printing_is_off = false;
858  printslogan();
859  Usage();
860  EXIT(0);
861  break;
862 
863  case 'g':
864  case_s_continued: // -s, see above
865  case opt_set: // --set
866  {
867  ataopts.get_set_used = true;
868  bool get = (optchar == 'g');
869  char name[16+1]; unsigned val;
870  int n1 = -1, n2 = -1, n3 = -1, len = strlen(optarg);
871  if (sscanf(optarg, "%16[^,=]%n%*[,=]%n%u%n", name, &n1, &n2, &val, &n3) >= 1
872  && (n1 == len || (!get && n2 > 0))) {
873  bool on = false;
874  bool off = false;
875  bool ata = false;
876  bool persistent = false;
877 
878  if (n2 > 0) {
879  int len2 = strlen(optarg + n2);
880  char * tmp = strstr(optarg+n2, ",p");
881  // handle ",p" in persistent options like: wcache-sct,[ata|on|off],p
882  if (tmp && (strlen(tmp) == 2)) {
883  persistent = true;
884  len2 = strlen(optarg+n2) - 2;
885 
886  // the ,p option only works for set of SCT Feature Control command
887  if (strcmp(name, "wcache-sct") != 0 &&
888  strcmp(name, "wcreorder") != 0)
889  badarg = true;
890  }
891  on = !strncmp(optarg+n2, "on", len2);
892  off = !strncmp(optarg+n2, "off", len2);
893  ata = !strncmp(optarg+n2, "ata", len2);
894  }
895  if (n3 != len)
896  val = ~0U;
897 
898  if (get && !strcmp(name, "all")) {
899  ataopts.get_aam = ataopts.get_apm = true;
900  ataopts.get_security = true;
901  ataopts.get_lookahead = ataopts.get_wcache = true;
902  ataopts.get_dsn = true;
903  scsiopts.get_rcd = scsiopts.get_wce = true;
904  }
905  else if (!strcmp(name, "aam")) {
906  if (get)
907  ataopts.get_aam = true;
908  else if (off)
909  ataopts.set_aam = -1;
910  else if (val <= 254)
911  ataopts.set_aam = val + 1;
912  else {
913  snprintf(extraerror, sizeof(extraerror), "Option -s aam,N must have 0 <= N <= 254\n");
914  badarg = true;
915  }
916  }
917  else if (!strcmp(name, "apm")) {
918  if (get)
919  ataopts.get_apm = true;
920  else if (off)
921  ataopts.set_apm = -1;
922  else if (1 <= val && val <= 254)
923  ataopts.set_apm = val + 1;
924  else {
925  snprintf(extraerror, sizeof(extraerror), "Option -s apm,N must have 1 <= N <= 254\n");
926  badarg = true;
927  }
928  }
929  else if (!strcmp(name, "lookahead")) {
930  if (get) {
931  ataopts.get_lookahead = true;
932  }
933  else if (off)
934  ataopts.set_lookahead = -1;
935  else if (on)
936  ataopts.set_lookahead = 1;
937  else
938  badarg = true;
939  }
940  else if (!strcmp(name, "wcreorder")) {
941  ataopts.sct_wcache_reorder_set_pers = persistent;
942  if (get) {
943  ataopts.sct_wcache_reorder_get = true;
944  }
945  else if (off)
946  ataopts.sct_wcache_reorder_set = -1;
947  else if (on)
948  ataopts.sct_wcache_reorder_set = 1;
949  else
950  badarg = true;
951  }
952  else if (!strcmp(name, "wcache-sct")) {
953  ataopts.sct_wcache_sct_set_pers = persistent;
954  if (get) {
955  ataopts.sct_wcache_sct_get = true;
956  }
957  else if (off)
958  ataopts.sct_wcache_sct_set = 3;
959  else if (on)
960  ataopts.sct_wcache_sct_set = 2;
961  else if (ata)
962  ataopts.sct_wcache_sct_set = 1;
963  else
964  badarg = true;
965  }
966  else if (!strcmp(name, "rcache")) {
967  if (get)
968  scsiopts.get_rcd = true;
969  else if (off)
970  scsiopts.set_rcd = -1;
971  else if (on)
972  scsiopts.set_rcd = 1;
973  else
974  badarg = true;
975  }
976  else if (get && !strcmp(name, "security")) {
977  ataopts.get_security = true;
978  }
979  else if (!get && !strcmp(optarg, "security-freeze")) {
980  ataopts.set_security_freeze = true;
981  }
982  else if (!get && !strcmp(optarg, "standby,now")) {
983  ataopts.set_standby_now = true;
984  }
985  else if (!get && !strcmp(name, "standby")) {
986  if (off)
987  ataopts.set_standby = 0 + 1;
988  else if (val <= 255)
989  ataopts.set_standby = val + 1;
990  else {
991  snprintf(extraerror, sizeof(extraerror), "Option -s standby,N must have 0 <= N <= 255\n");
992  badarg = true;
993  }
994  }
995  else if (!strcmp(name, "wcache")) {
996  if (get) {
997  ataopts.get_wcache = true;
998  scsiopts.get_wce = true;
999  }
1000  else if (off) {
1001  ataopts.set_wcache = -1;
1002  scsiopts.set_wce = -1;
1003  }
1004  else if (on) {
1005  ataopts.set_wcache = 1;
1006  scsiopts.set_wce = 1;
1007  }
1008  else
1009  badarg = true;
1010  }
1011  else if (!strcmp(name, "dsn")) {
1012  if (get) {
1013  ataopts.get_dsn = true;
1014  }
1015  else if (off) {
1016  ataopts.set_dsn = -1;
1017  }
1018  else if (on) {
1019  ataopts.set_dsn = 1;
1020  }
1021  else
1022  badarg = true;
1023  }
1024  else
1025  badarg = true;
1026  }
1027  else
1028  badarg = true;
1029  }
1030  break;
1031 
1032  case opt_scan:
1033  case opt_scan_open:
1034  scan = optchar;
1035  break;
1036 
1037  case '?':
1038  default:
1039  printing_is_off = false;
1040  printslogan();
1041  // Point arg to the argument in which this option was found.
1042  arg = argv[optind-1];
1043  // Check whether the option is a long option that doesn't map to -h.
1044  if (arg[1] == '-' && optchar != 'h') {
1045  // Iff optopt holds a valid option then argument must be missing.
1046  if (optopt && (optopt >= opt_scan || strchr(shortopts, optopt))) {
1047  pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2);
1048  printvalidarglistmessage(optopt);
1049  } else
1050  pout("=======> UNRECOGNIZED OPTION: %s\n",arg+2);
1051  if (extraerror[0])
1052  pout("=======> %s", extraerror);
1053  UsageSummary();
1054  EXIT(FAILCMD);
1055  }
1056  if (0 < optopt && optopt < '~') {
1057  // Iff optopt holds a valid option then argument must be
1058  // missing. Note (BA) this logic seems to fail using Solaris
1059  // getopt!
1060  if (strchr(shortopts, optopt) != NULL) {
1061  pout("=======> ARGUMENT REQUIRED FOR OPTION: %c\n", optopt);
1062  printvalidarglistmessage(optopt);
1063  } else
1064  pout("=======> UNRECOGNIZED OPTION: %c\n",optopt);
1065  if (extraerror[0])
1066  pout("=======> %s", extraerror);
1067  UsageSummary();
1068  EXIT(FAILCMD);
1069  }
1070  Usage();
1071  EXIT(0);
1072  } // closes switch statement to process command-line options
1073 
1074  // Check to see if option had an unrecognized or incorrect argument.
1075  if (badarg) {
1076  printslogan();
1077  // It would be nice to print the actual option name given by the user
1078  // here, but we just print the short form. Please fix this if you know
1079  // a clean way to do it.
1080  char optstr[] = { (char)optchar, 0 };
1081  pout("=======> INVALID ARGUMENT TO -%s: %s\n",
1082  (optchar == opt_identify ? "-identify" :
1083  optchar == opt_set ? "-set" :
1084  optchar == opt_smart ? "-smart" : optstr), optarg);
1085  printvalidarglistmessage(optchar);
1086  if (extraerror[0])
1087  pout("=======> %s", extraerror);
1088  UsageSummary();
1089  EXIT(FAILCMD);
1090  }
1091  }
1092 
1093  // Special handling of --scan, --scanopen
1094  if (scan) {
1095  // Read or init drive database to allow USB ID check.
1096  if (!init_drive_database(use_default_db))
1097  EXIT(FAILCMD);
1098  scan_devices(scan_types, (scan == opt_scan_open), argv + optind);
1099  EXIT(0);
1100  }
1101 
1102  // At this point we have processed all command-line options. If the
1103  // print output is switchable, then start with the print output
1104  // turned off
1106  printing_is_off = true;
1107 
1108  // Check for multiple -d TYPE options
1109  if (scan_types.size() > 1) {
1110  printing_is_off = false;
1111  printslogan();
1112  pout("ERROR: multiple -d TYPE options are only allowed with --scan\n");
1113  UsageSummary();
1114  EXIT(FAILCMD);
1115  }
1116 
1117  // error message if user has asked for more than one test
1118  if (testcnt > 1) {
1119  printing_is_off = false;
1120  printslogan();
1121  pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n");
1122  UsageSummary();
1123  EXIT(FAILCMD);
1124  }
1125 
1126  // error message if user has set selective self-test options without
1127  // asking for a selective self-test
1129  && !ataopts.smart_selective_args.num_spans) {
1130  printing_is_off = false;
1131  printslogan();
1132  if (ataopts.smart_selective_args.pending_time)
1133  pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n");
1134  else
1135  pout("\nERROR: smartctl -t afterselect,(on|off) must be used with -t select,N-M.\n");
1136  UsageSummary();
1137  EXIT(FAILCMD);
1138  }
1139 
1140  // If captive option was used, change test type if appropriate.
1141  if (captive)
1142  switch (ataopts.smart_selftest_type) {
1143  case SHORT_SELF_TEST:
1145  scsiopts.smart_short_selftest = false;
1146  scsiopts.smart_short_cap_selftest = true;
1147  break;
1148  case EXTEND_SELF_TEST:
1150  scsiopts.smart_extend_selftest = false;
1151  scsiopts.smart_extend_cap_selftest = true;
1152  break;
1153  case CONVEYANCE_SELF_TEST:
1155  break;
1156  case SELECTIVE_SELF_TEST:
1158  break;
1159  }
1160 
1161  // From here on, normal operations...
1162  printslogan();
1163 
1164  // Warn if the user has provided no device name
1165  if (argc-optind<1){
1166  pout("ERROR: smartctl requires a device name as the final command-line argument.\n\n");
1167  UsageSummary();
1168  EXIT(FAILCMD);
1169  }
1170 
1171  // Warn if the user has provided more than one device name
1172  if (argc-optind>1){
1173  int i;
1174  pout("ERROR: smartctl takes ONE device name as the final command-line argument.\n");
1175  pout("You have provided %d device names:\n",argc-optind);
1176  for (i=0; i<argc-optind; i++)
1177  pout("%s\n",argv[optind+i]);
1178  UsageSummary();
1179  EXIT(FAILCMD);
1180  }
1181 
1182  // Read or init drive database
1183  if (!init_drive_database(use_default_db))
1184  EXIT(FAILCMD);
1185 
1186  return type;
1187 }
1188 
1189 // Printing function (controlled by global printing_is_off)
1190 // [From GLIBC Manual: Since the prototype doesn't specify types for
1191 // optional arguments, in a call to a variadic function the default
1192 // argument promotions are performed on the optional argument
1193 // values. This means the objects of type char or short int (whether
1194 // signed or not) are promoted to either int or unsigned int, as
1195 // appropriate.]
1196 void pout(const char *fmt, ...){
1197  va_list ap;
1198 
1199  // initialize variable argument list
1200  va_start(ap,fmt);
1201  if (printing_is_off) {
1202  va_end(ap);
1203  return;
1204  }
1205 
1206  // print out
1207  vprintf(fmt,ap);
1208  va_end(ap);
1209  fflush(stdout);
1210  return;
1211 }
1212 
1213 // Globals to set failuretest() policy
1215 unsigned char failuretest_permissive = 0;
1216 
1217 // Compares failure type to policy in effect, and either exits or
1218 // simply returns to the calling routine.
1219 // Used in ataprint.cpp and scsiprint.cpp.
1220 void failuretest(failure_type type, int returnvalue)
1221 {
1222  // If this is an error in an "optional" SMART command
1223  if (type == OPTIONAL_CMD) {
1224  if (!failuretest_conservative)
1225  return;
1226  pout("An optional SMART command failed: exiting. Remove '-T conservative' option to continue.\n");
1227  EXIT(returnvalue);
1228  }
1229 
1230  // If this is an error in a "mandatory" SMART command
1231  if (type == MANDATORY_CMD) {
1232  if (failuretest_permissive--)
1233  return;
1234  pout("A mandatory SMART command failed: exiting. To continue, add one or more '-T permissive' options.\n");
1235  EXIT(returnvalue);
1236  }
1237 
1238  throw std::logic_error("failuretest: Unknown type");
1239 }
1240 
1241 // Used to warn users about invalid checksums. Called from atacmds.cpp.
1242 // Action to be taken may be altered by the user.
1243 void checksumwarning(const char * string)
1244 {
1245  // user has asked us to ignore checksum errors
1247  return;
1248 
1249  pout("Warning! %s error: invalid SMART checksum.\n", string);
1250 
1251  // user has asked us to fail on checksum errors
1253  EXIT(FAILSMART);
1254 }
1255 
1256 // Return info string about device protocol
1257 static const char * get_protocol_info(const smart_device * dev)
1258 {
1259  switch ( (int)dev->is_ata()
1260  | ((int)dev->is_scsi() << 1)
1261  | ((int)dev->is_nvme() << 2)) {
1262  case 0x1: return "ATA";
1263  case 0x2: return "SCSI";
1264  case 0x3: return "ATA+SCSI";
1265  case 0x4: return "NVMe";
1266  default: return "Unknown";
1267  }
1268 }
1269 
1270 // Device scan
1271 // smartctl [-d type] --scan[-open] -- [PATTERN] [smartd directive ...]
1272 void scan_devices(const smart_devtype_list & types, bool with_open, char ** argv)
1273 {
1274  bool dont_print = !(ata_debugmode || scsi_debugmode || nvme_debugmode);
1275 
1276  const char * pattern = 0;
1277  int ai = 0;
1278  if (argv[ai] && argv[ai][0] != '-')
1279  pattern = argv[ai++];
1280 
1281  smart_device_list devlist;
1282  printing_is_off = dont_print;
1283  bool ok = smi()->scan_smart_devices(devlist, types, pattern);
1284  printing_is_off = false;
1285 
1286  if (!ok) {
1287  pout("# scan_smart_devices: %s\n", smi()->get_errmsg());
1288  return;
1289  }
1290 
1291  for (unsigned i = 0; i < devlist.size(); i++) {
1292  smart_device_auto_ptr dev( devlist.release(i) );
1293 
1294  if (with_open) {
1295  printing_is_off = dont_print;
1296  dev.replace ( dev->autodetect_open() );
1297  printing_is_off = false;
1298 
1299  if (!dev->is_open()) {
1300  pout("# %s -d %s # %s, %s device open failed: %s\n", dev->get_dev_name(),
1301  dev->get_dev_type(), dev->get_info_name(),
1302  get_protocol_info(dev.get()), dev->get_errmsg());
1303  continue;
1304  }
1305  }
1306 
1307  pout("%s -d %s", dev->get_dev_name(), dev->get_dev_type());
1308  if (!argv[ai])
1309  pout(" # %s, %s device\n", dev->get_info_name(), get_protocol_info(dev.get()));
1310  else {
1311  for (int j = ai; argv[j]; j++)
1312  pout(" %s", argv[j]);
1313  pout("\n");
1314  }
1315 
1316  if (dev->is_open())
1317  dev->close();
1318  }
1319 }
1320 
1321 // Main program without exception handling
1322 static int main_worker(int argc, char **argv)
1323 {
1324  // Throw if runtime environment does not match compile time test.
1325  check_config();
1326 
1327  // Initialize interface
1329  if (!smi())
1330  return 1;
1331 
1332  // Parse input arguments
1333  ata_print_options ataopts;
1334  scsi_print_options scsiopts;
1335  nvme_print_options nvmeopts;
1336  bool print_type_only = false;
1337  const char * type = parse_options(argc, argv, ataopts, scsiopts, nvmeopts, print_type_only);
1338 
1339  const char * name = argv[argc-1];
1340 
1342  if (!strcmp(name,"-")) {
1343  // Parse "smartctl -r ataioctl,2 ..." output from stdin
1344  if (type || print_type_only) {
1345  pout("-d option is not allowed in conjunction with device name \"-\".\n");
1346  UsageSummary();
1347  return FAILCMD;
1348  }
1349  dev = get_parsed_ata_device(smi(), name);
1350  }
1351  else
1352  // get device of appropriate type
1353  dev = smi()->get_smart_device(name, type);
1354 
1355  if (!dev) {
1356  pout("%s: %s\n", name, smi()->get_errmsg());
1357  if (type)
1359  else
1360  pout("Please specify device type with the -d option.\n");
1361  UsageSummary();
1362  return FAILCMD;
1363  }
1364 
1365  if (print_type_only)
1366  // Report result of first autodetection
1367  pout("%s: Device of type '%s' [%s] detected\n",
1368  dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
1369 
1370  if (dev->is_ata() && ataopts.powermode>=2 && dev->is_powered_down()) {
1371  pout("Device is in STANDBY (OS) mode, exit(%d)\n", ataopts.powerexit);
1372  return ataopts.powerexit;
1373  }
1374 
1375  // Open device
1376  {
1377  // Save old info
1378  smart_device::device_info oldinfo = dev->get_info();
1379 
1380  // Open with autodetect support, may return 'better' device
1381  dev.replace( dev->autodetect_open() );
1382 
1383  // Report if type has changed
1384  if ( (ata_debugmode || scsi_debugmode || nvme_debugmode || print_type_only)
1385  && oldinfo.dev_type != dev->get_dev_type() )
1386  pout("%s: Device open changed type from '%s' to '%s'\n",
1387  dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type());
1388  }
1389  if (!dev->is_open()) {
1390  pout("Smartctl open device: %s failed: %s\n", dev->get_info_name(), dev->get_errmsg());
1391  return FAILDEV;
1392  }
1393 
1394  // now call appropriate ATA or SCSI routine
1395  int retval = 0;
1396  if (print_type_only)
1397  pout("%s: Device of type '%s' [%s] opened\n",
1398  dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
1399  else if (dev->is_ata())
1400  retval = ataPrintMain(dev->to_ata(), ataopts);
1401  else if (dev->is_scsi())
1402  retval = scsiPrintMain(dev->to_scsi(), scsiopts);
1403  else if (dev->is_nvme())
1404  retval = nvmePrintMain(dev->to_nvme(), nvmeopts);
1405  else
1406  // we should never fall into this branch!
1407  pout("%s: Neither ATA, SCSI nor NVMe device\n", dev->get_info_name());
1408 
1409  dev->close();
1410  return retval;
1411 }
1412 
1413 
1414 // Main program
1415 int main(int argc, char **argv)
1416 {
1417  int status;
1418  bool badcode = false;
1419 
1420  try {
1421  // Do the real work ...
1422  status = main_worker(argc, argv);
1423  }
1424  catch (int ex) {
1425  // EXIT(status) arrives here
1426  status = ex;
1427  }
1428  catch (const std::bad_alloc & /*ex*/) {
1429  // Memory allocation failed (also thrown by std::operator new)
1430  printf("Smartctl: Out of memory\n");
1431  status = FAILCMD;
1432  }
1433  catch (const std::exception & ex) {
1434  // Other fatal errors
1435  printf("Smartctl: Exception: %s\n", ex.what());
1436  badcode = true;
1437  status = FAILCMD;
1438  }
1439 
1440  // Check for remaining device objects
1441  if (smart_device::get_num_objects() != 0) {
1442  printf("Smartctl: Internal Error: %d device object(s) left at exit.\n",
1444  badcode = true;
1445  status = FAILCMD;
1446  }
1447 
1448  if (badcode)
1449  printf("Please inform " PACKAGE_BUGREPORT ", including output of smartctl -V.\n");
1450 
1451  return status;
1452 }
1453 
#define CONVEYANCE_CAPTIVE_SELF_TEST
Definition: atacmds.h:124
checksum_err_mode_t
Definition: smartctl.cpp:262
int main(int argc, char **argv)
Definition: smartctl.cpp:1415
#define PRIu64
Definition: int64.h:76
static void UsageSummary()
Definition: smartctl.cpp:67
unsigned char failuretest_permissive
Definition: smartctl.cpp:1215
u16 s[6]
Definition: megaraid.h:97
bool sct_wcache_sct_get
Definition: ataprint.h:113
unsigned page
Definition: ataprint.h:37
virtual std::string get_valid_dev_types_str()
Return valid args for device type option/directive.
u32 size
Definition: megaraid.h:79
short int set_rcd
Definition: scsiprint.h:57
ata_vendor_attr_defs attribute_defs
Definition: ataprint.h:90
bool parse_attribute_def(const char *opt, ata_vendor_attr_defs &defs, ata_vendor_def_prior priority)
Definition: atacmds.cpp:159
bool sct_wcache_sct_set_pers
Definition: ataprint.h:115
static int main_worker(int argc, char **argv)
Definition: smartctl.cpp:1322
static void Usage()
Definition: smartctl.cpp:76
firmwarebug_defs firmwarebugs
Definition: ataprint.h:87
bool smart_auto_save_enable
Definition: scsiprint.h:46
const char * get_valid_firmwarebug_args()
Definition: atacmds.cpp:307
bool smart_error_log
Definition: ataprint.h:53
bool sct_wcache_reorder_get
Definition: ataprint.h:110
int smart_selftest_type
Definition: ataprint.h:77
bool str_starts_with(const char *str, const char *prefix)
Definition: utility.h:57
const char * get_drivedb_path_add()
Smart pointer class for device pointers.
smart_interface * smi()
Global access to the (usually singleton) smart_interface.
std::string format_version_info(const char *prog_name, bool full)
Definition: utility.cpp:83
bool smart_vendor_attrib
Definition: nvmeprint.h:31
bool smart_default_selftest
Definition: scsiprint.h:48
bool smart_selective_selftest_log
Definition: ataprint.h:55
bool smart_disable
Definition: ataprint.h:73
bool sct_temp_hist
Definition: ataprint.h:67
bool read_drive_database(const char *path)
int identify_bit_level
Definition: ataprint.h:49
bool smart_background_log
Definition: scsiprint.h:42
bool printing_is_off
Definition: smartctl.cpp:60
bool smart_selftest_force
Definition: ataprint.h:78
#define EXTEND_SELF_TEST
Definition: atacmds.h:118
#define FAILSMART
Definition: smartctl.h:46
#define snprintf
Definition: utility.h:68
bool smart_selftest_force
Definition: scsiprint.h:52
bool is_nvme() const
Return true if NVMe device.
Definition: dev_interface.h:99
bool smart_check_status
Definition: scsiprint.h:38
unsigned char ata_debugmode
Definition: atacmds.cpp:43
bool drive_capabilities
Definition: nvmeprint.h:29
unsigned log_page_size
Definition: nvmeprint.h:34
#define FAILPOWER
Definition: smartctl.h:40
std::vector< int > devstat_pages
Definition: ataprint.h:65
#define FAILCMD
Definition: smartctl.h:34
virtual smart_device * get_smart_device(const char *name, const char *type)
Return device object for device 'name' with some 'type'.
#define SMARTCTL_H_CVSID
Definition: smartctl.h:29
const char * smartctl_cpp_cvsid
Definition: smartctl.cpp:55
unsigned sct_erc_writetime
Definition: ataprint.h:70
unsigned char nvme_debugmode
Definition: nvmecmds.cpp:39
unsigned char log_page
Definition: nvmeprint.h:33
bool smart_short_cap_selftest
Definition: scsiprint.h:49
bool failuretest_conservative
Definition: smartctl.cpp:1214
bool smart_auto_save_disable
Definition: scsiprint.h:46
std::string dev_type
Actual device type.
Definition: dev_interface.h:54
unsigned smart_ext_selftest_log
Definition: ataprint.h:59
#define SELECTIVE_SELF_TEST
Definition: atacmds.h:120
List of devices for DEVICESCAN.
ata_selective_selftest_args smart_selective_args
Definition: ataprint.h:79
short int set_wce
Definition: scsiprint.h:57
static int get_num_objects()
Get current number of allocated 'smart_device' objects.
void checksumwarning(const char *string)
Definition: smartctl.cpp:1243
bool retry_error_log
Definition: ataprint.h:60
#define PRId64
Definition: int64.h:72
device_type * get() const
Return the pointer.
bool fix_swapped_id
Definition: ataprint.h:88
static checksum_err_mode_t checksum_err_mode
Definition: smartctl.cpp:266
static void init()
Initialize platform interface and register with smi().
Definition: dev_legacy.cpp:341
std::vector< std::string > smart_devtype_list
List of types for DEVICESCAN.
bool set_security_freeze
Definition: ataprint.h:107
unsigned char output_format
Definition: ataprint.h:85
#define FAILDEV
Definition: smartctl.h:37
void replace(device_type *dev)
Replace the pointer.
bool smart_auto_save_enable
Definition: ataprint.h:75
#define ABORT_SELF_TEST
Definition: atacmds.h:121
unsigned char logaddr
Definition: ataprint.h:36
bool dont_print_serial_number
Definition: atacmds.cpp:47
void check_config()
Definition: utility.cpp:805
unsigned char scsi_debugmode
Definition: scsicmds.cpp:54
smart_device * release(unsigned i)
bool smart_general_values
Definition: ataprint.h:51
bool is_ata() const
Return true if ATA device.
Definition: dev_interface.h:93
void pout(const char *fmt,...)
Definition: smartctl.cpp:1196
int showmatchingpresets(const char *model, const char *firmware)
virtual std::string get_app_examples(const char *appname)
Return example string for program 'appname'.
#define OFFLINE_FULL_SCAN
Definition: atacmds.h:116
unsigned sct_temp_int
Definition: ataprint.h:81
bool smart_selftest_log
Definition: ataprint.h:54
static const char * parse_options(int argc, char **argv, ata_print_options &ataopts, scsi_print_options &scsiopts, nvme_print_options &nvmeopts, bool &print_type_only)
Definition: smartctl.cpp:272
bool sct_temp_int_pers
Definition: ataprint.h:82
bool retry_selftest_log
Definition: ataprint.h:60
ata_device * get_parsed_ata_device(smart_interface *intf, const char *dev_name)
Definition: atacmds.cpp:3049
bool sct_wcache_reorder_set_pers
Definition: ataprint.h:112
int ataPrintMain(ata_device *device, const ata_print_options &options)
Definition: ataprint.cpp:2547
Device info strings.
Definition: dev_interface.h:44
unsigned char powerexit
Definition: ataprint.h:95
bool smart_auto_offl_disable
Definition: ataprint.h:74
#define CONVEYANCE_SELF_TEST
Definition: atacmds.h:119
bool smart_check_status
Definition: nvmeprint.h:30
static void printvalidarglistmessage(int opt)
Definition: smartctl.cpp:244
static std::string getvalidarglist(int opt)
Definition: smartctl.cpp:188
unsigned size() const
bool parse_firmwarebug_def(const char *opt, firmwarebug_defs &firmwarebugs)
Definition: atacmds.cpp:287
#define EXTEND_CAPTIVE_SELF_TEST
Definition: atacmds.h:123
#define SELECTIVE_CAPTIVE_SELF_TEST
Definition: atacmds.h:125
bool is_scsi() const
Return true if SCSI device.
Definition: dev_interface.h:96
bool smart_ss_media_log
Definition: scsiprint.h:43
virtual bool scan_smart_devices(smart_device_list &devlist, const char *type, const char *pattern=0)=0
Fill 'devlist' with devices of some 'type' with device names specified by some optional 'pattern'...
int sct_wcache_sct_set
Definition: ataprint.h:114
Base class for all devices.
Definition: dev_interface.h:39
bool ignore_presets
Definition: ataprint.h:92
bool set_standby_now
Definition: ataprint.h:105
#define SHORT_SELF_TEST
Definition: atacmds.h:117
int scsiPrintMain(scsi_device *device, const scsi_print_options &options)
Definition: scsiprint.cpp:1889
#define EXIT(status)
Definition: utility.h:100
unsigned long long uint64_t
Definition: int64.h:54
bool init_drive_database(bool use_default_db)
bool devstat_all_pages
Definition: ataprint.h:64
bool smart_selftest_log
Definition: scsiprint.h:41
static const char * get_protocol_info(const smart_device *dev)
Definition: smartctl.cpp:1257
bool smart_short_selftest
Definition: scsiprint.h:49
bool smart_vendor_attrib
Definition: ataprint.h:52
unsigned char powermode
Definition: ataprint.h:94
bool smart_check_status
Definition: ataprint.h:50
bool smart_extend_selftest
Definition: scsiprint.h:50
bool smart_extend_cap_selftest
Definition: scsiprint.h:50
unsigned sct_erc_readtime
Definition: ataprint.h:70
failure_type
Definition: smartctl.h:69
bool smart_auto_save_disable
Definition: ataprint.h:75
unsigned nsectors
Definition: ataprint.h:38
static void scan_devices(const smart_devtype_list &types, bool with_open, char **argv)
Definition: smartctl.cpp:1272
void failuretest(failure_type type, int returnvalue)
Definition: smartctl.cpp:1220
int nvmePrintMain(nvme_device *device, const nvme_print_options &options)
Definition: nvmeprint.cpp:363
std::vector< ata_log_request > log_requests
Definition: ataprint.h:62
unsigned error_log_entries
Definition: nvmeprint.h:32
bool devstat_ssd_page
Definition: ataprint.h:64
unsigned smart_ext_error_log
Definition: ataprint.h:58
int showallpresets()
bool smart_selftest_abort
Definition: scsiprint.h:51
int identify_word_level
Definition: ataprint.h:49
int split_selective_arg(char *s, uint64_t *start, uint64_t *stop, int *mode)
Definition: utility.cpp:581
int sct_wcache_reorder_set
Definition: ataprint.h:111
std::string create_vendor_attribute_arg_list()
Definition: atacmds.cpp:272
bool printing_is_switchable
Definition: smartctl.cpp:59
bool sataphy_reset
Definition: ataprint.h:71
static void printslogan()
Definition: smartctl.cpp:62
#define SHORT_CAPTIVE_SELF_TEST
Definition: atacmds.h:122
bool smart_auto_offl_enable
Definition: ataprint.h:74
bool smart_vendor_attrib
Definition: scsiprint.h:39