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