File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / smartmontools / smartctl.cpp
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:36:45 2012 UTC (11 years, 9 months ago) by misho
Branches: smartmontools, elwix, MAIN
CVS tags: v5_43, HEAD
smartmontools

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>