]> git.proxmox.com Git - mirror_smartmontools-debian.git/blob - smartctl.cpp
Merge branch 'upstream'
[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-6 Bruce Allen <smartmontools-support@lists.sourceforge.net>
7 * Copyright (C) 2000 Michael Cornwell <cornwell@acm.org>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
12 * any later version.
13 *
14 * You should have received a copy of the GNU General Public License
15 * (for example COPYING); if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 <stdarg.h>
30
31 #include "config.h"
32 #ifdef HAVE_GETOPT_LONG
33 #include <getopt.h>
34 #endif
35 #if defined(__FreeBSD_version) && (__FreeBSD_version < 500000)
36 #include <unistd.h>
37 #endif
38
39 #include "int64.h"
40 #include "atacmds.h"
41 #include "ataprint.h"
42 #include "extern.h"
43 #include "knowndrives.h"
44 #include "scsicmds.h"
45 #include "scsiprint.h"
46 #include "smartctl.h"
47 #include "utility.h"
48
49 #ifdef NEED_SOLARIS_ATA_CODE
50 extern const char *os_solaris_ata_s_cvsid;
51 #endif
52 extern const char *atacmdnames_c_cvsid, *atacmds_c_cvsid, *ataprint_c_cvsid, *knowndrives_c_cvsid, *os_XXXX_c_cvsid, *scsicmds_c_cvsid, *scsiprint_c_cvsid, *utility_c_cvsid;
53 const char* smartctl_c_cvsid="$Id: smartctl.cpp,v 1.156 2006/10/09 11:45:12 guidog Exp $"
54 ATACMDS_H_CVSID ATAPRINT_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID SCSICMDS_H_CVSID SCSIPRINT_H_CVSID SMARTCTL_H_CVSID UTILITY_H_CVSID;
55
56 // This is a block containing all the "control variables". We declare
57 // this globally in this file, and externally in other files.
58 smartmonctrl *con=NULL;
59
60 // to hold onto exit code for atexit routine
61 extern int exitstatus;
62
63 // Track memory use
64 extern int64_t bytes;
65
66 void printslogan(){
67 #ifdef HAVE_GET_OS_VERSION_STR
68 const char * ver = get_os_version_str();
69 #else
70 const char * ver = SMARTMONTOOLS_BUILD_HOST;
71 #endif
72 pout("smartctl version %s [%s] Copyright (C) 2002-6 Bruce Allen\n", PACKAGE_VERSION, ver);
73 pout("Home page is " PACKAGE_HOMEPAGE "\n\n");
74 return;
75 }
76
77 void PrintOneCVS(const char *a_cvs_id){
78 char out[CVSMAXLEN];
79 printone(out,a_cvs_id);
80 pout("%s",out);
81 return;
82 }
83
84 void printcopy(){
85 char *configargs=strlen(SMARTMONTOOLS_CONFIGURE_ARGS)?SMARTMONTOOLS_CONFIGURE_ARGS:"[no arguments given]";
86
87 pout("smartctl comes with ABSOLUTELY NO WARRANTY. This\n");
88 pout("is free software, and you are welcome to redistribute it\n");
89 pout("under the terms of the GNU General Public License Version 2.\n");
90 pout("See http://www.gnu.org for further details.\n\n");
91 pout("CVS version IDs of files used to build this code are:\n");
92 PrintOneCVS(atacmdnames_c_cvsid);
93 PrintOneCVS(atacmds_c_cvsid);
94 PrintOneCVS(ataprint_c_cvsid);
95 PrintOneCVS(knowndrives_c_cvsid);
96 PrintOneCVS(os_XXXX_c_cvsid);
97 #ifdef NEED_SOLARIS_ATA_CODE
98 PrintOneCVS(os_solaris_ata_s_cvsid);
99 #endif
100 PrintOneCVS(scsicmds_c_cvsid);
101 PrintOneCVS(scsiprint_c_cvsid);
102 PrintOneCVS(smartctl_c_cvsid);
103 PrintOneCVS(utility_c_cvsid);
104 pout("\nsmartmontools release " PACKAGE_VERSION " dated " SMARTMONTOOLS_RELEASE_DATE " at " SMARTMONTOOLS_RELEASE_TIME "\n");
105 pout("smartmontools build host: " SMARTMONTOOLS_BUILD_HOST "\n");
106 pout("smartmontools build configured: " SMARTMONTOOLS_CONFIGURE_DATE "\n");
107 pout("smartctl compile dated " __DATE__ " at "__TIME__ "\n");
108 pout("smartmontools configure arguments: %s\n", configargs);
109 return;
110 }
111
112 void UsageSummary(){
113 pout("\nUse smartctl -h to get a usage summary\n\n");
114 return;
115 }
116
117 /* void prints help information for command syntax */
118 void Usage (void){
119 printf("Usage: smartctl [options] device\n\n");
120 printf("============================================ SHOW INFORMATION OPTIONS =====\n\n");
121 #ifdef HAVE_GETOPT_LONG
122 printf(
123 " -h, --help, --usage\n"
124 " Display this help and exit\n\n"
125 " -V, --version, --copyright, --license\n"
126 " Print license, copyright, and version information and exit\n\n"
127 " -i, --info \n"
128 " Show identity information for device\n\n"
129 " -a, --all \n"
130 " Show all SMART information for device\n\n"
131 );
132 #else
133 printf(
134 " -h Display this help and exit\n"
135 " -V Print license, copyright, and version information\n"
136 " -i Show identity information for device\n"
137 " -a Show all SMART information for device\n\n"
138 );
139 #endif
140 printf("================================== SMARTCTL RUN-TIME BEHAVIOR OPTIONS =====\n\n");
141 #ifdef HAVE_GETOPT_LONG
142 printf(
143 " -q TYPE, --quietmode=TYPE (ATA)\n"
144 " Set smartctl quiet mode to one of: errorsonly, silent\n\n"
145 " -d TYPE, --device=TYPE\n"
146 " Specify device type to one of: ata, scsi, marvell, sat, 3ware,N\n\n"
147 " -T TYPE, --tolerance=TYPE (ATA)\n"
148 " Tolerance: normal, conservative, permissive, verypermissive\n\n"
149 " -b TYPE, --badsum=TYPE (ATA)\n"
150 " Set action on bad checksum to one of: warn, exit, ignore\n\n"
151 " -r TYPE, --report=TYPE\n"
152 " Report transactions (see man page)\n\n"
153 " -n MODE, --nocheck=MODE (ATA)\n"
154 " No check if: never, sleep, standby, idle (see man page)\n\n"
155 );
156 #else
157 printf(
158 " -q TYPE Set smartctl quiet mode to one of: errorsonly, silent (ATA)\n"
159 " -d TYPE Specify device type to one of: ata, scsi, 3ware,N\n"
160 " -T TYPE Tolerance: normal, conservative,permissive,verypermissive (ATA\n"
161 " -b TYPE Set action on bad checksum to one of: warn, exit, ignore (ATA)\n"
162 " -r TYPE Report transactions (see man page)\n"
163 " -n MODE No check if: never, sleep, standby, idle (see man page) (ATA)\n\n"
164 );
165 #endif
166 printf("============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n");
167 #ifdef HAVE_GETOPT_LONG
168 printf(
169 " -s VALUE, --smart=VALUE\n"
170 " Enable/disable SMART on device (on/off)\n\n"
171 " -o VALUE, --offlineauto=VALUE (ATA)\n"
172 " Enable/disable automatic offline testing on device (on/off)\n\n"
173 " -S VALUE, --saveauto=VALUE (ATA)\n"
174 " Enable/disable Attribute autosave on device (on/off)\n\n"
175 );
176 #else
177 printf(
178 " -s VALUE Enable/disable SMART on device (on/off)\n"
179 " -o VALUE Enable/disable device automatic offline testing (on/off) (ATA)\n"
180 " -S VALUE Enable/disable device Attribute autosave (on/off) (ATA)\n\n"
181 );
182 #endif
183 printf("======================================= READ AND DISPLAY DATA OPTIONS =====\n\n");
184 #ifdef HAVE_GETOPT_LONG
185 printf(
186 " -H, --health\n"
187 " Show device SMART health status\n\n"
188 " -c, --capabilities (ATA)\n"
189 " Show device SMART capabilities\n\n"
190 " -A, --attributes \n"
191 " Show device SMART vendor-specific Attributes and values\n\n"
192 " -l TYPE, --log=TYPE\n"
193 " Show device log. TYPE: error, selftest, selective, directory,\n"
194 " background\n\n"
195 " -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n"
196 " Set display OPTION for vendor Attribute N (see man page)\n\n"
197 " -F TYPE, --firmwarebug=TYPE (ATA)\n"
198 " Use firmware bug workaround: none, samsung, samsung2\n\n"
199 " -P TYPE, --presets=TYPE (ATA)\n"
200 " Drive-specific presets: use, ignore, show, showall\n\n"
201 );
202 #else
203 printf(
204 " -H Show device SMART health status\n"
205 " -c Show device SMART capabilities (ATA)\n"
206 " -A Show device SMART vendor-specific Attributes and values (ATA)\n"
207 " -l TYPE Show device log. TYPE: error, selftest, selective, directory,\n"
208 " background\n"
209 " -v N,OPT Set display OPTion for vendor Attribute N (see man page) (ATA)\n"
210 " -F TYPE Use firmware bug workaround: none, samsung, samsung2 (ATA)\n"
211 " -P TYPE Drive-specific presets: use, ignore, show, showall (ATA)\n\n"
212 );
213 #endif
214 printf("============================================ DEVICE SELF-TEST OPTIONS =====\n\n");
215 #ifdef HAVE_GETOPT_LONG
216 printf(
217 " -t TEST, --test=TEST\n"
218 " Run test. TEST is: offline short long conveyance select,M-N pending,N afterselect,on afterselect,off\n\n"
219 " -C, --captive\n"
220 " Do test in captive mode (along with -t)\n\n"
221 " -X, --abort\n"
222 " Abort any non-captive test on device\n\n"
223 );
224 #else
225 printf(
226 " -t TEST Run test. TEST is: offline short long conveyance select,M-N pending,N afterselect,on afterselect,off\n"
227 " -C Do test in captive mode (along with -t)\n"
228 " -X Abort any non-captive test\n\n"
229 );
230 #endif
231 print_smartctl_examples();
232 return;
233 }
234
235 /* Returns a pointer to a static string containing a formatted list of the valid
236 arguments to the option opt or NULL on failure. Note 'v' case different */
237 const char *getvalidarglist(char opt) {
238 switch (opt) {
239 case 'q':
240 return "errorsonly, silent";
241 case 'd':
242 return "ata, scsi, marvell, sat, 3ware,N, hpt,L/M/N cciss,N";
243 case 'T':
244 return "normal, conservative, permissive, verypermissive";
245 case 'b':
246 return "warn, exit, ignore";
247 case 'r':
248 return "ioctl[,N], ataioctl[,N], scsiioctl[,N]";
249 case 's':
250 case 'o':
251 case 'S':
252 return "on, off";
253 case 'l':
254 return "error, selftest, selective, directory, background";
255 case 'P':
256 return "use, ignore, show, showall";
257 case 't':
258 return "offline, short, long, conveyance, select,M-N, pending,N, afterselect,on, afterselect,off";
259 case 'F':
260 return "none, samsung, samsung2";
261 case 'n':
262 return "never, sleep, standby, idle";
263 case 'v':
264 default:
265 return NULL;
266 }
267 }
268
269 /* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where
270 <LIST> is the list of valid arguments for option opt. */
271 void printvalidarglistmessage(char opt) {
272 char *s;
273
274 if (opt=='v')
275 s=create_vendor_attribute_arg_list();
276 else
277 s=(char *)getvalidarglist(opt);
278
279 if (!s) {
280 pout("Error whilst constructing argument list for option %c", opt);
281 return;
282 }
283
284 if (opt=='v'){
285 pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n", s);
286 free(s);
287 }
288 else {
289 // getvalidarglist() might produce a multiline or single line string. We
290 // need to figure out which to get the formatting right.
291 char separator = strchr(s, '\n') ? '\n' : ' ';
292 pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, (char *)s, separator);
293 }
294
295 return;
296 }
297
298 /* Takes command options and sets features to be run */
299 void ParseOpts (int argc, char** argv){
300 int optchar;
301 int badarg;
302 int captive;
303 unsigned char *charp;
304 extern char *optarg;
305 extern int optopt, optind, opterr;
306 char extraerror[256];
307 // Please update getvalidarglist() if you edit shortopts
308 const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iav:P:t:CXF:n:";
309 #ifdef HAVE_GETOPT_LONG
310 char *arg;
311 // Please update getvalidarglist() if you edit longopts
312 struct option longopts[] = {
313 { "help", no_argument, 0, 'h' },
314 { "usage", no_argument, 0, 'h' },
315 { "version", no_argument, 0, 'V' },
316 { "copyright", no_argument, 0, 'V' },
317 { "license", no_argument, 0, 'V' },
318 { "quietmode", required_argument, 0, 'q' },
319 { "device", required_argument, 0, 'd' },
320 { "tolerance", required_argument, 0, 'T' },
321 { "badsum", required_argument, 0, 'b' },
322 { "report", required_argument, 0, 'r' },
323 { "smart", required_argument, 0, 's' },
324 { "offlineauto", required_argument, 0, 'o' },
325 { "saveauto", required_argument, 0, 'S' },
326 { "health", no_argument, 0, 'H' },
327 { "capabilities", no_argument, 0, 'c' },
328 { "attributes", no_argument, 0, 'A' },
329 { "log", required_argument, 0, 'l' },
330 { "info", no_argument, 0, 'i' },
331 { "all", no_argument, 0, 'a' },
332 { "vendorattribute", required_argument, 0, 'v' },
333 { "presets", required_argument, 0, 'P' },
334 { "test", required_argument, 0, 't' },
335 { "captive", no_argument, 0, 'C' },
336 { "abort", no_argument, 0, 'X' },
337 { "firmwarebug", required_argument, 0, 'F' },
338 { "nocheck", required_argument, 0, 'n' },
339 { 0, 0, 0, 0 }
340 };
341 #endif
342
343 memset(extraerror, 0, sizeof(extraerror));
344 memset(con,0,sizeof(*con));
345 con->testcase=-1;
346 opterr=optopt=0;
347 badarg = captive = FALSE;
348
349 // This miserable construction is needed to get emacs to do proper indenting. Sorry!
350 while (-1 != (optchar =
351 #ifdef HAVE_GETOPT_LONG
352 getopt_long(argc, argv, shortopts, longopts, NULL)
353 #else
354 getopt(argc, argv, shortopts)
355 #endif
356 )){
357 switch (optchar){
358 case 'V':
359 con->dont_print=FALSE;
360 printslogan();
361 printcopy();
362 exit(0);
363 break;
364 case 'q':
365 if (!strcmp(optarg,"errorsonly")) {
366 con->printing_switchable = TRUE;
367 con->dont_print = FALSE;
368 } else if (!strcmp(optarg,"silent")) {
369 con->printing_switchable = FALSE;
370 con->dont_print = TRUE;
371 } else {
372 badarg = TRUE;
373 }
374 break;
375 case 'd':
376 con->controller_explicit = 1;
377 if (!strcmp(optarg,"ata")) {
378 con->controller_type = CONTROLLER_ATA;
379 con->controller_port = 0;
380 } else if (!strcmp(optarg,"scsi")) {
381 con->controller_type = CONTROLLER_SCSI;
382 con->controller_port = 0;
383 } else if (!strcmp(optarg,"marvell")) {
384 con->controller_type = CONTROLLER_MARVELL_SATA;
385 con->controller_port = 0;
386 } else if (!strncmp(optarg, "sat", 3)) {
387 con->controller_type = CONTROLLER_SAT;
388 con->controller_port = 0;
389 con->satpassthrulen = 0;
390 if (strlen(optarg) > 3) {
391 int k;
392 char * cp;
393
394 cp = strchr(optarg, ',');
395 if (cp && (1 == sscanf(cp + 1, "%d", &k)) &&
396 ((0 == k) || (12 == k) || (16 == k)))
397 con->satpassthrulen = k;
398 else {
399 sprintf(extraerror, "Option '-d sat,<n>' requires <n> to be "
400 "0, 12 or 16\n");
401 badarg = TRUE;
402 }
403 }
404 } else if (!strncmp(optarg, "hpt", 3)){
405 unsigned char i, slash = 0;
406 con->hpt_data[0] = 0;
407 con->hpt_data[1] = 0;
408 con->hpt_data[2] = 0;
409 con->controller_type = CONTROLLER_HPT;
410 for (i=4; i < strlen(optarg); i++) {
411 if(optarg[i] == '/') {
412 slash++;
413 if(slash == 3) {
414 sprintf(extraerror, "Option '-d hpt,L/M/N' supports 2-3 items\n");
415 badarg = TRUE;
416 break;
417 }
418 }
419 else if ((optarg[i])>='0' && (optarg[i])<='9') {
420 if (con->hpt_data[slash]>1) { /* hpt_data[x] max 19 */
421 badarg = TRUE;
422 break;
423 }
424 con->hpt_data[slash] = con->hpt_data[slash]*10 + optarg[i] - '0';
425 }
426 else {
427 badarg = TRUE;
428 break;
429 }
430 }
431 if (slash == 0) {
432 sprintf(extraerror, "Option '-d hpt,L/M/N' requires 2-3 items\n");
433 badarg = TRUE;
434 } else if (badarg != TRUE) {
435 if (con->hpt_data[0]==0 || con->hpt_data[0]>8){
436 sprintf(extraerror, "Option '-d hpt,L/M/N' no/invalid controller id L supplied\n");
437 badarg = TRUE;
438 }
439 if (con->hpt_data[1]==0 || con->hpt_data[1]>8){
440 sprintf(extraerror, "Option '-d hpt,L/M/N' no/invalid channel number M supplied\n");
441 badarg = TRUE;
442 }
443 if (slash==2) {
444 if ( con->hpt_data[2]==0 || con->hpt_data[2]>15) {
445 sprintf(extraerror, "Option '-d hpt,L/M/N' no/invalid pmport number N supplied\n");
446 badarg = TRUE;
447 }
448 } else {
449 con->hpt_data[2]=1;
450 }
451 }
452 } else {
453 // look for RAID-type device
454 int i;
455 char *s;
456
457 // make a copy of the string to mess with
458 if (!(s = strdup(optarg))) {
459 con->dont_print = FALSE;
460 pout("No memory for argument of -d. Exiting...\n");
461 exit(FAILCMD);
462 } else if (!strncmp(s,"3ware,",6)) {
463 if (split_report_arg2(s, &i)) {
464 sprintf(extraerror, "Option -d 3ware,N requires N to be a non-negative integer\n");
465 badarg = TRUE;
466 } else if (i<0 || i>15) {
467 sprintf(extraerror, "Option -d 3ware,N (N=%d) must have 0 <= N <= 15\n", i);
468 badarg = TRUE;
469 } else {
470 // NOTE: controller_port == disk number + 1
471 con->controller_type = CONTROLLER_3WARE;
472 con->controller_port = i+1;
473 }
474 free(s);
475 } else if (!strncmp(s,"cciss,",6)) {
476 if (split_report_arg2(s, &i)) {
477 sprintf(extraerror, "Option -d cciss,N requires N to be a non-negative integer\n");
478 badarg = TRUE;
479 } else if (i<0 || i>15) {
480 sprintf(extraerror, "Option -d cciss,N (N=%d) must have 0 <= N <= 15\n", i);
481 badarg = TRUE;
482 } else {
483 // NOTE: controller_port == drive number
484 con->controller_type = CONTROLLER_CCISS;
485 con->controller_port = i+1;
486 }
487 free(s);
488 } else
489 badarg=TRUE;
490 }
491 break;
492 case 'T':
493 if (!strcmp(optarg,"normal")) {
494 con->conservative = FALSE;
495 con->permissive = 0;
496 } else if (!strcmp(optarg,"conservative")) {
497 con->conservative = TRUE;
498 } else if (!strcmp(optarg,"permissive")) {
499 if (con->permissive<0xff)
500 con->permissive++;
501 } else if (!strcmp(optarg,"verypermissive")) {
502 con->permissive=0xff;
503 } else {
504 badarg = TRUE;
505 }
506 break;
507 case 'b':
508 if (!strcmp(optarg,"warn")) {
509 con->checksumfail = FALSE;
510 con->checksumignore = FALSE;
511 } else if (!strcmp(optarg,"exit")) {
512 con->checksumfail = TRUE;
513 con->checksumignore = FALSE;
514 } else if (!strcmp(optarg,"ignore")) {
515 con->checksumignore = TRUE;
516 con->checksumfail = FALSE;
517 } else {
518 badarg = TRUE;
519 }
520 break;
521 case 'r':
522 {
523 int i;
524 char *s;
525
526 // split_report_arg() may modify its first argument string, so use a
527 // copy of optarg in case we want optarg for an error message.
528 if (!(s = strdup(optarg))) {
529 con->dont_print = FALSE;
530 pout("Can't allocate memory to copy argument to -r option"
531 " - exiting\n");
532 EXIT(FAILCMD);
533 }
534 if (split_report_arg(s, &i)) {
535 badarg = TRUE;
536 } else if (!strcmp(s,"ioctl")) {
537 con->reportataioctl = con->reportscsiioctl = i;
538 } else if (!strcmp(s,"ataioctl")) {
539 con->reportataioctl = i;
540 } else if (!strcmp(s,"scsiioctl")) {
541 con->reportscsiioctl = i;
542 } else {
543 badarg = TRUE;
544 }
545 free(s);
546 }
547 break;
548 case 's':
549 if (!strcmp(optarg,"on")) {
550 con->smartenable = TRUE;
551 con->smartdisable = FALSE;
552 } else if (!strcmp(optarg,"off")) {
553 con->smartdisable = TRUE;
554 con->smartenable = FALSE;
555 } else {
556 badarg = TRUE;
557 }
558 break;
559 case 'o':
560 if (!strcmp(optarg,"on")) {
561 con->smartautoofflineenable = TRUE;
562 con->smartautoofflinedisable = FALSE;
563 } else if (!strcmp(optarg,"off")) {
564 con->smartautoofflinedisable = TRUE;
565 con->smartautoofflineenable = FALSE;
566 } else {
567 badarg = TRUE;
568 }
569 break;
570 case 'S':
571 if (!strcmp(optarg,"on")) {
572 con->smartautosaveenable = TRUE;
573 con->smartautosavedisable = FALSE;
574 } else if (!strcmp(optarg,"off")) {
575 con->smartautosavedisable = TRUE;
576 con->smartautosaveenable = FALSE;
577 } else {
578 badarg = TRUE;
579 }
580 break;
581 case 'H':
582 con->checksmart = TRUE;
583 break;
584 case 'F':
585 if (!strcmp(optarg,"none")) {
586 con->fixfirmwarebug = FIX_NONE;
587 } else if (!strcmp(optarg,"samsung")) {
588 con->fixfirmwarebug = FIX_SAMSUNG;
589 } else if (!strcmp(optarg,"samsung2")) {
590 con->fixfirmwarebug = FIX_SAMSUNG2;
591 } else {
592 badarg = TRUE;
593 }
594 break;
595 case 'c':
596 con->generalsmartvalues = TRUE;
597 break;
598 case 'A':
599 con->smartvendorattrib = TRUE;
600 break;
601 case 'l':
602 if (!strcmp(optarg,"error")) {
603 con->smarterrorlog = TRUE;
604 } else if (!strcmp(optarg,"selftest")) {
605 con->smartselftestlog = TRUE;
606 } else if (!strcmp(optarg, "selective")) {
607 con->selectivetestlog = TRUE;
608 } else if (!strcmp(optarg,"directory")) {
609 con->smartlogdirectory = TRUE;
610 } else if (!strcmp(optarg,"background")) {
611 con->smartbackgroundlog = TRUE;
612 } else {
613 badarg = TRUE;
614 }
615 break;
616 case 'i':
617 con->driveinfo = TRUE;
618 break;
619 case 'a':
620 con->driveinfo = TRUE;
621 con->checksmart = TRUE;
622 con->generalsmartvalues = TRUE;
623 con->smartvendorattrib = TRUE;
624 con->smarterrorlog = TRUE;
625 con->smartselftestlog = TRUE;
626 con->selectivetestlog = TRUE;
627 /* con->smartbackgroundlog = TRUE; */
628 break;
629 case 'v':
630 // parse vendor-specific definitions of attributes
631 if (!strcmp(optarg,"help")) {
632 char *s;
633 con->dont_print=FALSE;
634 printslogan();
635 if (!(s = create_vendor_attribute_arg_list())) {
636 pout("Insufficient memory to construct argument list\n");
637 EXIT(FAILCMD);
638 }
639 pout("The valid arguments to -v are:\n\thelp\n%s\n", s);
640 free(s);
641 EXIT(0);
642 }
643 charp=con->attributedefs;
644 if (!charp){
645 pout("Fatal internal error in ParseOpts()\n");
646 EXIT(FAILCMD);
647 }
648 if (parse_attribute_def(optarg, &charp))
649 badarg = TRUE;
650 break;
651 case 'P':
652 if (!strcmp(optarg, "use")) {
653 con->ignorepresets = FALSE;
654 } else if (!strcmp(optarg, "ignore")) {
655 con->ignorepresets = TRUE;
656 } else if (!strcmp(optarg, "show")) {
657 con->showpresets = TRUE;
658 } else if (!strcmp(optarg, "showall")) {
659 if (optind < argc) { // -P showall MODEL [FIRMWARE]
660 int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL));
661 EXIT(cnt); // report #matches
662 }
663 if (showallpresets())
664 EXIT(FAILCMD); // report regexp syntax error
665 EXIT(0);
666 } else {
667 badarg = TRUE;
668 }
669 break;
670 case 't':
671 if (!strcmp(optarg,"offline")) {
672 con->smartexeoffimmediate = TRUE;
673 con->testcase = OFFLINE_FULL_SCAN;
674 } else if (!strcmp(optarg,"short")) {
675 con->smartshortselftest = TRUE;
676 con->testcase = SHORT_SELF_TEST;
677 } else if (!strcmp(optarg,"long")) {
678 con->smartextendselftest = TRUE;
679 con->testcase = EXTEND_SELF_TEST;
680 } else if (!strcmp(optarg,"conveyance")) {
681 con->smartconveyanceselftest = TRUE;
682 con->testcase = CONVEYANCE_SELF_TEST;
683 } else if (!strcmp(optarg,"afterselect,on")) {
684 // scan remainder of disk after doing selected segments
685 con->scanafterselect=2;
686 } else if (!strcmp(optarg,"afterselect,off")) {
687 // don't scan remainder of disk after doing selected segments
688 con->scanafterselect=1;
689 } else if (!strncmp(optarg,"pending,",strlen("pending,"))) {
690 // parse number of minutes that test should be pending
691 int i;
692 char *tailptr=NULL;
693 errno=0;
694 i=(int)strtol(optarg+strlen("pending,"), &tailptr, 10);
695 if (errno || *tailptr != '\0') {
696 sprintf(extraerror, "Option -t pending,N requires N to be a non-negative integer\n");
697 badarg = TRUE;
698 } else if (i<0 || i>65535) {
699 sprintf(extraerror, "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i);
700 badarg = TRUE;
701 } else {
702 con->pendingtime=i+1;
703 }
704 } else if (!strncmp(optarg,"select",strlen("select"))) {
705 // parse range of LBAs to test
706 uint64_t start, stop;
707
708 if (split_selective_arg(optarg, &start, &stop)) {
709 sprintf(extraerror, "Option -t select,M-N must have non-negative integer M and N\n");
710 badarg = TRUE;
711 } else {
712 if (con->smartselectivenumspans >= 5 || start > stop) {
713 if (start > stop) {
714 sprintf(extraerror, "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n",
715 start, stop, optarg);
716 } else {
717 sprintf(extraerror,"ERROR: No more than five selective self-test spans may be"
718 " defined\n");
719 }
720 badarg = TRUE;
721 }
722 con->smartselectivespan[con->smartselectivenumspans][0] = start;
723 con->smartselectivespan[con->smartselectivenumspans][1] = stop;
724 con->smartselectivenumspans++;
725 con->testcase = SELECTIVE_SELF_TEST;
726 }
727 } else {
728 badarg = TRUE;
729 }
730 break;
731 case 'C':
732 captive = TRUE;
733 break;
734 case 'X':
735 con->smartselftestabort = TRUE;
736 con->testcase = ABORT_SELF_TEST;
737 break;
738 case 'n':
739 // skip disk check if in low-power mode
740 if (!strcmp(optarg, "never"))
741 con->powermode = 1; // do not skip, but print mode
742 else if (!strcmp(optarg, "sleep"))
743 con->powermode = 2;
744 else if (!strcmp(optarg, "standby"))
745 con->powermode = 3;
746 else if (!strcmp(optarg, "idle"))
747 con->powermode = 4;
748 else
749 badarg = TRUE;
750 break;
751 case 'h':
752 con->dont_print=FALSE;
753 printslogan();
754 Usage();
755 EXIT(0);
756 break;
757 case '?':
758 default:
759 con->dont_print=FALSE;
760 printslogan();
761 #ifdef HAVE_GETOPT_LONG
762 // Point arg to the argument in which this option was found.
763 arg = argv[optind-1];
764 // Check whether the option is a long option that doesn't map to -h.
765 if (arg[1] == '-' && optchar != 'h') {
766 // Iff optopt holds a valid option then argument must be missing.
767 if (optopt && (strchr(shortopts, optopt) != NULL)) {
768 pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2);
769 printvalidarglistmessage(optopt);
770 } else
771 pout("=======> UNRECOGNIZED OPTION: %s\n",arg+2);
772 if (extraerror[0])
773 pout("=======> %s", extraerror);
774 UsageSummary();
775 EXIT(FAILCMD);
776 }
777 #endif
778 if (optopt) {
779 // Iff optopt holds a valid option then argument must be
780 // missing. Note (BA) this logic seems to fail using Solaris
781 // getopt!
782 if (strchr(shortopts, optopt) != NULL) {
783 pout("=======> ARGUMENT REQUIRED FOR OPTION: %c\n", optopt);
784 printvalidarglistmessage(optopt);
785 } else
786 pout("=======> UNRECOGNIZED OPTION: %c\n",optopt);
787 if (extraerror[0])
788 pout("=======> %s", extraerror);
789 UsageSummary();
790 EXIT(FAILCMD);
791 }
792 Usage();
793 EXIT(0);
794 } // closes switch statement to process command-line options
795
796 // Check to see if option had an unrecognized or incorrect argument.
797 if (badarg) {
798 printslogan();
799 // It would be nice to print the actual option name given by the user
800 // here, but we just print the short form. Please fix this if you know
801 // a clean way to do it.
802 pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg);
803 printvalidarglistmessage(optchar);
804 if (extraerror[0])
805 pout("=======> %s", extraerror);
806 UsageSummary();
807 EXIT(FAILCMD);
808 }
809 }
810 // At this point we have processed all command-line options. If the
811 // print output is switchable, then start with the print output
812 // turned off
813 if (con->printing_switchable)
814 con->dont_print=TRUE;
815
816 // error message if user has asked for more than one test
817 if (1<(con->smartexeoffimmediate+con->smartshortselftest+con->smartextendselftest+
818 con->smartshortcapselftest+con->smartextendcapselftest+con->smartselftestabort + (con->smartselectivenumspans>0?1:0))){
819 con->dont_print=FALSE;
820 printslogan();
821 pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n");
822 UsageSummary();
823 EXIT(FAILCMD);
824 }
825
826 // error message if user has set selective self-test options without
827 // asking for a selective self-test
828 if ((con->pendingtime || con->scanafterselect) && !con->smartselectivenumspans){
829 con->dont_print=FALSE;
830 printslogan();
831 if (con->pendingtime)
832 pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n");
833 else
834 pout("\nERROR: smartctl -t afterselect,(on|off) must be used with -t select,N-M.\n");
835 UsageSummary();
836 EXIT(FAILCMD);
837 }
838
839 // If captive option was used, change test type if appropriate.
840 if (captive && con->smartshortselftest) {
841 con->smartshortselftest = FALSE;
842 con->smartshortcapselftest = TRUE;
843 con->testcase = SHORT_CAPTIVE_SELF_TEST;
844 } else if (captive && con->smartextendselftest) {
845 con->smartextendselftest = FALSE;
846 con->smartextendcapselftest = TRUE;
847 con->testcase = EXTEND_CAPTIVE_SELF_TEST;
848 }
849 else if (captive && con->smartconveyanceselftest) {
850 con->smartconveyanceselftest = FALSE;
851 con->smartconveyancecapselftest = TRUE;
852 con->testcase = CONVEYANCE_CAPTIVE_SELF_TEST;
853 }
854 else if (captive && con->smartselectiveselftest) {
855 con->smartselectiveselftest = FALSE;
856 con->smartselectivecapselftest = TRUE;
857 con->testcase = SELECTIVE_CAPTIVE_SELF_TEST;
858 }
859
860 // From here on, normal operations...
861 printslogan();
862
863 // Warn if the user has provided no device name
864 if (argc-optind<1){
865 pout("ERROR: smartctl requires a device name as the final command-line argument.\n\n");
866 UsageSummary();
867 EXIT(FAILCMD);
868 }
869
870 // Warn if the user has provided more than one device name
871 if (argc-optind>1){
872 int i;
873 pout("ERROR: smartctl takes ONE device name as the final command-line argument.\n");
874 pout("You have provided %d device names:\n",argc-optind);
875 for (i=0; i<argc-optind; i++)
876 pout("%s\n",argv[optind+i]);
877 UsageSummary();
878 EXIT(FAILCMD);
879 }
880 }
881
882 // Printing function (controlled by global con->dont_print)
883 // [From GLIBC Manual: Since the prototype doesn't specify types for
884 // optional arguments, in a call to a variadic function the default
885 // argument promotions are performed on the optional argument
886 // values. This means the objects of type char or short int (whether
887 // signed or not) are promoted to either int or unsigned int, as
888 // appropriate.]
889 void pout(const char *fmt, ...){
890 va_list ap;
891
892 // initialize variable argument list
893 va_start(ap,fmt);
894 if (con->dont_print){
895 va_end(ap);
896 return;
897 }
898
899 // print out
900 vprintf(fmt,ap);
901 va_end(ap);
902 fflush(stdout);
903 return;
904 }
905
906 // This function is used by utility.cpp to report LOG_CRIT errors.
907 // The smartctl version prints to stdout instead of syslog().
908 void PrintOut(int priority, const char *fmt, ...) {
909 va_list ap;
910
911 // avoid warning message about unused variable from gcc -W: just
912 // change value of local copy.
913 priority=0;
914
915 va_start(ap,fmt);
916 vprintf(fmt,ap);
917 va_end(ap);
918 return;
919 }
920
921
922 /* Main Program */
923 int main (int argc, char **argv){
924 int fd,retval=0;
925 char *device;
926 smartmonctrl control;
927 char *mode=NULL;
928
929 // define control block for external functions
930 con=&control;
931
932 // Part input arguments
933 ParseOpts(argc,argv);
934
935 device = argv[argc-1];
936
937 // If use has specified 3ware controller, determine which interface
938 if (con->controller_type == CONTROLLER_3WARE) {
939 con->controller_type=guess_device_type(device);
940 if (con->controller_type!=CONTROLLER_3WARE_9000_CHAR && con->controller_type!=CONTROLLER_3WARE_678K_CHAR)
941 con->controller_type = CONTROLLER_3WARE_678K;
942 }
943
944 if (con->controller_type == CONTROLLER_UNKNOWN)
945 con->controller_type=guess_device_type(device);
946
947 if (con->controller_type == CONTROLLER_UNKNOWN) {
948 pout("Smartctl: please specify device type with the -d option.\n");
949 UsageSummary();
950 return FAILCMD;
951 }
952
953 // set up mode for open() call. SCSI case is:
954 switch (con->controller_type) {
955 case CONTROLLER_SCSI:
956 case CONTROLLER_SAT:
957 mode="SCSI";
958 break;
959 case CONTROLLER_3WARE_9000_CHAR:
960 mode="ATA_3WARE_9000";
961 break;
962 case CONTROLLER_3WARE_678K_CHAR:
963 mode="ATA_3WARE_678K";
964 break;
965 case CONTROLLER_CCISS:
966 mode="CCISS";
967 break;
968 default:
969 mode="ATA";
970 break;
971 }
972
973 // open device - SCSI devices are opened (O_RDWR | O_NONBLOCK) so the
974 // scsi generic device can be used (needs write permission for MODE
975 // SELECT command) plus O_NONBLOCK to stop open hanging if media not
976 // present (e.g. with st). Opening is retried O_RDONLY if read-only
977 // media prevents opening O_RDWR (it cannot happen for scsi generic
978 // devices, but it can for the others).
979 fd = deviceopen(device, mode);
980 if (fd<0) {
981 char errmsg[256];
982 snprintf(errmsg,256,"Smartctl open device: %s failed",argv[argc-1]);
983 errmsg[255]='\0';
984 syserror(errmsg);
985 return FAILDEV;
986 }
987
988 // now call appropriate ATA or SCSI routine
989 switch (con->controller_type) {
990 case CONTROLLER_UNKNOWN:
991 // we should never fall into this branch!
992 pout("Smartctl: please specify device type with the -d option.\n");
993 UsageSummary();
994 retval = FAILCMD;
995 break;
996 case CONTROLLER_SCSI:
997 retval = scsiPrintMain(fd);
998 if ((0 == retval) && (CONTROLLER_SAT == con->controller_type))
999 retval = ataPrintMain(fd);
1000 break;
1001 case CONTROLLER_CCISS:
1002 // route the cciss command through scsiPrintMain.
1003 // cciss pass-throughs will separeate from the SCSI data-path.
1004 retval = scsiPrintMain(fd);
1005 break;
1006 default:
1007 retval = ataPrintMain(fd);
1008 break;
1009 }
1010
1011 return retval;
1012 }