--- embedaddon/smartmontools/smartctl.cpp 2012/02/21 16:32:16 1.1.1.1 +++ embedaddon/smartmontools/smartctl.cpp 2012/10/09 09:36:45 1.1.1.2 @@ -4,7 +4,7 @@ * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-11 Bruce Allen - * Copyright (C) 2008-11 Christian Franke + * Copyright (C) 2008-12 Christian Franke * Copyright (C) 2000 Michael Cornwell * * This program is free software; you can redistribute it and/or modify @@ -55,7 +55,7 @@ #include "smartctl.h" #include "utility.h" -const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp,v 1.1.1.1 2012/02/21 16:32:16 misho Exp $" +const char * smartctl_cpp_cvsid = "$Id: smartctl.cpp,v 1.1.1.2 2012/10/09 09:36:45 misho Exp $" CONFIG_H_CVSID SMARTCTL_H_CVSID; // Globals to control printing @@ -73,7 +73,7 @@ static void UsageSummary() return; } -static std::string getvalidarglist(char opt); +static std::string getvalidarglist(int opt); /* void prints help information for command syntax */ static void Usage() @@ -85,9 +85,11 @@ static void Usage() " Display this help and exit\n\n" " -V, --version, --copyright, --license\n" " Print license, copyright, and version information and exit\n\n" -" -i, --info \n" +" -i, --info\n" " Show identity information for device\n\n" -" -a, --all \n" +" -g NAME, --get=NAME\n" +" Get device setting: all, aam, apm, lookahead, security, wcache\n\n" +" -a, --all\n" " Show all SMART information for device\n\n" " -x, --xall\n" " Show all information for device\n\n" @@ -119,6 +121,10 @@ static void Usage() " Enable/disable automatic offline testing on device (on/off)\n\n" " -S VALUE, --saveauto=VALUE (ATA)\n" " Enable/disable Attribute autosave on device (on/off)\n\n" +" -s NAME[,VALUE], --set=NAME[,VALUE]\n" +" Enable/disable/change device setting: aam,[N|off], apm,[N|off],\n" +" lookahead,[on|off], security-freeze, standby,[N|off|now],\n" +" wcache,[on|off]\n\n" ); printf( "======================================= READ AND DISPLAY DATA OPTIONS =====\n\n" @@ -129,7 +135,7 @@ static void Usage() " -A, --attributes\n" " Show device SMART vendor-specific Attributes and values\n\n" " -f FORMAT, --format=FORMAT (ATA)\n" -" Set output format for attributes to one of: old, brief\n\n" +" Set output format for attributes: old, brief, hex[,id|val]\n\n" " -l TYPE, --log=TYPE\n" " Show device log. TYPE: error, selftest, selective, directory[,g|s],\n" " xerror[,N][,error], xselftest[,N][,selftest],\n" @@ -160,7 +166,7 @@ static void Usage() "]\n\n" "============================================ DEVICE SELF-TEST OPTIONS =====\n\n" " -t TEST, --test=TEST\n" -" Run test. TEST: offline, short, long, conveyance, vendor,N,\n" +" Run test. TEST: offline, short, long, conveyance, force, vendor,N,\n" " select,M-N, pending,N, afterselect,[on|off]\n\n" " -C, --captive\n" " Do test in captive mode (along with -t)\n\n" @@ -172,9 +178,12 @@ static void Usage() printf("%s\n", examples.c_str()); } +// Values for --long only options, see parse_options() +enum { opt_scan = 1000, opt_scan_open, opt_set, opt_smart }; + /* Returns a string containing a formatted list of the valid arguments to the option opt or empty on failure. Note 'v' case different */ -static std::string getvalidarglist(char opt) +static std::string getvalidarglist(int opt) { switch (opt) { case 'q': @@ -187,7 +196,7 @@ static std::string getvalidarglist(char opt) return "warn, exit, ignore"; case 'r': return "ioctl[,N], ataioctl[,N], scsiioctl[,N]"; - case 's': + case opt_smart: case 'o': case 'S': return "on, off"; @@ -202,14 +211,21 @@ static std::string getvalidarglist(char opt) case 'P': return "use, ignore, show, showall"; case 't': - return "offline, short, long, conveyance, vendor,N, select,M-N, " + return "offline, short, long, conveyance, force, vendor,N, select,M-N, " "pending,N, afterselect,[on|off]"; case 'F': return "none, samsung, samsung2, samsung3, swapid"; case 'n': return "never, sleep, standby, idle"; case 'f': - return "old, brief"; + return "old, brief, hex[,id|val]"; + case 'g': + return "aam, apm, lookahead, security, wcache"; + case opt_set: + return "aam,[N|off], apm,[N|off], lookahead,[on|off], security-freeze, " + "standby,[N|off|now], wcache,[on|off]"; + case 's': + return getvalidarglist(opt_smart)+", "+getvalidarglist(opt_set); case 'v': default: return ""; @@ -218,7 +234,7 @@ static std::string getvalidarglist(char opt) /* Prints the message "=======> VALID ARGUMENTS ARE: \n", where is the list of valid arguments for option opt. */ -static void printvalidarglistmessage(char opt) +static void printvalidarglistmessage(int opt) { if (opt=='v'){ pout("=======> VALID ARGUMENTS ARE:\n\thelp\n%s\n<=======\n", @@ -244,15 +260,15 @@ static checksum_err_mode_t checksum_err_mode = CHECKSU static void scan_devices(const char * type, bool with_open, char ** argv); + /* Takes command options and sets features to be run */ static const char * parse_options(int argc, char** argv, - ata_print_options & ataopts, - scsi_print_options & scsiopts) + ata_print_options & ataopts, scsi_print_options & scsiopts, + bool & print_type_only) { // Please update getvalidarglist() if you edit shortopts - const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iaxv:P:t:CXF:n:B:f:"; + const char *shortopts = "h?Vq:d:T:b:r:s:o:S:HcAl:iaxv:P:t:CXF:n:B:f:g:"; // Please update getvalidarglist() if you edit longopts - enum { opt_scan = 1000, opt_scan_open = 1001 }; struct option longopts[] = { { "help", no_argument, 0, 'h' }, { "usage", no_argument, 0, 'h' }, @@ -264,7 +280,7 @@ static const char * parse_options(int argc, char** arg { "tolerance", required_argument, 0, 'T' }, { "badsum", required_argument, 0, 'b' }, { "report", required_argument, 0, 'r' }, - { "smart", required_argument, 0, 's' }, + { "smart", required_argument, 0, opt_smart }, { "offlineauto", required_argument, 0, 'o' }, { "saveauto", required_argument, 0, 'S' }, { "health", no_argument, 0, 'H' }, @@ -283,6 +299,8 @@ static const char * parse_options(int argc, char** arg { "nocheck", required_argument, 0, 'n' }, { "drivedb", required_argument, 0, 'B' }, { "format", required_argument, 0, 'f' }, + { "get", required_argument, 0, 'g' }, + { "set", required_argument, 0, opt_set }, { "scan", no_argument, 0, opt_scan }, { "scan-open", no_argument, 0, opt_scan_open }, { 0, 0, 0, 0 } @@ -323,7 +341,10 @@ static const char * parse_options(int argc, char** arg } break; case 'd': - type = (strcmp(optarg, "auto") ? optarg : (char *)0); + if (!strcmp(optarg, "test")) + print_type_only = true; + else + type = (strcmp(optarg, "auto") ? optarg : (char *)0); break; case 'T': if (!strcmp(optarg,"normal")) { @@ -375,17 +396,22 @@ static const char * parse_options(int argc, char** arg free(s); } break; + case 's': + case opt_smart: // --smart if (!strcmp(optarg,"on")) { ataopts.smart_enable = scsiopts.smart_enable = true; ataopts.smart_disable = scsiopts.smart_disable = false; } else if (!strcmp(optarg,"off")) { ataopts.smart_disable = scsiopts.smart_disable = true; ataopts.smart_enable = scsiopts.smart_enable = false; + } else if (optchar == 's') { + goto case_s_continued; // --set, see below } else { badarg = true; } break; + case 'o': if (!strcmp(optarg,"on")) { ataopts.smart_auto_offl_enable = true; @@ -593,11 +619,15 @@ static const char * parse_options(int argc, char** arg ataopts.sct_temp_sts = ataopts.sct_temp_hist = true; ataopts.sct_erc_get = true; ataopts.sataphy = true; + ataopts.get_set_used = true; + ataopts.get_aam = ataopts.get_apm = true; + ataopts.get_security = true; + ataopts.get_lookahead = ataopts.get_wcache = true; scsiopts.smart_background_log = true; scsiopts.smart_ss_media_log = true; scsiopts.sasphy = true; if (!output_format_set) - ataopts.output_format = 1; // '-f brief' + ataopts.output_format |= ata_print_options::FMT_BRIEF; break; case 'v': // parse vendor-specific definitions of attributes @@ -648,6 +678,8 @@ static const char * parse_options(int argc, char** arg } else if (!strcmp(optarg,"conveyance")) { testcnt++; ataopts.smart_selftest_type = CONVEYANCE_SELF_TEST; + } else if (!strcmp(optarg,"force")) { + ataopts.smart_selftest_force = true; } else if (!strcmp(optarg,"afterselect,on")) { // scan remainder of disk after doing selected segment ataopts.smart_selective_args.scan_after_select = 2; @@ -732,14 +764,23 @@ static const char * parse_options(int argc, char** arg badarg = true; break; case 'f': - output_format_set = true; - if (!strcmp(optarg,"old")) { - ataopts.output_format = 0; - } else if (!strcmp(optarg,"brief")) { - ataopts.output_format = 1; - } else { - badarg = true; + if (!strcmp(optarg, "old")) { + ataopts.output_format &= ~ata_print_options::FMT_BRIEF; + output_format_set = true; } + else if (!strcmp(optarg, "brief")) { + ataopts.output_format |= ata_print_options::FMT_BRIEF; + output_format_set = true; + } + else if (!strcmp(optarg, "hex")) + ataopts.output_format |= ata_print_options::FMT_HEX_ID + | ata_print_options::FMT_HEX_VAL; + else if (!strcmp(optarg, "hex,id")) + ataopts.output_format |= ata_print_options::FMT_HEX_ID; + else if (!strcmp(optarg, "hex,val")) + ataopts.output_format |= ata_print_options::FMT_HEX_VAL; + else + badarg = true; break; case 'B': { @@ -759,6 +800,97 @@ static const char * parse_options(int argc, char** arg EXIT(0); break; + case 'g': + case_s_continued: // -s, see above + case opt_set: // --set + { + ataopts.get_set_used = true; + bool get = (optchar == 'g'); + char name[16+1]; unsigned val; + int n1 = -1, n2 = -1, n3 = -1, len = strlen(optarg); + if (sscanf(optarg, "%16[^,=]%n%*[,=]%n%u%n", name, &n1, &n2, &val, &n3) >= 1 + && (n1 == len || (!get && n2 > 0))) { + bool on = (n2 > 0 && !strcmp(optarg+n2, "on")); + bool off = (n2 > 0 && !strcmp(optarg+n2, "off")); + if (n3 != len) + val = ~0U; + + if (get && !strcmp(name, "all")) { + ataopts.get_aam = ataopts.get_apm = true; + ataopts.get_security = true; + ataopts.get_lookahead = ataopts.get_wcache = true; + } + else if (!strcmp(name, "aam")) { + if (get) + ataopts.get_aam = true; + else if (off) + ataopts.set_aam = -1; + else if (val <= 254) + ataopts.set_aam = val + 1; + else { + sprintf(extraerror, "Option -s aam,N must have 0 <= N <= 254\n"); + badarg = true; + } + } + else if (!strcmp(name, "apm")) { + if (get) + ataopts.get_apm = true; + else if (off) + ataopts.set_apm = -1; + else if (1 <= val && val <= 254) + ataopts.set_apm = val + 1; + else { + sprintf(extraerror, "Option -s apm,N must have 1 <= N <= 254\n"); + badarg = true; + } + } + else if (!strcmp(name, "lookahead")) { + if (get) + ataopts.get_lookahead = true; + else if (off) + ataopts.set_lookahead = -1; + else if (on) + ataopts.set_lookahead = 1; + else + badarg = true; + } + else if (get && !strcmp(name, "security")) { + ataopts.get_security = true; + } + else if (!get && !strcmp(optarg, "security-freeze")) { + ataopts.set_security_freeze = true; + } + else if (!get && !strcmp(optarg, "standby,now")) { + ataopts.set_standby_now = true; + } + else if (!get && !strcmp(name, "standby")) { + if (off) + ataopts.set_standby = 0 + 1; + else if (val <= 255) + ataopts.set_standby = val + 1; + else { + sprintf(extraerror, "Option -s standby,N must have 0 <= N <= 255\n"); + badarg = true; + } + } + else if (!strcmp(name, "wcache")) { + if (get) + ataopts.get_wcache = true; + else if (off) + ataopts.set_wcache = -1; + else if (on) + ataopts.set_wcache = 1; + else + badarg = true; + } + else + badarg = true; + } + else + badarg = true; + } + break; + case opt_scan: case opt_scan_open: scan = optchar; @@ -773,7 +905,7 @@ static const char * parse_options(int argc, char** arg // Check whether the option is a long option that doesn't map to -h. if (arg[1] == '-' && optchar != 'h') { // Iff optopt holds a valid option then argument must be missing. - if (optopt && (strchr(shortopts, optopt) != NULL)) { + if (optopt && (optopt >= opt_scan || strchr(shortopts, optopt))) { pout("=======> ARGUMENT REQUIRED FOR OPTION: %s\n", arg+2); printvalidarglistmessage(optopt); } else @@ -783,7 +915,7 @@ static const char * parse_options(int argc, char** arg UsageSummary(); EXIT(FAILCMD); } - if (optopt) { + if (0 < optopt && optopt < '~') { // Iff optopt holds a valid option then argument must be // missing. Note (BA) this logic seems to fail using Solaris // getopt! @@ -807,7 +939,10 @@ static const char * parse_options(int argc, char** arg // It would be nice to print the actual option name given by the user // here, but we just print the short form. Please fix this if you know // a clean way to do it. - pout("=======> INVALID ARGUMENT TO -%c: %s\n", optchar, optarg); + char optstr[] = { (char)optchar, 0 }; + pout("=======> INVALID ARGUMENT TO -%s: %s\n", + (optchar == opt_set ? "-set" : + optchar == opt_smart ? "-smart" : optstr), optarg); printvalidarglistmessage(optchar); if (extraerror[0]) pout("=======> %s", extraerror); @@ -1046,12 +1181,8 @@ static int main_worker(int argc, char **argv) // Parse input arguments ata_print_options ataopts; scsi_print_options scsiopts; - const char * type = parse_options(argc, argv, ataopts, scsiopts); - - // '-d test' -> Report result of autodetection - bool print_type_only = (type && !strcmp(type, "test")); - if (print_type_only) - type = 0; + bool print_type_only = false; + const char * type = parse_options(argc, argv, ataopts, scsiopts, print_type_only); const char * name = argv[argc-1];