]> 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.155 2006/09/20 16:17:31 shattered 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";
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 badarg = TRUE;
464 } else if (split_report_arg2(s, &i)) {
465 sprintf(extraerror, "Option -d 3ware,N requires N to be a non-negative integer\n");
466 badarg = TRUE;
467 } else if (i<0 || i>15) {
468 sprintf(extraerror, "Option -d 3ware,N (N=%d) must have 0 <= N <= 15\n", i);
469 badarg = TRUE;
470 } else {
471 // NOTE: controller_port == disk number + 1
472 con->controller_type = CONTROLLER_3WARE;
473 con->controller_port = i+1;
474 }
475 free(s);
476 }
477 break;
478 case 'T':
479 if (!strcmp(optarg,"normal")) {
480 con->conservative = FALSE;
481 con->permissive = 0;
482 } else if (!strcmp(optarg,"conservative")) {
483 con->conservative = TRUE;
484 } else if (!strcmp(optarg,"permissive")) {
485 if (con->permissive<0xff)
486 con->permissive++;
487 } else if (!strcmp(optarg,"verypermissive")) {
488 con->permissive=0xff;
489 } else {
490 badarg = TRUE;
491 }
492 break;
493 case 'b':
494 if (!strcmp(optarg,"warn")) {
495 con->checksumfail = FALSE;
496 con->checksumignore = FALSE;
497 } else if (!strcmp(optarg,"exit")) {
498 con->checksumfail = TRUE;
499 con->checksumignore = FALSE;
500 } else if (!strcmp(optarg,"ignore")) {
501 con->checksumignore = TRUE;
502 con->checksumfail = FALSE;
503 } else {
504 badarg = TRUE;
505 }
506 break;
507 case 'r':
508 {
509 int i;
510 char *s;
511
512 // split_report_arg() may modify its first argument string, so use a
513 // copy of optarg in case we want optarg for an error message.
514 if (!(s = strdup(optarg))) {
515 con->dont_print = FALSE;
516 pout("Can't allocate memory to copy argument to -r option"
517 " - exiting\n");
518 EXIT(FAILCMD);
519 }
520 if (split_report_arg(s, &i)) {
521 badarg = TRUE;
522 } else if (!strcmp(s,"ioctl")) {
523 con->reportataioctl = con->reportscsiioctl = i;
524 } else if (!strcmp(s,"ataioctl")) {
525 con->reportataioctl = i;
526 } else if (!strcmp(s,"scsiioctl")) {
527 con->reportscsiioctl = i;
528 } else {
529 badarg = TRUE;
530 }
531 free(s);
532 }
533 break;
534 case 's':
535 if (!strcmp(optarg,"on")) {
536 con->smartenable = TRUE;
537 con->smartdisable = FALSE;
538 } else if (!strcmp(optarg,"off")) {
539 con->smartdisable = TRUE;
540 con->smartenable = FALSE;
541 } else {
542 badarg = TRUE;
543 }
544 break;
545 case 'o':
546 if (!strcmp(optarg,"on")) {
547 con->smartautoofflineenable = TRUE;
548 con->smartautoofflinedisable = FALSE;
549 } else if (!strcmp(optarg,"off")) {
550 con->smartautoofflinedisable = TRUE;
551 con->smartautoofflineenable = FALSE;
552 } else {
553 badarg = TRUE;
554 }
555 break;
556 case 'S':
557 if (!strcmp(optarg,"on")) {
558 con->smartautosaveenable = TRUE;
559 con->smartautosavedisable = FALSE;
560 } else if (!strcmp(optarg,"off")) {
561 con->smartautosavedisable = TRUE;
562 con->smartautosaveenable = FALSE;
563 } else {
564 badarg = TRUE;
565 }
566 break;
567 case 'H':
568 con->checksmart = TRUE;
569 break;
570 case 'F':
571 if (!strcmp(optarg,"none")) {
572 con->fixfirmwarebug = FIX_NONE;
573 } else if (!strcmp(optarg,"samsung")) {
574 con->fixfirmwarebug = FIX_SAMSUNG;
575 } else if (!strcmp(optarg,"samsung2")) {
576 con->fixfirmwarebug = FIX_SAMSUNG2;
577 } else {
578 badarg = TRUE;
579 }
580 break;
581 case 'c':
582 con->generalsmartvalues = TRUE;
583 break;
584 case 'A':
585 con->smartvendorattrib = TRUE;
586 break;
587 case 'l':
588 if (!strcmp(optarg,"error")) {
589 con->smarterrorlog = TRUE;
590 } else if (!strcmp(optarg,"selftest")) {
591 con->smartselftestlog = TRUE;
592 } else if (!strcmp(optarg, "selective")) {
593 con->selectivetestlog = TRUE;
594 } else if (!strcmp(optarg,"directory")) {
595 con->smartlogdirectory = TRUE;
596 } else if (!strcmp(optarg,"background")) {
597 con->smartbackgroundlog = TRUE;
598 } else {
599 badarg = TRUE;
600 }
601 break;
602 case 'i':
603 con->driveinfo = TRUE;
604 break;
605 case 'a':
606 con->driveinfo = TRUE;
607 con->checksmart = TRUE;
608 con->generalsmartvalues = TRUE;
609 con->smartvendorattrib = TRUE;
610 con->smarterrorlog = TRUE;
611 con->smartselftestlog = TRUE;
612 con->selectivetestlog = TRUE;
613 /* con->smartbackgroundlog = TRUE; */
614 break;
615 case 'v':
616 // parse vendor-specific definitions of attributes
617 if (!strcmp(optarg,"help")) {
618 char *s;
619 con->dont_print=FALSE;
620 printslogan();
621 if (!(s = create_vendor_attribute_arg_list())) {
622 pout("Insufficient memory to construct argument list\n");
623 EXIT(FAILCMD);
624 }
625 pout("The valid arguments to -v are:\n\thelp\n%s\n", s);
626 free(s);
627 EXIT(0);
628 }
629 charp=con->attributedefs;
630 if (!charp){
631 pout("Fatal internal error in ParseOpts()\n");
632 EXIT(FAILCMD);
633 }
634 if (parse_attribute_def(optarg, &charp))
635 badarg = TRUE;
636 break;
637 case 'P':
638 if (!strcmp(optarg, "use")) {
639 con->ignorepresets = FALSE;
640 } else if (!strcmp(optarg, "ignore")) {
641 con->ignorepresets = TRUE;
642 } else if (!strcmp(optarg, "show")) {
643 con->showpresets = TRUE;
644 } else if (!strcmp(optarg, "showall")) {
645 if (optind < argc) { // -P showall MODEL [FIRMWARE]
646 int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL));
647 EXIT(cnt); // report #matches
648 }
649 if (showallpresets())
650 EXIT(FAILCMD); // report regexp syntax error
651 EXIT(0);
652 } else {
653 badarg = TRUE;
654 }
655 break;
656 case 't':
657 if (!strcmp(optarg,"offline")) {
658 con->smartexeoffimmediate = TRUE;
659 con->testcase = OFFLINE_FULL_SCAN;
660 } else if (!strcmp(optarg,"short")) {
661 con->smartshortselftest = TRUE;
662 con->testcase = SHORT_SELF_TEST;
663 } else if (!strcmp(optarg,"long")) {
664 con->smartextendselftest = TRUE;
665 con->testcase = EXTEND_SELF_TEST;
666 } else if (!strcmp(optarg,"conveyance")) {
667 con->smartconveyanceselftest = TRUE;
668 con->testcase = CONVEYANCE_SELF_TEST;
669 } else if (!strcmp(optarg,"afterselect,on")) {
670 // scan remainder of disk after doing selected segments
671 con->scanafterselect=2;
672 } else if (!strcmp(optarg,"afterselect,off")) {
673 // don't scan remainder of disk after doing selected segments
674 con->scanafterselect=1;
675 } else if (!strncmp(optarg,"pending,",strlen("pending,"))) {
676 // parse number of minutes that test should be pending
677 int i;
678 char *tailptr=NULL;
679 errno=0;
680 i=(int)strtol(optarg+strlen("pending,"), &tailptr, 10);
681 if (errno || *tailptr != '\0') {
682 sprintf(extraerror, "Option -t pending,N requires N to be a non-negative integer\n");
683 badarg = TRUE;
684 } else if (i<0 || i>65535) {
685 sprintf(extraerror, "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i);
686 badarg = TRUE;
687 } else {
688 con->pendingtime=i+1;
689 }
690 } else if (!strncmp(optarg,"select",strlen("select"))) {
691 // parse range of LBAs to test
692 uint64_t start, stop;
693
694 if (split_selective_arg(optarg, &start, &stop)) {
695 sprintf(extraerror, "Option -t select,M-N must have non-negative integer M and N\n");
696 badarg = TRUE;
697 } else {
698 if (con->smartselectivenumspans >= 5 || start > stop) {
699 if (start > stop) {
700 sprintf(extraerror, "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n",
701 start, stop, optarg);
702 } else {
703 sprintf(extraerror,"ERROR: No more than five selective self-test spans may be"
704 " defined\n");
705 }
706 badarg = TRUE;
707 }
708 con->smartselectivespan[con->smartselectivenumspans][0] = start;
709 con->smartselectivespan[con->smartselectivenumspans][1] = stop;
710 con->smartselectivenumspans++;
711 con->testcase = SELECTIVE_SELF_TEST;
712 }
713 } else {
714 badarg = TRUE;
715 }
716 break;
717 case 'C':
718 captive = TRUE;
719 break;
720 case 'X':
721 con->smartselftestabort = TRUE;
722 con->testcase = ABORT_SELF_TEST;
723 break;
724 case 'n':
725 // skip disk check if in low-power mode
726 if (!strcmp(optarg, "never"))
727 con->powermode = 1; // do not skip, but print mode
728 else if (!strcmp(optarg, "sleep"))
729 con->powermode = 2;
730 else if (!strcmp(optarg, "standby"))
731 con->powermode = 3;
732 else if (!strcmp(optarg, "idle"))
733 con->powermode = 4;
734 else
735 badarg = TRUE;
736 break;
737 case 'h':
738 con->dont_print=FALSE;
739 printslogan();
740 Usage();
741 EXIT(0);
742 break;
743 case '?':
744 default:
745 con->dont_print=FALSE;
746 printslogan();
747 #ifdef HAVE_GETOPT_LONG
748 // Point arg to the argument in which this option was found.
749 arg = argv[optind-1];
750 // Check whether the option is a long option that doesn't map to -h.
751 if (arg[1] == '-' && optchar != 'h') {
752 // Iff optopt holds a valid option then argument must be missing.
753 if (optopt && (strchr(shortopts, optopt) != NULL)) {
754 pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2);
755 printvalidarglistmessage(optopt);
756 } else
757 pout("=======> UNRECOGNIZED OPTION: %s\n",arg+2);
758 if (extraerror[0])
759 pout("=======> %s", extraerror);
760 UsageSummary();
761 EXIT(FAILCMD);
762 }
763 #endif
764 if (optopt) {
765 // Iff optopt holds a valid option then argument must be
766 // missing. Note (BA) this logic seems to fail using Solaris
767 // getopt!
768 if (strchr(shortopts, optopt) != NULL) {
769 pout("=======> ARGUMENT REQUIRED FOR OPTION: %c\n", optopt);
770 printvalidarglistmessage(optopt);
771 } else
772 pout("=======> UNRECOGNIZED OPTION: %c\n",optopt);
773 if (extraerror[0])
774 pout("=======> %s", extraerror);
775 UsageSummary();
776 EXIT(FAILCMD);
777 }
778 Usage();
779 EXIT(0);
780 } // closes switch statement to process command-line options
781
782 // Check to see if option had an unrecognized or incorrect argument.
783 if (badarg) {
784 printslogan();
785 // It would be nice to print the actual option name given by the user
786 // here, but we just print the short form. Please fix this if you know
787 // a clean way to do it.
788 pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg);
789 printvalidarglistmessage(optchar);
790 if (extraerror[0])
791 pout("=======> %s", extraerror);
792 UsageSummary();
793 EXIT(FAILCMD);
794 }
795 }
796 // At this point we have processed all command-line options. If the
797 // print output is switchable, then start with the print output
798 // turned off
799 if (con->printing_switchable)
800 con->dont_print=TRUE;
801
802 // error message if user has asked for more than one test
803 if (1<(con->smartexeoffimmediate+con->smartshortselftest+con->smartextendselftest+
804 con->smartshortcapselftest+con->smartextendcapselftest+con->smartselftestabort + (con->smartselectivenumspans>0?1:0))){
805 con->dont_print=FALSE;
806 printslogan();
807 pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n");
808 UsageSummary();
809 EXIT(FAILCMD);
810 }
811
812 // error message if user has set selective self-test options without
813 // asking for a selective self-test
814 if ((con->pendingtime || con->scanafterselect) && !con->smartselectivenumspans){
815 con->dont_print=FALSE;
816 printslogan();
817 if (con->pendingtime)
818 pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n");
819 else
820 pout("\nERROR: smartctl -t afterselect,(on|off) must be used with -t select,N-M.\n");
821 UsageSummary();
822 EXIT(FAILCMD);
823 }
824
825 // If captive option was used, change test type if appropriate.
826 if (captive && con->smartshortselftest) {
827 con->smartshortselftest = FALSE;
828 con->smartshortcapselftest = TRUE;
829 con->testcase = SHORT_CAPTIVE_SELF_TEST;
830 } else if (captive && con->smartextendselftest) {
831 con->smartextendselftest = FALSE;
832 con->smartextendcapselftest = TRUE;
833 con->testcase = EXTEND_CAPTIVE_SELF_TEST;
834 }
835 else if (captive && con->smartconveyanceselftest) {
836 con->smartconveyanceselftest = FALSE;
837 con->smartconveyancecapselftest = TRUE;
838 con->testcase = CONVEYANCE_CAPTIVE_SELF_TEST;
839 }
840 else if (captive && con->smartselectiveselftest) {
841 con->smartselectiveselftest = FALSE;
842 con->smartselectivecapselftest = TRUE;
843 con->testcase = SELECTIVE_CAPTIVE_SELF_TEST;
844 }
845
846 // From here on, normal operations...
847 printslogan();
848
849 // Warn if the user has provided no device name
850 if (argc-optind<1){
851 pout("ERROR: smartctl requires a device name as the final command-line argument.\n\n");
852 UsageSummary();
853 EXIT(FAILCMD);
854 }
855
856 // Warn if the user has provided more than one device name
857 if (argc-optind>1){
858 int i;
859 pout("ERROR: smartctl takes ONE device name as the final command-line argument.\n");
860 pout("You have provided %d device names:\n",argc-optind);
861 for (i=0; i<argc-optind; i++)
862 pout("%s\n",argv[optind+i]);
863 UsageSummary();
864 EXIT(FAILCMD);
865 }
866 }
867
868 // Printing function (controlled by global con->dont_print)
869 // [From GLIBC Manual: Since the prototype doesn't specify types for
870 // optional arguments, in a call to a variadic function the default
871 // argument promotions are performed on the optional argument
872 // values. This means the objects of type char or short int (whether
873 // signed or not) are promoted to either int or unsigned int, as
874 // appropriate.]
875 void pout(const char *fmt, ...){
876 va_list ap;
877
878 // initialize variable argument list
879 va_start(ap,fmt);
880 if (con->dont_print){
881 va_end(ap);
882 return;
883 }
884
885 // print out
886 vprintf(fmt,ap);
887 va_end(ap);
888 fflush(stdout);
889 return;
890 }
891
892 // This function is used by utility.cpp to report LOG_CRIT errors.
893 // The smartctl version prints to stdout instead of syslog().
894 void PrintOut(int priority, const char *fmt, ...) {
895 va_list ap;
896
897 // avoid warning message about unused variable from gcc -W: just
898 // change value of local copy.
899 priority=0;
900
901 va_start(ap,fmt);
902 vprintf(fmt,ap);
903 va_end(ap);
904 return;
905 }
906
907
908 /* Main Program */
909 int main (int argc, char **argv){
910 int fd,retval=0;
911 char *device;
912 smartmonctrl control;
913 char *mode=NULL;
914
915 // define control block for external functions
916 con=&control;
917
918 // Part input arguments
919 ParseOpts(argc,argv);
920
921 device = argv[argc-1];
922
923 // If use has specified 3ware controller, determine which interface
924 if (con->controller_type == CONTROLLER_3WARE) {
925 con->controller_type=guess_device_type(device);
926 if (con->controller_type!=CONTROLLER_3WARE_9000_CHAR && con->controller_type!=CONTROLLER_3WARE_678K_CHAR)
927 con->controller_type = CONTROLLER_3WARE_678K;
928 }
929
930 if (con->controller_type == CONTROLLER_UNKNOWN)
931 con->controller_type=guess_device_type(device);
932
933 if (con->controller_type == CONTROLLER_UNKNOWN) {
934 pout("Smartctl: please specify device type with the -d option.\n");
935 UsageSummary();
936 return FAILCMD;
937 }
938
939 // set up mode for open() call. SCSI case is:
940 switch (con->controller_type) {
941 case CONTROLLER_SCSI:
942 case CONTROLLER_SAT:
943 mode="SCSI";
944 break;
945 case CONTROLLER_3WARE_9000_CHAR:
946 mode="ATA_3WARE_9000";
947 break;
948 case CONTROLLER_3WARE_678K_CHAR:
949 mode="ATA_3WARE_678K";
950 break;
951 default:
952 mode="ATA";
953 break;
954 }
955
956 // open device - SCSI devices are opened (O_RDWR | O_NONBLOCK) so the
957 // scsi generic device can be used (needs write permission for MODE
958 // SELECT command) plus O_NONBLOCK to stop open hanging if media not
959 // present (e.g. with st). Opening is retried O_RDONLY if read-only
960 // media prevents opening O_RDWR (it cannot happen for scsi generic
961 // devices, but it can for the others).
962 fd = deviceopen(device, mode);
963 if (fd<0) {
964 char errmsg[256];
965 snprintf(errmsg,256,"Smartctl open device: %s failed",argv[argc-1]);
966 errmsg[255]='\0';
967 syserror(errmsg);
968 return FAILDEV;
969 }
970
971 // now call appropriate ATA or SCSI routine
972 switch (con->controller_type) {
973 case CONTROLLER_UNKNOWN:
974 // we should never fall into this branch!
975 pout("Smartctl: please specify device type with the -d option.\n");
976 UsageSummary();
977 retval = FAILCMD;
978 break;
979 case CONTROLLER_SCSI:
980 retval = scsiPrintMain(fd);
981 if ((0 == retval) && (CONTROLLER_SAT == con->controller_type))
982 retval = ataPrintMain(fd);
983 break;
984 default:
985 retval = ataPrintMain(fd);
986 break;
987 }
988
989 return retval;
990 }