]> git.proxmox.com Git - mirror_smartmontools-debian.git/blame - smartctl.c
debian/rules: - remove autogenerated files
[mirror_smartmontools-debian.git] / smartctl.c
CommitLineData
832b75ed
GG
1/*
2 * smartctl.c
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
50extern const char *os_solaris_ata_s_cvsid;
51#endif
52extern 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;
53const char* smartctl_c_cvsid="$Id: smartctl.c,v 1.143 2006/04/12 14:54:28 ballen4705 Exp $"
54ATACMDS_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.
58smartmonctrl *con=NULL;
59
60// to hold onto exit code for atexit routine
61extern int exitstatus;
62
63// Track memory use
64extern int64_t bytes;
65
66void 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
77void PrintOneCVS(const char *a_cvs_id){
78 char out[CVSMAXLEN];
79 printone(out,a_cvs_id);
80 pout("%s",out);
81 return;
82}
83
84void 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
112void 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 */
118void 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, 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 );
154#else
155 printf(
156" -q TYPE Set smartctl quiet mode to one of: errorsonly, silent (ATA)\n"
157" -d TYPE Specify device type to one of: ata, scsi, 3ware,N\n"
158" -T TYPE Tolerance: normal, conservative,permissive,verypermissive (ATA\n"
159" -b TYPE Set action on bad checksum to one of: warn, exit, ignore (ATA)\n"
160" -r TYPE Report transactions (see man page)\n\n"
161 );
162#endif
163 printf("============================== DEVICE FEATURE ENABLE/DISABLE COMMANDS =====\n\n");
164#ifdef HAVE_GETOPT_LONG
165 printf(
166" -s VALUE, --smart=VALUE\n"
167" Enable/disable SMART on device (on/off)\n\n"
168" -o VALUE, --offlineauto=VALUE (ATA)\n"
169" Enable/disable automatic offline testing on device (on/off)\n\n"
170" -S VALUE, --saveauto=VALUE (ATA)\n"
171" Enable/disable Attribute autosave on device (on/off)\n\n"
172 );
173#else
174 printf(
175" -s VALUE Enable/disable SMART on device (on/off)\n"
176" -o VALUE Enable/disable device automatic offline testing (on/off) (ATA)\n"
177" -S VALUE Enable/disable device Attribute autosave (on/off) (ATA)\n\n"
178 );
179#endif
180 printf("======================================= READ AND DISPLAY DATA OPTIONS =====\n\n");
181#ifdef HAVE_GETOPT_LONG
182 printf(
183" -H, --health\n"
184" Show device SMART health status\n\n"
185" -c, --capabilities (ATA)\n"
186" Show device SMART capabilities\n\n"
187" -A, --attributes \n"
188" Show device SMART vendor-specific Attributes and values\n\n"
189" -l TYPE, --log=TYPE\n"
190" Show device log. TYPE: error, selftest, selective, directory\n\n"
191" -v N,OPTION , --vendorattribute=N,OPTION (ATA)\n"
192" Set display OPTION for vendor Attribute N (see man page)\n\n"
193" -F TYPE, --firmwarebug=TYPE (ATA)\n"
194" Use firmware bug workaround: none, samsung, samsung2\n\n"
195" -P TYPE, --presets=TYPE (ATA)\n"
196" Drive-specific presets: use, ignore, show, showall\n\n"
197 );
198#else
199 printf(
200" -H Show device SMART health status\n"
201" -c Show device SMART capabilities (ATA)\n"
202" -A Show device SMART vendor-specific Attributes and values (ATA)\n"
203" -l TYPE Show device log. TYPE: error,selftest,selective,directory\n"
204" -v N,OPT Set display OPTion for vendor Attribute N (see man page) (ATA)\n"
205" -F TYPE Use firmware bug workaround: none, samsung, samsung2 (ATA)\n"
206" -P TYPE Drive-specific presets: use, ignore, show, showall (ATA)\n\n"
207 );
208#endif
209 printf("============================================ DEVICE SELF-TEST OPTIONS =====\n\n");
210#ifdef HAVE_GETOPT_LONG
211 printf(
212" -t TEST, --test=TEST\n"
213" Run test. TEST is: offline short long conveyance select,M-N pending,N afterselect,on afterselect,off\n\n"
214" -C, --captive\n"
215" Do test in captive mode (along with -t)\n\n"
216" -X, --abort\n"
217" Abort any non-captive test on device\n\n"
218);
219#else
220 printf(
221" -t TEST Run test. TEST is: offline short long conveyance select,M-N pending,N afterselect,on afterselect,off\n"
222" -C Do test in captive mode (along with -t)\n"
223" -X Abort any non-captive test\n\n"
224 );
225#endif
226 print_smartctl_examples();
227 return;
228}
229
230/* Returns a pointer to a static string containing a formatted list of the valid
231 arguments to the option opt or NULL on failure. Note 'v' case different */
232const char *getvalidarglist(char opt) {
233 switch (opt) {
234 case 'q':
235 return "errorsonly, silent";
236 case 'd':
237 return "ata, scsi, marvell, 3ware,N";
238 case 'T':
239 return "normal, conservative, permissive, verypermissive";
240 case 'b':
241 return "warn, exit, ignore";
242 case 'r':
243 return "ioctl[,N], ataioctl[,N], scsiioctl[,N]";
244 case 's':
245 case 'o':
246 case 'S':
247 return "on, off";
248 case 'l':
249 return "error, selftest, selective, directory";
250 case 'P':
251 return "use, ignore, show, showall";
252 case 't':
253 return "offline, short, long, conveyance, select,M-N, pending,N, afterselect,on, afterselect,off";
254 case 'F':
255 return "none, samsung, samsung2";
256 case 'v':
257 default:
258 return NULL;
259 }
260}
261
262/* Prints the message "=======> VALID ARGUMENTS ARE: <LIST> \n", where
263 <LIST> is the list of valid arguments for option opt. */
264void printvalidarglistmessage(char opt) {
265 char *s;
266
267 if (opt=='v')
268 s=create_vendor_attribute_arg_list();
269 else
270 s=(char *)getvalidarglist(opt);
271
272 if (!s) {
273 pout("Error whilst constructing argument list for option %c", opt);
274 return;
275 }
276
277 if (opt=='v'){
278 pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n", s);
279 free(s);
280 }
281 else {
282 // getvalidarglist() might produce a multiline or single line string. We
283 // need to figure out which to get the formatting right.
284 char separator = strchr(s, '\n') ? '\n' : ' ';
285 pout("=======> VALID ARGUMENTS ARE:%c%s%c<=======\n", separator, (char *)s, separator);
286 }
287
288 return;
289}
290
291/* Takes command options and sets features to be run */
292void ParseOpts (int argc, char** argv){
293 int optchar;
294 int badarg;
295 int captive;
296 unsigned char *charp;
297 extern char *optarg;
298 extern int optopt, optind, opterr;
299 char extraerror[256];
300 // Please update getvalidarglist() if you edit shortopts
301 const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iav:P:t:CXF:";
302#ifdef HAVE_GETOPT_LONG
303 char *arg;
304 // Please update getvalidarglist() if you edit longopts
305 struct option longopts[] = {
306 { "help", no_argument, 0, 'h' },
307 { "usage", no_argument, 0, 'h' },
308 { "version", no_argument, 0, 'V' },
309 { "copyright", no_argument, 0, 'V' },
310 { "license", no_argument, 0, 'V' },
311 { "quietmode", required_argument, 0, 'q' },
312 { "device", required_argument, 0, 'd' },
313 { "tolerance", required_argument, 0, 'T' },
314 { "badsum", required_argument, 0, 'b' },
315 { "report", required_argument, 0, 'r' },
316 { "smart", required_argument, 0, 's' },
317 { "offlineauto", required_argument, 0, 'o' },
318 { "saveauto", required_argument, 0, 'S' },
319 { "health", no_argument, 0, 'H' },
320 { "capabilities", no_argument, 0, 'c' },
321 { "attributes", no_argument, 0, 'A' },
322 { "log", required_argument, 0, 'l' },
323 { "info", no_argument, 0, 'i' },
324 { "all", no_argument, 0, 'a' },
325 { "vendorattribute", required_argument, 0, 'v' },
326 { "presets", required_argument, 0, 'P' },
327 { "test", required_argument, 0, 't' },
328 { "captive", no_argument, 0, 'C' },
329 { "abort", no_argument, 0, 'X' },
330 { "firmwarebug", required_argument, 0, 'F' },
331 { 0, 0, 0, 0 }
332 };
333#endif
334
335 memset(extraerror, 0, sizeof(extraerror));
336 memset(con,0,sizeof(*con));
337 con->testcase=-1;
338 opterr=optopt=0;
339 badarg = captive = FALSE;
340
341 // This miserable construction is needed to get emacs to do proper indenting. Sorry!
342 while (-1 != (optchar =
343#ifdef HAVE_GETOPT_LONG
344 getopt_long(argc, argv, shortopts, longopts, NULL)
345#else
346 getopt(argc, argv, shortopts)
347#endif
348 )){
349 switch (optchar){
350 case 'V':
351 con->dont_print=FALSE;
352 printslogan();
353 printcopy();
354 exit(0);
355 break;
356 case 'q':
357 if (!strcmp(optarg,"errorsonly")) {
358 con->printing_switchable = TRUE;
359 con->dont_print = FALSE;
360 } else if (!strcmp(optarg,"silent")) {
361 con->printing_switchable = FALSE;
362 con->dont_print = TRUE;
363 } else {
364 badarg = TRUE;
365 }
366 break;
367 case 'd':
368 if (!strcmp(optarg,"ata")) {
369 con->controller_type = CONTROLLER_ATA;
370 con->controller_port = 0;
371 } else if (!strcmp(optarg,"scsi")) {
372 con->controller_type = CONTROLLER_SCSI;
373 con->controller_port = 0;
374 } else if (!strcmp(optarg,"marvell")) {
375 con->controller_type = CONTROLLER_MARVELL_SATA;
376 con->controller_port = 0;
377 } else {
378 // look for RAID-type device
379 int i;
380 char *s;
381
382 // make a copy of the string to mess with
383 if (!(s = strdup(optarg))) {
384 con->dont_print = FALSE;
385 pout("No memory for argument of -d. Exiting...\n");
386 exit(FAILCMD);
387 } else if (strncmp(s,"3ware,",6)) {
388 badarg = TRUE;
389 } else if (split_report_arg2(s, &i)) {
390 sprintf(extraerror, "Option -d 3ware,N requires N to be a non-negative integer\n");
391 badarg = TRUE;
392 } else if (i<0 || i>15) {
393 sprintf(extraerror, "Option -d 3ware,N (N=%d) must have 0 <= N <= 15\n", i);
394 badarg = TRUE;
395 } else {
396 // NOTE: controller_port == disk number + 1
397 con->controller_type = CONTROLLER_3WARE;
398 con->controller_port = i+1;
399 }
400 free(s);
401 }
402 break;
403 case 'T':
404 if (!strcmp(optarg,"normal")) {
405 con->conservative = FALSE;
406 con->permissive = 0;
407 } else if (!strcmp(optarg,"conservative")) {
408 con->conservative = TRUE;
409 } else if (!strcmp(optarg,"permissive")) {
410 if (con->permissive<0xff)
411 con->permissive++;
412 } else if (!strcmp(optarg,"verypermissive")) {
413 con->permissive=0xff;
414 } else {
415 badarg = TRUE;
416 }
417 break;
418 case 'b':
419 if (!strcmp(optarg,"warn")) {
420 con->checksumfail = FALSE;
421 con->checksumignore = FALSE;
422 } else if (!strcmp(optarg,"exit")) {
423 con->checksumfail = TRUE;
424 con->checksumignore = FALSE;
425 } else if (!strcmp(optarg,"ignore")) {
426 con->checksumignore = TRUE;
427 con->checksumfail = FALSE;
428 } else {
429 badarg = TRUE;
430 }
431 break;
432 case 'r':
433 {
434 int i;
435 char *s;
436
437 // split_report_arg() may modify its first argument string, so use a
438 // copy of optarg in case we want optarg for an error message.
439 if (!(s = strdup(optarg))) {
440 con->dont_print = FALSE;
441 pout("Can't allocate memory to copy argument to -r option"
442 " - exiting\n");
443 EXIT(FAILCMD);
444 }
445 if (split_report_arg(s, &i)) {
446 badarg = TRUE;
447 } else if (!strcmp(s,"ioctl")) {
448 con->reportataioctl = con->reportscsiioctl = i;
449 } else if (!strcmp(s,"ataioctl")) {
450 con->reportataioctl = i;
451 } else if (!strcmp(s,"scsiioctl")) {
452 con->reportscsiioctl = i;
453 } else {
454 badarg = TRUE;
455 }
456 free(s);
457 }
458 break;
459 case 's':
460 if (!strcmp(optarg,"on")) {
461 con->smartenable = TRUE;
462 con->smartdisable = FALSE;
463 } else if (!strcmp(optarg,"off")) {
464 con->smartdisable = TRUE;
465 con->smartenable = FALSE;
466 } else {
467 badarg = TRUE;
468 }
469 break;
470 case 'o':
471 if (!strcmp(optarg,"on")) {
472 con->smartautoofflineenable = TRUE;
473 con->smartautoofflinedisable = FALSE;
474 } else if (!strcmp(optarg,"off")) {
475 con->smartautoofflinedisable = TRUE;
476 con->smartautoofflineenable = FALSE;
477 } else {
478 badarg = TRUE;
479 }
480 break;
481 case 'S':
482 if (!strcmp(optarg,"on")) {
483 con->smartautosaveenable = TRUE;
484 con->smartautosavedisable = FALSE;
485 } else if (!strcmp(optarg,"off")) {
486 con->smartautosavedisable = TRUE;
487 con->smartautosaveenable = FALSE;
488 } else {
489 badarg = TRUE;
490 }
491 break;
492 case 'H':
493 con->checksmart = TRUE;
494 break;
495 case 'F':
496 if (!strcmp(optarg,"none")) {
497 con->fixfirmwarebug = FIX_NONE;
498 } else if (!strcmp(optarg,"samsung")) {
499 con->fixfirmwarebug = FIX_SAMSUNG;
500 } else if (!strcmp(optarg,"samsung2")) {
501 con->fixfirmwarebug = FIX_SAMSUNG2;
502 } else {
503 badarg = TRUE;
504 }
505 break;
506 case 'c':
507 con->generalsmartvalues = TRUE;
508 break;
509 case 'A':
510 con->smartvendorattrib = TRUE;
511 break;
512 case 'l':
513 if (!strcmp(optarg,"error")) {
514 con->smarterrorlog = TRUE;
515 } else if (!strcmp(optarg,"selftest")) {
516 con->smartselftestlog = TRUE;
517 } else if (!strcmp(optarg, "selective")) {
518 con->selectivetestlog = TRUE;
519 } else if (!strcmp(optarg,"directory")) {
520 con->smartlogdirectory = TRUE;
521 } else {
522 badarg = TRUE;
523 }
524 break;
525 case 'i':
526 con->driveinfo = TRUE;
527 break;
528 case 'a':
529 con->driveinfo = TRUE;
530 con->checksmart = TRUE;
531 con->generalsmartvalues = TRUE;
532 con->smartvendorattrib = TRUE;
533 con->smarterrorlog = TRUE;
534 con->smartselftestlog = TRUE;
535 con->selectivetestlog = TRUE;
536 break;
537 case 'v':
538 // parse vendor-specific definitions of attributes
539 if (!strcmp(optarg,"help")) {
540 char *s;
541 con->dont_print=FALSE;
542 printslogan();
543 if (!(s = create_vendor_attribute_arg_list())) {
544 pout("Insufficient memory to construct argument list\n");
545 EXIT(FAILCMD);
546 }
547 pout("The valid arguments to -v are:\n\thelp\n%s\n", s);
548 free(s);
549 EXIT(0);
550 }
551 charp=con->attributedefs;
552 if (!charp){
553 pout("Fatal internal error in ParseOpts()\n");
554 EXIT(FAILCMD);
555 }
556 if (parse_attribute_def(optarg, &charp))
557 badarg = TRUE;
558 break;
559 case 'P':
560 if (!strcmp(optarg, "use")) {
561 con->ignorepresets = FALSE;
562 } else if (!strcmp(optarg, "ignore")) {
563 con->ignorepresets = TRUE;
564 } else if (!strcmp(optarg, "show")) {
565 con->showpresets = TRUE;
566 } else if (!strcmp(optarg, "showall")) {
567 if (optind < argc) { // -P showall MODEL [FIRMWARE]
568 int cnt = showmatchingpresets(argv[optind], (optind+1<argc ? argv[optind+1] : NULL));
569 EXIT(cnt); // report #matches
570 }
571 if (showallpresets())
572 EXIT(FAILCMD); // report regexp syntax error
573 EXIT(0);
574 } else {
575 badarg = TRUE;
576 }
577 break;
578 case 't':
579 if (!strcmp(optarg,"offline")) {
580 con->smartexeoffimmediate = TRUE;
581 con->testcase = OFFLINE_FULL_SCAN;
582 } else if (!strcmp(optarg,"short")) {
583 con->smartshortselftest = TRUE;
584 con->testcase = SHORT_SELF_TEST;
585 } else if (!strcmp(optarg,"long")) {
586 con->smartextendselftest = TRUE;
587 con->testcase = EXTEND_SELF_TEST;
588 } else if (!strcmp(optarg,"conveyance")) {
589 con->smartconveyanceselftest = TRUE;
590 con->testcase = CONVEYANCE_SELF_TEST;
591 } else if (!strcmp(optarg,"afterselect,on")) {
592 // scan remainder of disk after doing selected segments
593 con->scanafterselect=2;
594 } else if (!strcmp(optarg,"afterselect,off")) {
595 // don't scan remainder of disk after doing selected segments
596 con->scanafterselect=1;
597 } else if (!strncmp(optarg,"pending,",strlen("pending,"))) {
598 // parse number of minutes that test should be pending
599 int i;
600 char *tailptr=NULL;
601 errno=0;
602 i=(int)strtol(optarg+strlen("pending,"), &tailptr, 10);
603 if (errno || *tailptr != '\0') {
604 sprintf(extraerror, "Option -t pending,N requires N to be a non-negative integer\n");
605 badarg = TRUE;
606 } else if (i<0 || i>65535) {
607 sprintf(extraerror, "Option -t pending,N (N=%d) must have 0 <= N <= 65535\n", i);
608 badarg = TRUE;
609 } else {
610 con->pendingtime=i+1;
611 }
612 } else if (!strncmp(optarg,"select",strlen("select"))) {
613 // parse range of LBAs to test
614 uint64_t start, stop;
615
616 if (split_selective_arg(optarg, &start, &stop)) {
617 sprintf(extraerror, "Option -t select,M-N must have non-negative integer M and N\n");
618 badarg = TRUE;
619 } else {
620 if (con->smartselectivenumspans >= 5 || start > stop) {
621 if (start > stop) {
622 sprintf(extraerror, "ERROR: Start LBA (%"PRIu64") > ending LBA (%"PRId64") in argument \"%s\"\n",
623 start, stop, optarg);
624 } else {
625 sprintf(extraerror,"ERROR: No more than five selective self-test spans may be"
626 " defined\n");
627 }
628 badarg = TRUE;
629 }
630 con->smartselectivespan[con->smartselectivenumspans][0] = start;
631 con->smartselectivespan[con->smartselectivenumspans][1] = stop;
632 con->smartselectivenumspans++;
633 con->testcase = SELECTIVE_SELF_TEST;
634 }
635 } else {
636 badarg = TRUE;
637 }
638 break;
639 case 'C':
640 captive = TRUE;
641 break;
642 case 'X':
643 con->smartselftestabort = TRUE;
644 con->testcase = ABORT_SELF_TEST;
645 break;
646 case 'h':
647 con->dont_print=FALSE;
648 printslogan();
649 Usage();
650 EXIT(0);
651 break;
652 case '?':
653 default:
654 con->dont_print=FALSE;
655 printslogan();
656#ifdef HAVE_GETOPT_LONG
657 // Point arg to the argument in which this option was found.
658 arg = argv[optind-1];
659 // Check whether the option is a long option that doesn't map to -h.
660 if (arg[1] == '-' && optchar != 'h') {
661 // Iff optopt holds a valid option then argument must be missing.
662 if (optopt && (strchr(shortopts, optopt) != NULL)) {
663 pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2);
664 printvalidarglistmessage(optopt);
665 } else
666 pout("=======> UNRECOGNIZED OPTION: %s\n",arg+2);
667 if (extraerror[0])
668 pout("=======> %s", extraerror);
669 UsageSummary();
670 EXIT(FAILCMD);
671 }
672#endif
673 if (optopt) {
674 // Iff optopt holds a valid option then argument must be
675 // missing. Note (BA) this logic seems to fail using Solaris
676 // getopt!
677 if (strchr(shortopts, optopt) != NULL) {
678 pout("=======> ARGUMENT REQUIRED FOR OPTION: %c\n", optopt);
679 printvalidarglistmessage(optopt);
680 } else
681 pout("=======> UNRECOGNIZED OPTION: %c\n",optopt);
682 if (extraerror[0])
683 pout("=======> %s", extraerror);
684 UsageSummary();
685 EXIT(FAILCMD);
686 }
687 Usage();
688 EXIT(0);
689 } // closes switch statement to process command-line options
690
691 // Check to see if option had an unrecognized or incorrect argument.
692 if (badarg) {
693 printslogan();
694 // It would be nice to print the actual option name given by the user
695 // here, but we just print the short form. Please fix this if you know
696 // a clean way to do it.
697 pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg);
698 printvalidarglistmessage(optchar);
699 if (extraerror[0])
700 pout("=======> %s", extraerror);
701 UsageSummary();
702 EXIT(FAILCMD);
703 }
704 }
705 // At this point we have processed all command-line options. If the
706 // print output is switchable, then start with the print output
707 // turned off
708 if (con->printing_switchable)
709 con->dont_print=TRUE;
710
711 // error message if user has asked for more than one test
712 if (1<(con->smartexeoffimmediate+con->smartshortselftest+con->smartextendselftest+
713 con->smartshortcapselftest+con->smartextendcapselftest+con->smartselftestabort + (con->smartselectivenumspans>0?1:0))){
714 con->dont_print=FALSE;
715 printslogan();
716 pout("\nERROR: smartctl can only run a single test type (or abort) at a time.\n");
717 UsageSummary();
718 EXIT(FAILCMD);
719 }
720
721 // error message if user has set selective self-test options without
722 // asking for a selective self-test
723 if ((con->pendingtime || con->scanafterselect) && !con->smartselectivenumspans){
724 con->dont_print=FALSE;
725 printslogan();
726 if (con->pendingtime)
727 pout("\nERROR: smartctl -t pending,N must be used with -t select,N-M.\n");
728 else
729 pout("\nERROR: smartctl -t afterselect,(on|off) must be used with -t select,N-M.\n");
730 UsageSummary();
731 EXIT(FAILCMD);
732 }
733
734 // If captive option was used, change test type if appropriate.
735 if (captive && con->smartshortselftest) {
736 con->smartshortselftest = FALSE;
737 con->smartshortcapselftest = TRUE;
738 con->testcase = SHORT_CAPTIVE_SELF_TEST;
739 } else if (captive && con->smartextendselftest) {
740 con->smartextendselftest = FALSE;
741 con->smartextendcapselftest = TRUE;
742 con->testcase = EXTEND_CAPTIVE_SELF_TEST;
743 }
744 else if (captive && con->smartconveyanceselftest) {
745 con->smartconveyanceselftest = FALSE;
746 con->smartconveyancecapselftest = TRUE;
747 con->testcase = CONVEYANCE_CAPTIVE_SELF_TEST;
748 }
749 else if (captive && con->smartselectiveselftest) {
750 con->smartselectiveselftest = FALSE;
751 con->smartselectivecapselftest = TRUE;
752 con->testcase = SELECTIVE_CAPTIVE_SELF_TEST;
753 }
754
755 // From here on, normal operations...
756 printslogan();
757
758 // Warn if the user has provided no device name
759 if (argc-optind<1){
760 pout("ERROR: smartctl requires a device name as the final command-line argument.\n\n");
761 UsageSummary();
762 EXIT(FAILCMD);
763 }
764
765 // Warn if the user has provided more than one device name
766 if (argc-optind>1){
767 int i;
768 pout("ERROR: smartctl takes ONE device name as the final command-line argument.\n");
769 pout("You have provided %d device names:\n",argc-optind);
770 for (i=0; i<argc-optind; i++)
771 pout("%s\n",argv[optind+i]);
772 UsageSummary();
773 EXIT(FAILCMD);
774 }
775}
776
777// Printing function (controlled by global con->dont_print)
778// [From GLIBC Manual: Since the prototype doesn't specify types for
779// optional arguments, in a call to a variadic function the default
780// argument promotions are performed on the optional argument
781// values. This means the objects of type char or short int (whether
782// signed or not) are promoted to either int or unsigned int, as
783// appropriate.]
784void pout(char *fmt, ...){
785 va_list ap;
786
787 // initialize variable argument list
788 va_start(ap,fmt);
789 if (con->dont_print){
790 va_end(ap);
791 return;
792 }
793
794 // print out
795 vprintf(fmt,ap);
796 va_end(ap);
797 fflush(stdout);
798 return;
799}
800
801// This function is used by utility.c to report LOG_CRIT errors.
802// The smartctl version prints to stdout instead of syslog().
803void PrintOut(int priority, char *fmt, ...) {
804 va_list ap;
805
806 // avoid warning message about unused variable from gcc -W: just
807 // change value of local copy.
808 priority=0;
809
810 va_start(ap,fmt);
811 vprintf(fmt,ap);
812 va_end(ap);
813 return;
814}
815
816
817/* Main Program */
818int main (int argc, char **argv){
819 int fd,retval=0;
820 char *device;
821 smartmonctrl control;
822 char *mode=NULL;
823
824 // define control block for external functions
825 con=&control;
826
827 // Part input arguments
828 ParseOpts(argc,argv);
829
830 device = argv[argc-1];
831
832 // If use has specified 3ware controller, determine which interface
833 if (con->controller_type == CONTROLLER_3WARE) {
834 con->controller_type=guess_device_type(device);
835 if (con->controller_type!=CONTROLLER_3WARE_9000_CHAR && con->controller_type!=CONTROLLER_3WARE_678K_CHAR)
836 con->controller_type = CONTROLLER_3WARE_678K;
837 }
838
839 if (con->controller_type == CONTROLLER_UNKNOWN)
840 con->controller_type=guess_device_type(device);
841
842 if (con->controller_type == CONTROLLER_UNKNOWN) {
843 pout("Smartctl: please specify device type with the -d option.\n");
844 UsageSummary();
845 return FAILCMD;
846 }
847
848 // set up mode for open() call. SCSI case is:
849 switch (con->controller_type) {
850 case CONTROLLER_SCSI:
851 mode="SCSI";
852 break;
853 case CONTROLLER_3WARE_9000_CHAR:
854 mode="ATA_3WARE_9000";
855 break;
856 case CONTROLLER_3WARE_678K_CHAR:
857 mode="ATA_3WARE_678K";
858 break;
859 default:
860 mode="ATA";
861 break;
862 }
863
864 // open device - SCSI devices are opened (O_RDWR | O_NONBLOCK) so the
865 // scsi generic device can be used (needs write permission for MODE
866 // SELECT command) plus O_NONBLOCK to stop open hanging if media not
867 // present (e.g. with st). Opening is retried O_RDONLY if read-only
868 // media prevents opening O_RDWR (it cannot happen for scsi generic
869 // devices, but it can for the others).
870 fd = deviceopen(device, mode);
871 if (fd<0) {
872 char errmsg[256];
873 snprintf(errmsg,256,"Smartctl open device: %s failed",argv[argc-1]);
874 errmsg[255]='\0';
875 syserror(errmsg);
876 return FAILDEV;
877 }
878
879 // now call appropriate ATA or SCSI routine
880 switch (con->controller_type) {
881 case CONTROLLER_UNKNOWN:
882 // we should never fall into this branch!
883 pout("Smartctl: please specify device type with the -d option.\n");
884 UsageSummary();
885 retval = FAILCMD;
886 break;
887 case CONTROLLER_SCSI:
888 retval = scsiPrintMain(fd);
889 break;
890 default:
891 retval = ataPrintMain(fd);
892 break;
893 }
894
895 return retval;
896}