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