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