]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - smartctl.cpp
Merge commit 'upstream/5.38+svn2993'
[mirror_smartmontools-debian.git] / smartctl.cpp
1 /*
2 * smartctl.cpp
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 *
6 * Copyright (C) 2002-9 Bruce Allen <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
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, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * This code was originally developed as a Senior Thesis by Michael Cornwell
20 * at the Concurrent Systems Laboratory (now part of the Storage Systems
21 * Research Center), Jack Baskin School of Engineering, University of
22 * California, Santa Cruz. http://ssrc.soe.ucsc.edu/
23 *
24 */
25
26 #include <errno.h>
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <string.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 #if defined(__QNXNTO__)
45 #include <new> // TODO: Why is this include necessary on QNX ?
46 #endif
47
48 #include "int64.h"
49 #include "atacmds.h"
50 #include "dev_interface.h"
51 #include "ataprint.h"
52 #include "extern.h"
53 #include "knowndrives.h"
54 #include "scsicmds.h"
55 #include "scsiprint.h"
56 #include "smartctl.h"
57 #include "utility.h"
58
59 const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp 2975 2009-10-29 22:52:38Z chrfranke $"
60 CONFIG_H_CVSID EXTERN_H_CVSID SMARTCTL_H_CVSID;
61
62 // This is a block containing all the "control variables". We declare
63 // this globally in this file, and externally in other files.
64 smartmonctrl *con=NULL;
65
66 static void printslogan()
67 {
68 pout("%s\n", format_version_info("smartctl").c_str());
69 }
70
71 void UsageSummary(){
72 pout("\nUse smartctl -h to get a usage summary\n\n");
73 return;
74 }
75
76 static std::string getvalidarglist(char opt);
77
78 /* void prints help information for command syntax */
79 void Usage (void){
80 printf("Usage: smartctl [options] device\n\n");
81 printf(
82 "============================================ SHOW INFORMATION OPTIONS =====\n\n"
83 " -h, --help, --usage\n"
84 " Display this help and exit\n\n"
85 " -V, --version, --copyright, --license\n"
86 " Print license, copyright, and version information and exit\n\n"
87 " -i, --info \n"
88 " Show identity information for device\n\n"
89 " -a, --all \n"
90 " Show all SMART information for device\n\n"
91 " -x, --xall\n"
92 " Show all information for device\n\n"
93 );
94 printf(
95 "================================== SMARTCTL RUN-TIME BEHAVIOR OPTIONS =====\n\n"
96 " -q TYPE, --quietmode=TYPE (ATA)\n"
97 " Set smartctl quiet mode to one of: errorsonly, silent, noserial\n\n"
98 " -d TYPE, --device=TYPE\n"
99 " Specify device type to one of: %s\n\n"
100 " -T TYPE, --tolerance=TYPE (ATA)\n"
101 " Tolerance: normal, conservative, permissive, verypermissive\n\n"
102 " -b TYPE, --badsum=TYPE (ATA)\n"
103 " Set action on bad checksum to one of: warn, exit, ignore\n\n"
104 " -r TYPE, --report=TYPE\n"
105 " Report transactions (see man page)\n\n"
106 " -n MODE, --nocheck=MODE (ATA)\n"
107 " No check if: never, sleep, standby, idle (see man page)\n\n",
108 getvalidarglist('d').c_str()); // TODO: Use this function also for other options ?
109 printf(
110 "============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n"
111 " -s VALUE, --smart=VALUE\n"
112 " Enable/disable SMART on device (on/off)\n\n"
113 " -o VALUE, --offlineauto=VALUE (ATA)\n"
114 " Enable/disable automatic offline testing on device (on/off)\n\n"
115 " -S VALUE, --saveauto=VALUE (ATA)\n"
116 " Enable/disable Attribute autosave on device (on/off)\n\n"
117 );
118 printf(
119 "======================================= READ AND DISPLAY DATA OPTIONS =====\n\n"
120 " -H, --health\n"
121 " Show device SMART health status\n\n"
122 " -c, --capabilities (ATA)\n"
123 " Show device SMART capabilities\n\n"
124 " -A, --attributes \n"
125 " Show device SMART vendor-specific Attributes and values\n\n"
126 " -l TYPE, --log=TYPE\n"
127 " Show device log. TYPE: error, selftest, selective, directory[,g|s],\n"
128 " background, sasphy[,reset], sataphy[,reset],\n"
129 " scttemp[sts,hist],\n"
130 " gplog,N[,RANGE], smartlog,N[,RANGE],\n"
131 " xerror[,N][,error], xselftest[,N][,selftest]\n\n"
132 " -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n"
133 " Set display OPTION for vendor Attribute N (see man page)\n\n"
134 " -F TYPE, --firmwarebug=TYPE (ATA)\n"
135 " Use firmware bug workaround: none, samsung, samsung2,\n"
136 " samsung3, swapid\n\n"
137 " -P TYPE, --presets=TYPE (ATA)\n"
138 " Drive-specific presets: use, ignore, show, showall\n\n"
139 " -B [+]FILE, --drivedb=[+]FILE (ATA)\n"
140 " Read and replace [add] drive database from FILE\n"
141 #ifdef SMARTMONTOOLS_DRIVEDBDIR
142 " [default is "SMARTMONTOOLS_DRIVEDBDIR"/drivedb.h]\n"
143 #endif
144 "\n"
145 );
146 printf(
147 "============================================ DEVICE SELF-TEST OPTIONS =====\n\n"
148 " -t TEST, --test=TEST\n"
149 " Run test. TEST: offline short long conveyance select,M-N\n"
150 " pending,N afterselect,[on|off] scttempint,N[,p]\n\n"
151 " -C, --captive\n"
152 " Do test in captive mode (along with -t)\n\n"
153 " -X, --abort\n"
154 " Abort any non-captive test on device\n\n"
155 );
156 std::string examples = smi()->get_app_examples("smartctl");
157 if (!examples.empty())
158 printf("%s\n", examples.c_str());
159 }
160
161 /* Returns a string containing a formatted list of the valid arguments
162 to the option opt or empty on failure. Note 'v' case different */
163 static std::string getvalidarglist(char opt)
164 {
165 switch (opt) {
166 case 'q':
167 return "errorsonly, silent, noserial";
168 case 'd':
169 return smi()->get_valid_dev_types_str() + ", test";
170 case 'T':
171 return "normal, conservative, permissive, verypermissive";
172 case 'b':
173 return "warn, exit, ignore";
174 case 'r':
175 return "ioctl[,N], ataioctl[,N], scsiioctl[,N]";
176 case 's':
177 case 'o':
178 case 'S':
179 return "on, off";
180 case 'l':
181 return "error, selftest, selective, directory[,g|s], background, scttemp[sts|hist], "
182 "sasphy[,reset], sataphy[,reset], gplog,N[,RANGE], smartlog,N[,RANGE], "
183 "xerror[,N][,error], xselftest[,N][,selftest]";
184 case 'P':
185 return "use, ignore, show, showall";
186 case 't':
187 return "offline, short, long, conveyance, select,M-N, pending,N, afterselect,[on|off], scttempint,N[,p]";
188 case 'F':
189 return "none, samsung, samsung2, samsung3, swapid";
190 case 'n':
191 return "never, sleep, standby, idle";
192 case 'v':
193 default:
194 return "";
195 }
196 }
197
198 /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where
199 <LIST> is the list of valid arguments for option opt. */
200 void printvalidarglistmessage(char opt) {
201
202 if (opt=='v'){
203 pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n",
204 create_vendor_attribute_arg_list().c_str());
205 }
206 else {
207 // getvalidarglist() might produce a multiline or single line string. We
208 // need to figure out which to get the formatting right.
209 std::string s = getvalidarglist(opt);
210 char separator = strchr(s.c_str(), '\n') ? '\n' : ' ';
211 pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, s.c_str(), separator);
212 }
213
214 return;
215 }
216
217 // Checksum error mode
218 enum checksum_err_mode_t {
219 CHECKSUM_ERR_WARN, CHECKSUM_ERR_EXIT, CHECKSUM_ERR_IGNORE
220 };
221
222 static checksum_err_mode_t checksum_err_mode = CHECKSUM_ERR_WARN;
223
224 /* Takes command options and sets features to be run */
225 const char * parse_options(int argc, char** argv,
226 ata_print_options & ataopts,
227 scsi_print_options & scsiopts)
228 {
229 // Please update getvalidarglist() if you edit shortopts
230 const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iaxv:P:t:CXF:n:B:";
231 // Please update getvalidarglist() if you edit longopts
232 struct option longopts[] = {
233 { "help", no_argument, 0, 'h' },
234 { "usage", no_argument, 0, 'h' },
235 { "version", no_argument, 0, 'V' },
236 { "copyright", no_argument, 0, 'V' },
237 { "license", no_argument, 0, 'V' },
238 { "quietmode", required_argument, 0, 'q' },
239 { "device", required_argument, 0, 'd' },
240 { "tolerance", required_argument, 0, 'T' },
241 { "badsum", required_argument, 0, 'b' },
242 { "report", required_argument, 0, 'r' },
243 { "smart", required_argument, 0, 's' },
244 { "offlineauto", required_argument, 0, 'o' },
245 { "saveauto", required_argument, 0, 'S' },
246 { "health", no_argument, 0, 'H' },
247 { "capabilities", no_argument, 0, 'c' },
248 { "attributes", no_argument, 0, 'A' },
249 { "log", required_argument, 0, 'l' },
250 { "info", no_argument, 0, 'i' },
251 { "all", no_argument, 0, 'a' },
252 { "xall", no_argument, 0, 'x' },
253 { "vendorattribute", required_argument, 0, 'v' },
254 { "presets", required_argument, 0, 'P' },
255 { "test", required_argument, 0, 't' },
256 { "captive", no_argument, 0, 'C' },
257 { "abort", no_argument, 0, 'X' },
258 { "firmwarebug", required_argument, 0, 'F' },
259 { "nocheck", required_argument, 0, 'n' },
260 { "drivedb", required_argument, 0, 'B' },
261 { 0, 0, 0, 0 }
262 };
263
264 char extraerror[256];
265 memset(extraerror, 0, sizeof(extraerror));
266 memset(con,0,sizeof(*con));
267 opterr=optopt=0;
268
269 const char * type = 0; // set to -d optarg
270 bool no_defaultdb = false; // set true on '-B FILE'
271 bool badarg = false, captive = false;
272 int testcnt = 0; // number of self-tests requested
273
274 int optchar;
275 char *arg;
276
277 // This miserable construction is needed to get emacs to do proper indenting. Sorry!
278 while (-1 != (optchar =
279 getopt_long(argc, argv, shortopts, longopts, NULL)
280 )){
281 switch (optchar){
282 case 'V':
283 con->dont_print = false;
284 pout("%s", format_version_info("smartctl", true /*full*/).c_str());
285 EXIT(0);
286 break;
287 case 'q':
288 if (!strcmp(optarg,"errorsonly")) {
289 con->printing_switchable = true;
290 con->dont_print = false;
291 } else if (!strcmp(optarg,"silent")) {
292 con->printing_switchable = false;
293 con->dont_print = true;
294 } else if (!strcmp(optarg,"noserial")) {
295 con->dont_print_serial = true;
296 } else {
297 badarg = true;
298 }
299 break;
300 case 'd':
301 type = optarg;
302 break;
303 case 'T':
304 if (!strcmp(optarg,"normal")) {
305 con->conservative = false;
306 con->permissive = 0;
307 } else if (!strcmp(optarg,"conservative")) {
308 con->conservative = true;
309 } else if (!strcmp(optarg,"permissive")) {
310 if (con->permissive<0xff)
311 con->permissive++;
312 } else if (!strcmp(optarg,"verypermissive")) {
313 con->permissive = 0xff;
314 } else {
315 badarg = true;
316 }
317 break;
318 case 'b':
319 if (!strcmp(optarg,"warn")) {
320 checksum_err_mode = CHECKSUM_ERR_WARN;
321 } else if (!strcmp(optarg,"exit")) {
322 checksum_err_mode = CHECKSUM_ERR_EXIT;
323 } else if (!strcmp(optarg,"ignore")) {
324 checksum_err_mode = CHECKSUM_ERR_IGNORE;
325 } else {
326 badarg = true;
327 }
328 break;
329 case 'r':
330 {
331 int i;
332 char *s;
333
334 // split_report_arg() may modify its first argument string, so use a
335 // copy of optarg in case we want optarg for an error message.
336 if (!(s = strdup(optarg))) {
337 throw std::bad_alloc();
338 }
339 if (split_report_arg(s, &i)) {
340 badarg = true;
341 } else if (!strcmp(s,"ioctl")) {
342 con->reportataioctl = con->reportscsiioctl = i;
343 } else if (!strcmp(s,"ataioctl")) {
344 con->reportataioctl = i;
345 } else if (!strcmp(s,"scsiioctl")) {
346 con->reportscsiioctl = i;
347 } else {
348 badarg = true;
349 }
350 free(s);
351 }
352 break;
353 case 's':
354 if (!strcmp(optarg,"on")) {
355 ataopts.smart_enable = scsiopts.smart_enable = true;
356 ataopts.smart_disable = scsiopts.smart_disable = false;
357 } else if (!strcmp(optarg,"off")) {
358 ataopts.smart_disable = scsiopts.smart_disable = true;
359 ataopts.smart_enable = scsiopts.smart_enable = false;
360 } else {
361 badarg = true;
362 }
363 break;
364 case 'o':
365 if (!strcmp(optarg,"on")) {
366 ataopts.smart_auto_offl_enable = true;
367 ataopts.smart_auto_offl_disable = false;
368 } else if (!strcmp(optarg,"off")) {
369 ataopts.smart_auto_offl_disable = true;
370 ataopts.smart_auto_offl_enable = false;
371 } else {
372 badarg = true;
373 }
374 break;
375 case 'S':
376 if (!strcmp(optarg,"on")) {
377 ataopts.smart_auto_save_enable = scsiopts.smart_auto_save_enable = true;
378 ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = false;
379 } else if (!strcmp(optarg,"off")) {
380 ataopts.smart_auto_save_disable = scsiopts.smart_auto_save_disable = true;
381 ataopts.smart_auto_save_enable = scsiopts.smart_auto_save_enable = false;
382 } else {
383 badarg = true;
384 }
385 break;
386 case 'H':
387 ataopts.smart_check_status = scsiopts.smart_check_status = true;
388 break;
389 case 'F':
390 if (!strcmp(optarg,"none")) {
391 ataopts.fix_firmwarebug = FIX_NONE;
392 } else if (!strcmp(optarg,"samsung")) {
393 ataopts.fix_firmwarebug = FIX_SAMSUNG;
394 } else if (!strcmp(optarg,"samsung2")) {
395 ataopts.fix_firmwarebug = FIX_SAMSUNG2;
396 } else if (!strcmp(optarg,"samsung3")) {
397 ataopts.fix_firmwarebug = FIX_SAMSUNG3;
398 } else if (!strcmp(optarg,"swapid")) {
399 ataopts.fix_swapped_id = true;
400 } else {
401 badarg = true;
402 }
403 break;
404 case 'c':
405 ataopts.smart_general_values = true;
406 break;
407 case 'A':
408 ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true;
409 break;
410 case 'l':
411 if (!strcmp(optarg,"error")) {
412 ataopts.smart_error_log = scsiopts.smart_error_log = true;
413 } else if (!strcmp(optarg,"selftest")) {
414 ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true;
415 } else if (!strcmp(optarg, "selective")) {
416 ataopts.smart_selective_selftest_log = true;
417 } else if (!strcmp(optarg,"directory")) {
418 ataopts.smart_logdir = ataopts.gp_logdir = true; // SMART+GPL
419 } else if (!strcmp(optarg,"directory,s")) {
420 ataopts.smart_logdir = true; // SMART
421 } else if (!strcmp(optarg,"directory,g")) {
422 ataopts.gp_logdir = true; // GPL
423 } else if (!strcmp(optarg,"sasphy")) {
424 scsiopts.sasphy = true;
425 } else if (!strcmp(optarg,"sasphy,reset")) {
426 scsiopts.sasphy = scsiopts.sasphy_reset = true;
427 } else if (!strcmp(optarg,"sataphy")) {
428 ataopts.sataphy = true;
429 } else if (!strcmp(optarg,"sataphy,reset")) {
430 ataopts.sataphy = ataopts.sataphy_reset = true;
431 } else if (!strcmp(optarg,"background")) {
432 scsiopts.smart_background_log = true;
433 } else if (!strcmp(optarg,"scttemp")) {
434 ataopts.sct_temp_sts = ataopts.sct_temp_hist = true;
435 } else if (!strcmp(optarg,"scttempsts")) {
436 ataopts.sct_temp_sts = true;
437 } else if (!strcmp(optarg,"scttemphist")) {
438 ataopts.sct_temp_hist = true;
439
440 } else if (!strncmp(optarg, "xerror", sizeof("xerror")-1)) {
441 int n1 = -1, n2 = -1, len = strlen(optarg);
442 unsigned val = 8;
443 sscanf(optarg, "xerror%n,error%n", &n1, &n2);
444 if (!(n1 == len || n2 == len)) {
445 n1 = n2 = -1;
446 sscanf(optarg, "xerror,%u%n,error%n", &val, &n1, &n2);
447 }
448 if ((n1 == len || n2 == len) && val > 0) {
449 ataopts.smart_ext_error_log = val;
450 ataopts.retry_error_log = (n2 == len);
451 }
452 else
453 badarg = true;
454
455 } else if (!strncmp(optarg, "xselftest", sizeof("xselftest")-1)) {
456 int n1 = -1, n2 = -1, len = strlen(optarg);
457 unsigned val = 25;
458 sscanf(optarg, "xselftest%n,selftest%n", &n1, &n2);
459 if (!(n1 == len || n2 == len)) {
460 n1 = n2 = -1;
461 sscanf(optarg, "xselftest,%u%n,selftest%n", &val, &n1, &n2);
462 }
463 if ((n1 == len || n2 == len) && val > 0) {
464 ataopts.smart_ext_selftest_log = val;
465 ataopts.retry_selftest_log = (n2 == len);
466 }
467 else
468 badarg = true;
469
470 } else if ( !strncmp(optarg, "gplog," , sizeof("gplog," )-1)
471 || !strncmp(optarg, "smartlog,", sizeof("smartlog,")-1)) {
472 unsigned logaddr = ~0U; unsigned page = 0, nsectors = 1; char sign = 0;
473 int n1 = -1, n2 = -1, n3 = -1, len = strlen(optarg);
474 sscanf(optarg, "%*[a-z],0x%x%n,%u%n%c%u%n",
475 &logaddr, &n1, &page, &n2, &sign, &nsectors, &n3);
476 if (len > n2 && n3 == -1 && !strcmp(optarg+n2, "-max")) {
477 nsectors = ~0U; sign = '+'; n3 = len;
478 }
479 bool gpl = (optarg[0] == 'g');
480 const char * erropt = (gpl ? "gplog" : "smartlog");
481 if (!( n1 == len || n2 == len
482 || (n3 == len && (sign == '+' || sign == '-')))) {
483 sprintf(extraerror, "Option -l %s,ADDR[,FIRST[-LAST|+SIZE]] syntax error\n", erropt);
484 badarg = true;
485 }
486 else if (!( logaddr <= 0xff && page <= (gpl ? 0xffffU : 0x00ffU)
487 && 0 < nsectors
488 && (nsectors <= (gpl ? 0xffffU : 0xffU) || nsectors == ~0U)
489 && (sign != '-' || page <= nsectors) )) {
490 sprintf(extraerror, "Option -l %s,ADDR[,FIRST[-LAST|+SIZE]] parameter out of range\n", erropt);
491 badarg = true;
492 }
493 else {
494 ata_log_request req;
495 req.gpl = gpl; req.logaddr = logaddr; req.page = page;
496 req.nsectors = (sign == '-' ? nsectors-page+1 : nsectors);
497 ataopts.log_requests.push_back(req);
498 }
499 } else {
500 badarg = true;
501 }
502 break;
503 case 'i':
504 ataopts.drive_info = scsiopts.drive_info = true;
505 break;
506 case 'a':
507 ataopts.drive_info = scsiopts.drive_info = true;
508 ataopts.smart_check_status = scsiopts.smart_check_status = true;
509 ataopts.smart_general_values = true;
510 ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true;
511 ataopts.smart_error_log = scsiopts.smart_error_log = true;
512 ataopts.smart_selftest_log = scsiopts.smart_selftest_log = true;
513 ataopts.smart_selective_selftest_log = true;
514 /* scsiopts.smart_background_log = true; */
515 break;
516 case 'x':
517 ataopts.drive_info = scsiopts.drive_info = true;
518 ataopts.smart_check_status = scsiopts.smart_check_status = true;
519 ataopts.smart_general_values = true;
520 ataopts.smart_vendor_attrib = scsiopts.smart_vendor_attrib = true;
521 ataopts.smart_ext_error_log = 8;
522 ataopts.retry_error_log = true;
523 ataopts.smart_ext_selftest_log = 25;
524 ataopts.retry_selftest_log = true;
525 scsiopts.smart_error_log = scsiopts.smart_selftest_log = true;
526 ataopts.smart_selective_selftest_log = true;
527 ataopts.smart_logdir = ataopts.gp_logdir = true;
528 ataopts.sct_temp_sts = ataopts.sct_temp_hist = true;
529 ataopts.sataphy = true;
530 scsiopts.smart_background_log = true;
531 scsiopts.sasphy = true;
532 break;
533 case 'v':
534 // parse vendor-specific definitions of attributes
535 if (!strcmp(optarg,"help")) {
536 con->dont_print = false;
537 printslogan();
538 pout("The valid arguments to -v are:\n\thelp\n%s\n",
539 create_vendor_attribute_arg_list().c_str());
540 EXIT(0);
541 }
542 if (!parse_attribute_def(optarg, ataopts.attribute_defs, PRIOR_USER))
543 badarg = true;
544 break;
545 case 'P':
546 if (!strcmp(optarg, "use")) {
547 ataopts.ignore_presets = false;
548 } else if (!strcmp(optarg, "ignore")) {
549 ataopts.ignore_presets = true;
550 } else if (!strcmp(optarg, "show")) {
551 ataopts.show_presets = true;
552 } else if (!strcmp(optarg, "showall")) {
553 if (!no_defaultdb && !read_default_drive_databases())
554 EXIT(FAILCMD);
555 if (optind < argc) { // -P showall MODEL [FIRMWARE]
556 int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL));
557 EXIT(cnt); // report #matches
558 }
559 if (showallpresets())
560 EXIT(FAILCMD); // report regexp syntax error
561 EXIT(0);
562 } else {
563 badarg = true;
564 }
565 break;
566 case 't':
567 if (!strcmp(optarg,"offline")) {
568 testcnt++;
569 ataopts.smart_selftest_type = OFFLINE_FULL_SCAN;
570 scsiopts.smart_default_selftest = true;
571 } else if (!strcmp(optarg,"short")) {
572 testcnt++;
573 ataopts.smart_selftest_type = SHORT_SELF_TEST;
574 scsiopts.smart_short_selftest = true;
575 } else if (!strcmp(optarg,"long")) {
576 testcnt++;
577 ataopts.smart_selftest_type = EXTEND_SELF_TEST;
578 scsiopts.smart_extend_selftest = true;
579 } else if (!strcmp(optarg,"conveyance")) {
580 testcnt++;
581 ataopts.smart_selftest_type = CONVEYANCE_SELF_TEST;
582 } else if (!strcmp(optarg,"afterselect,on")) {
583 // scan remainder of disk after doing selected segment
584 ataopts.smart_selective_args.scan_after_select = 2;
585 } else if (!strcmp(optarg,"afterselect,off")) {
586 // don't scan remainder of disk after doing selected segments
587 ataopts.smart_selective_args.scan_after_select = 1;
588 } else if (!strncmp(optarg,"pending,",strlen("pending,"))) {
589 // parse number of minutes that test should be pending
590 int i;
591 char *tailptr=NULL;
592 errno=0;
593 i=(int)strtol(optarg+strlen("pending,"), &tailptr, 10);
594 if (errno || *tailptr != '\0') {
595 sprintf(extraerror, "Option -t pending,N requires N to be a non-negative integer\n");
596 badarg = true;
597 } else if (i<0 || i>65535) {
598 sprintf(extraerror, "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i);
599 badarg = true;
600 } else {
601 ataopts.smart_selective_args.pending_time = i+1;
602 }
603 } else if (!strncmp(optarg,"select",strlen("select"))) {
604 testcnt++;
605 // parse range of LBAs to test
606 uint64_t start, stop; int mode;
607 if (split_selective_arg(optarg, &start, &stop, &mode)) {
608 sprintf(extraerror, "Option -t select,M-N must have non-negative integer M and N\n");
609 badarg = true;
610 } else {
611 if (ataopts.smart_selective_args.num_spans >= 5 || start > stop) {
612 if (start > stop) {
613 sprintf(extraerror, "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n",
614 start, stop, optarg);
615 } else {
616 sprintf(extraerror,"ERROR: No more than five selective self-test spans may be"
617 " defined\n");
618 }
619 badarg = true;
620 }
621 ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].start = start;
622 ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].end = stop;
623 ataopts.smart_selective_args.span[ataopts.smart_selective_args.num_spans].mode = mode;
624 ataopts.smart_selective_args.num_spans++;
625 ataopts.smart_selftest_type = SELECTIVE_SELF_TEST;
626 }
627 } else if (!strncmp(optarg, "scttempint,", sizeof("scstempint,")-1)) {
628 unsigned interval = 0; int n1 = -1, n2 = -1, len = strlen(optarg);
629 if (!( sscanf(optarg,"scttempint,%u%n,p%n", &interval, &n1, &n2) == 1
630 && 0 < interval && interval <= 0xffff && (n1 == len || n2 == len))) {
631 strcpy(extraerror, "Option -t scttempint,N[,p] must have positive integer N\n");
632 badarg = true;
633 }
634 ataopts.sct_temp_int = interval;
635 ataopts.sct_temp_int_pers = (n2 == len);
636 } else {
637 badarg = true;
638 }
639 break;
640 case 'C':
641 captive = true;
642 break;
643 case 'X':
644 testcnt++;
645 scsiopts.smart_selftest_abort = true;
646 ataopts.smart_selftest_type = ABORT_SELF_TEST;
647 break;
648 case 'n':
649 // skip disk check if in low-power mode
650 if (!strcmp(optarg, "never"))
651 ataopts.powermode = 1; // do not skip, but print mode
652 else if (!strcmp(optarg, "sleep"))
653 ataopts.powermode = 2;
654 else if (!strcmp(optarg, "standby"))
655 ataopts.powermode = 3;
656 else if (!strcmp(optarg, "idle"))
657 ataopts.powermode = 4;
658 else
659 badarg = true;
660 break;
661 case 'B':
662 {
663 const char * path = optarg;
664 if (*path == '+' && path[1])
665 path++;
666 else
667 no_defaultdb = true;
668 if (!read_drive_database(path))
669 EXIT(FAILCMD);
670 }
671 break;
672 case 'h':
673 con->dont_print = false;
674 printslogan();
675 Usage();
676 EXIT(0);
677 break;
678 case '?':
679 default:
680 con->dont_print = false;
681 printslogan();
682 // Point arg to the argument in which this option was found.
683 arg = argv[optind-1];
684 // Check whether the option is a long option that doesn't map to -h.
685 if (arg[1] == '-' && optchar != 'h') {
686 // Iff optopt holds a valid option then argument must be missing.
687 if (optopt && (strchr(shortopts, optopt) != NULL)) {
688 pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2);
689 printvalidarglistmessage(optopt);
690 } else
691 pout("=======> UNRECOGNIZED OPTION: %s\n",arg+2);
692 if (extraerror[0])
693 pout("=======> %s", extraerror);
694 UsageSummary();
695 EXIT(FAILCMD);
696 }
697 if (optopt) {
698 // Iff optopt holds a valid option then argument must be
699 // missing. Note (BA) this logic seems to fail using Solaris
700 // getopt!
701 if (strchr(shortopts, optopt) != NULL) {
702 pout("=======> ARGUMENT REQUIRED FOR OPTION: %c\n", optopt);
703 printvalidarglistmessage(optopt);
704 } else
705 pout("=======> UNRECOGNIZED OPTION: %c\n",optopt);
706 if (extraerror[0])
707 pout("=======> %s", extraerror);
708 UsageSummary();
709 EXIT(FAILCMD);
710 }
711 Usage();
712 EXIT(0);
713 } // closes switch statement to process command-line options
714
715 // Check to see if option had an unrecognized or incorrect argument.
716 if (badarg) {
717 printslogan();
718 // It would be nice to print the actual option name given by the user
719 // here, but we just print the short form. Please fix this if you know
720 // a clean way to do it.
721 pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg);
722 printvalidarglistmessage(optchar);
723 if (extraerror[0])
724 pout("=======> %s", extraerror);
725 UsageSummary();
726 EXIT(FAILCMD);
727 }
728 }
729 // At this point we have processed all command-line options. If the
730 // print output is switchable, then start with the print output
731 // turned off
732 if (con->printing_switchable)
733 con->dont_print = false;
734
735 // error message if user has asked for more than one test
736 if (testcnt > 1) {
737 con->dont_print = false;
738 printslogan();
739 pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n");
740 UsageSummary();
741 EXIT(FAILCMD);
742 }
743
744 // error message if user has set selective self-test options without
745 // asking for a selective self-test
746 if ( (ataopts.smart_selective_args.pending_time || ataopts.smart_selective_args.scan_after_select)
747 && !ataopts.smart_selective_args.num_spans) {
748 con->dont_print = false;
749 printslogan();
750 if (ataopts.smart_selective_args.pending_time)
751 pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n");
752 else
753 pout("\nERROR: smartctl -t afterselect,(on|off) must be used with -t select,N-M.\n");
754 UsageSummary();
755 EXIT(FAILCMD);
756 }
757
758 // If captive option was used, change test type if appropriate.
759 if (captive)
760 switch (ataopts.smart_selftest_type) {
761 case SHORT_SELF_TEST:
762 ataopts.smart_selftest_type = SHORT_CAPTIVE_SELF_TEST;
763 scsiopts.smart_short_selftest = false;
764 scsiopts.smart_short_cap_selftest = true;
765 break;
766 case EXTEND_SELF_TEST:
767 ataopts.smart_selftest_type = EXTEND_CAPTIVE_SELF_TEST;
768 scsiopts.smart_extend_selftest = false;
769 scsiopts.smart_extend_cap_selftest = true;
770 break;
771 case CONVEYANCE_SELF_TEST:
772 ataopts.smart_selftest_type = CONVEYANCE_CAPTIVE_SELF_TEST;
773 break;
774 case SELECTIVE_SELF_TEST:
775 ataopts.smart_selftest_type = SELECTIVE_CAPTIVE_SELF_TEST;
776 break;
777 }
778
779 // From here on, normal operations...
780 printslogan();
781
782 // Warn if the user has provided no device name
783 if (argc-optind<1){
784 pout("ERROR: smartctl requires a device name as the final command-line argument.\n\n");
785 UsageSummary();
786 EXIT(FAILCMD);
787 }
788
789 // Warn if the user has provided more than one device name
790 if (argc-optind>1){
791 int i;
792 pout("ERROR: smartctl takes ONE device name as the final command-line argument.\n");
793 pout("You have provided %d device names:\n",argc-optind);
794 for (i=0; i<argc-optind; i++)
795 pout("%s\n",argv[optind+i]);
796 UsageSummary();
797 EXIT(FAILCMD);
798 }
799
800 // Read or init drive database
801 if (!no_defaultdb && !read_default_drive_databases())
802 EXIT(FAILCMD);
803
804 return type;
805 }
806
807 // Printing function (controlled by global con->dont_print)
808 // [From GLIBC Manual: Since the prototype doesn't specify types for
809 // optional arguments, in a call to a variadic function the default
810 // argument promotions are performed on the optional argument
811 // values. This means the objects of type char or short int (whether
812 // signed or not) are promoted to either int or unsigned int, as
813 // appropriate.]
814 void pout(const char *fmt, ...){
815 va_list ap;
816
817 // initialize variable argument list
818 va_start(ap,fmt);
819 if (con->dont_print){
820 va_end(ap);
821 return;
822 }
823
824 // print out
825 vprintf(fmt,ap);
826 va_end(ap);
827 fflush(stdout);
828 return;
829 }
830
831 // This function is used by utility.cpp to report LOG_CRIT errors.
832 // The smartctl version prints to stdout instead of syslog().
833 void PrintOut(int priority, const char *fmt, ...) {
834 va_list ap;
835
836 // avoid warning message about unused variable from gcc -W: just
837 // change value of local copy.
838 priority=0;
839
840 va_start(ap,fmt);
841 vprintf(fmt,ap);
842 va_end(ap);
843 return;
844 }
845
846 // Used to warn users about invalid checksums. Called from atacmds.cpp.
847 // Action to be taken may be altered by the user.
848 void checksumwarning(const char * string)
849 {
850 // user has asked us to ignore checksum errors
851 if (checksum_err_mode == CHECKSUM_ERR_IGNORE)
852 return;
853
854 pout("Warning! %s error: invalid SMART checksum.\n", string);
855
856 // user has asked us to fail on checksum errors
857 if (checksum_err_mode == CHECKSUM_ERR_EXIT)
858 EXIT(FAILSMART);
859 }
860
861 // Return info string about device protocol
862 static const char * get_protocol_info(const smart_device * dev)
863 {
864 switch ((int)dev->is_ata() | ((int)dev->is_scsi() << 1)) {
865 case 0x1: return "ATA";
866 case 0x2: return "SCSI";
867 case 0x3: return "ATA+SCSI";
868 default: return "Unknown";
869 }
870 }
871
872 // Main program without exception handling
873 int main_worker(int argc, char **argv)
874 {
875 // Initialize interface
876 smart_interface::init();
877 if (!smi())
878 return 1;
879
880 // define control block for external functions
881 smartmonctrl control;
882 con=&control;
883
884 // Parse input arguments
885 ata_print_options ataopts;
886 scsi_print_options scsiopts;
887 const char * type = parse_options(argc, argv, ataopts, scsiopts);
888
889 // '-d test' -> Report result of autodetection
890 bool print_type_only = (type && !strcmp(type, "test"));
891 if (print_type_only)
892 type = 0;
893
894 const char * name = argv[argc-1];
895
896 smart_device_auto_ptr dev;
897 if (!strcmp(name,"-")) {
898 // Parse "smartctl -r ataioctl,2 ..." output from stdin
899 if (type || print_type_only) {
900 pout("Smartctl: -d option is not allowed in conjunction with device name \"-\".\n");
901 UsageSummary();
902 return FAILCMD;
903 }
904 dev = get_parsed_ata_device(smi(), name);
905 }
906 else
907 // get device of appropriate type
908 dev = smi()->get_smart_device(name, type);
909
910 if (!dev) {
911 pout("%s: %s\n", name, smi()->get_errmsg());
912 if (type)
913 printvalidarglistmessage('d');
914 else
915 pout("Smartctl: please specify device type with the -d option.\n");
916 UsageSummary();
917 return FAILCMD;
918 }
919
920 if (print_type_only)
921 // Report result of first autodetection
922 pout("%s: Device of type '%s' [%s] detected\n",
923 dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
924
925 // Open device
926 {
927 // Save old info
928 smart_device::device_info oldinfo = dev->get_info();
929
930 // Open with autodetect support, may return 'better' device
931 dev.replace( dev->autodetect_open() );
932
933 // Report if type has changed
934 if ((type || print_type_only) && oldinfo.dev_type != dev->get_dev_type())
935 pout("%s: Device open changed type from '%s' to '%s'\n",
936 dev->get_info_name(), oldinfo.dev_type.c_str(), dev->get_dev_type());
937 }
938 if (!dev->is_open()) {
939 pout("Smartctl open device: %s failed: %s\n", dev->get_info_name(), dev->get_errmsg());
940 return FAILDEV;
941 }
942
943 // now call appropriate ATA or SCSI routine
944 int retval = 0;
945 if (print_type_only)
946 pout("%s: Device of type '%s' [%s] opened\n",
947 dev->get_info_name(), dev->get_dev_type(), get_protocol_info(dev.get()));
948 else if (dev->is_ata())
949 retval = ataPrintMain(dev->to_ata(), ataopts);
950 else if (dev->is_scsi())
951 retval = scsiPrintMain(dev->to_scsi(), scsiopts);
952 else
953 // we should never fall into this branch!
954 pout("%s: Neither ATA nor SCSI device\n", dev->get_info_name());
955
956 dev->close();
957 return retval;
958 }
959
960
961 // Main program
962 int main(int argc, char **argv)
963 {
964 int status;
965 try {
966 // Do the real work ...
967 status = main_worker(argc, argv);
968 }
969 catch (int ex) {
970 // EXIT(status) arrives here
971 status = ex;
972 }
973 catch (const std::bad_alloc & /*ex*/) {
974 // Memory allocation failed (also thrown by std::operator new)
975 printf("Smartctl: Out of memory\n");
976 status = FAILCMD;
977 }
978 catch (const std::exception & ex) {
979 // Other fatal errors
980 printf("Smartctl: Exception: %s\n", ex.what());
981 status = FAILCMD;
982 }
983 return status;
984 }
985