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