📄 atacmds.cpp
字号:
/* * atacmds.cpp * * Home page of code is: http://smartmontools.sourceforge.net * * Copyright (C) 2002-8 Bruce Allen <smartmontools-support@lists.sourceforge.net> * Copyright (C) 1999-2000 Michael Cornwell <cornwell@acm.org> * Copyright (C) 2000 Andre Hedrick <andre@linux-ide.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * This code was originally developed as a Senior Thesis by Michael Cornwell * at the Concurrent Systems Laboratory (now part of the Storage Systems * Research Center), Jack Baskin School of Engineering, University of * California, Santa Cruz. http://ssrc.soe.ucsc.edu/ * */#include <stdio.h>#include <string.h>#include <errno.h>#include <stdlib.h>#include <ctype.h>#include "config.h"#include "int64.h"#include "atacmds.h"#include "scsiata.h"#include "extern.h"#include "utility.h"const char *atacmds_c_cvsid="$Id: atacmds.cpp,v 1.190 2008/03/04 22:09:47 ballen4705 Exp $"ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID SCSIATA_H_CVSID UTILITY_H_CVSID;// to hold onto exit code for atexit routineextern int exitstatus;// for passing global control variablesextern smartmonctrl *con;// These Drive Identity tables are taken from hdparm 5.2, and are also// given in the ATA/ATAPI specs for the IDENTIFY DEVICE command. Note// that SMART was first added into the ATA/ATAPI-3 Standard with// Revision 3 of the document, July 25, 1995. Look at the "Document// Status" revision commands at the beginning of// http://www.t13.org/project/d2008r6.pdf to see this.#define NOVAL_0 0x0000#define NOVAL_1 0xffff/* word 81: minor version number */#define MINOR_MAX 0x22const char *minor_str[] = { /* word 81 value: */ "Device does not report version", /* 0x0000 */ "ATA-1 X3T9.2 781D prior to revision 4", /* 0x0001 */ "ATA-1 published, ANSI X3.221-1994", /* 0x0002 */ "ATA-1 X3T9.2 781D revision 4", /* 0x0003 */ "ATA-2 published, ANSI X3.279-1996", /* 0x0004 */ "ATA-2 X3T10 948D prior to revision 2k", /* 0x0005 */ "ATA-3 X3T10 2008D revision 1", /* 0x0006 */ /* SMART NOT INCLUDED */ "ATA-2 X3T10 948D revision 2k", /* 0x0007 */ "ATA-3 X3T10 2008D revision 0", /* 0x0008 */ "ATA-2 X3T10 948D revision 3", /* 0x0009 */ "ATA-3 published, ANSI X3.298-199x", /* 0x000a */ "ATA-3 X3T10 2008D revision 6", /* 0x000b */ /* 1st VERSION WITH SMART */ "ATA-3 X3T13 2008D revision 7 and 7a", /* 0x000c */ "ATA/ATAPI-4 X3T13 1153D revision 6", /* 0x000d */ "ATA/ATAPI-4 T13 1153D revision 13", /* 0x000e */ "ATA/ATAPI-4 X3T13 1153D revision 7", /* 0x000f */ "ATA/ATAPI-4 T13 1153D revision 18", /* 0x0010 */ "ATA/ATAPI-4 T13 1153D revision 15", /* 0x0011 */ "ATA/ATAPI-4 published, ANSI NCITS 317-1998", /* 0x0012 */ "ATA/ATAPI-5 T13 1321D revision 3", /* 0x0013 */ "ATA/ATAPI-4 T13 1153D revision 14", /* 0x0014 */ "ATA/ATAPI-5 T13 1321D revision 1", /* 0x0015 */ "ATA/ATAPI-5 published, ANSI NCITS 340-2000", /* 0x0016 */ "ATA/ATAPI-4 T13 1153D revision 17", /* 0x0017 */ "ATA/ATAPI-6 T13 1410D revision 0", /* 0x0018 */ "ATA/ATAPI-6 T13 1410D revision 3a", /* 0x0019 */ "ATA/ATAPI-7 T13 1532D revision 1", /* 0x001a */ "ATA/ATAPI-6 T13 1410D revision 2", /* 0x001b */ "ATA/ATAPI-6 T13 1410D revision 1", /* 0x001c */ "ATA/ATAPI-7 published, ANSI INCITS 397-2005",/* 0x001d */ "ATA/ATAPI-7 T13 1532D revision 0", /* 0x001e */ "reserved", /* 0x001f */ "reserved", /* 0x0020 */ "ATA/ATAPI-7 T13 1532D revision 4a", /* 0x0021 */ "ATA/ATAPI-6 published, ANSI INCITS 361-2002" /* 0x0022 */};// NOTE ATA/ATAPI-4 REV 4 was the LAST revision where the device// attribute structures were NOT completely vendor specific. So any// disk that is ATA/ATAPI-4 or above can not be trusted to show the// vendor values in sensible format.// Negative values below are because it doesn't support SMARTconst int actual_ver[] = { /* word 81 value: */ 0, /* 0x0000 WARNING: */ 1, /* 0x0001 WARNING: */ 1, /* 0x0002 WARNING: */ 1, /* 0x0003 WARNING: */ 2, /* 0x0004 WARNING: This array */ 2, /* 0x0005 WARNING: corresponds */ -3, /*<== */ /* 0x0006 WARNING: *exactly* */ 2, /* 0x0007 WARNING: to the ATA/ */ -3, /*<== */ /* 0x0008 WARNING: ATAPI version */ 2, /* 0x0009 WARNING: listed in */ 3, /* 0x000a WARNING: the */ 3, /* 0x000b WARNING: minor_str */ 3, /* 0x000c WARNING: array */ 4, /* 0x000d WARNING: above. */ 4, /* 0x000e WARNING: */ 4, /* 0x000f WARNING: If you change */ 4, /* 0x0010 WARNING: that one, */ 4, /* 0x0011 WARNING: change this one */ 4, /* 0x0012 WARNING: too!!! */ 5, /* 0x0013 WARNING: */ 4, /* 0x0014 WARNING: */ 5, /* 0x0015 WARNING: */ 5, /* 0x0016 WARNING: */ 4, /* 0x0017 WARNING: */ 6, /* 0x0018 WARNING: */ 6, /* 0x0019 WARNING: */ 7, /* 0x001a WARNING: */ 6, /* 0x001b WARNING: */ 6, /* 0x001c WARNING: */ 7, /* 0x001d WARNING: */ 7, /* 0x001e WARNING: */ 0, /* 0x001f WARNING: */ 0, /* 0x0020 WARNING: */ 7, /* 0x0021 WARNING: */ 6 /* 0x0022 WARNING: */};// When you add additional items to this list, you should then:// 0 -- update this list// 1 -- modify the following function parse_attribute_def()// 2 -- if needed, modify ataPrintSmartAttribRawValue()// 3 - if needed, modify ataPrintSmartAttribName()// 4 -- add #define PRESET_N_DESCRIPTION at top of knowndrives.c// 5 -- add drive in question into knowndrives[] table in knowndrives.c// 6 -- update smartctl.8// 7 -- update smartd.8// 8 -- do "make smartd.conf.5" to update smartd.conf.5// 9 -- update CHANGELOG fileconst char *vendorattributeargs[] = { // 0 defs[9]=1 "9,minutes", // 1 defs[9]=3 "9,seconds", // 2 defs[9]=2 "9,temp", // 3 defs[220]=1 "220,temp", // 4 defs[*]=253 "N,raw8", // 5 defs[*]=254 "N,raw16", // 6 defs[*]=255 "N,raw48", // 7 defs[200]=1 "200,writeerrorcount", // 8 defs[9]=4 "9,halfminutes", // 9 defs[194]=1 "194,10xCelsius", // 10 defs[194]=2 "194,unknown", // 11 defs[193]=1 "193,loadunload", // 12 defs[201]=1 "201,detectedtacount", // 13 defs[192]=1 "192,emergencyretractcyclect", // 14 defs[198]=1 "198,offlinescanuncsectorct", // NULL should always terminate the array NULL};// This are the meanings of the Self-test failure checkpoint byte.// This is in the self-test log at offset 4 bytes into the self-test// descriptor and in the SMART READ DATA structure at byte offset// 371. These codes are not well documented. The meanings returned by// this routine are used (at least) by Maxtor and IBM. Returns NULL if// not recognized. Currently the maximum length is 15 bytes.const char *SelfTestFailureCodeName(unsigned char which){ switch (which) { case 0: return "Write_Test"; case 1: return "Servo_Basic"; case 2: return "Servo_Random"; case 3: return "G-list_Scan"; case 4: return "Handling_Damage"; case 5: return "Read_Scan"; default: return NULL; }}// This is a utility function for parsing pairs like "9,minutes" or// "220,temp", and putting the correct flag into the attributedefs// array. Returns 1 if problem, 0 if pair has been recongized.int parse_attribute_def(char *pair, unsigned char **defsptr){ int i,j; char temp[32]; unsigned char *defs; // If array does not exist, allocate it if (!*defsptr && !(*defsptr=(unsigned char *)calloc(MAX_ATTRIBUTE_NUM, 1))){ pout("Out of memory in parse_attribute_def\n"); EXIT(1); } defs=*defsptr; // look along list and see if we find the pair for (i=0; vendorattributeargs[i] && strcmp(pair, vendorattributeargs[i]); i++); switch (i) { case 0: // attribute 9 is power on time in minutes defs[9]=1; return 0; case 1: // attribute 9 is power-on-time in seconds defs[9]=3; return 0; case 2: // attribute 9 is temperature in celsius defs[9]=2; return 0; case 3: // attribute 220 is temperature in celsius defs[220]=1; return 0; case 4: // print all attributes in raw 8-bit form for (j=0; j<MAX_ATTRIBUTE_NUM; j++) defs[j]=253; return 0; case 5: // print all attributes in raw 16-bit form for (j=0; j<MAX_ATTRIBUTE_NUM; j++) defs[j]=254; return 0; case 6: // print all attributes in raw 48-bit form for (j=0; j<MAX_ATTRIBUTE_NUM; j++) defs[j]=255; return 0; case 7: // attribute 200 is write error count defs[200]=1; return 0; case 8: // attribute 9 increments once every 30 seconds (power on time // measure) defs[9]=4; return 0; case 9: // attribute 194 is ten times disk temp in Celsius defs[194]=1; return 0; case 10: // attribute 194 is unknown defs[194]=2; return 0; case 11: // Hitachi : Attributes 193 has 2 values : 1 load, 1 normal unload defs[193]=1; return 0; case 12: // Fujitsu defs[201]=1; return 0; case 13: // Fujitsu defs[192]=1; return 0; case 14: // Fujitsu defs[198]=1; return 0; default: // pair not found break; } // At this point, either the pair was not found, or it is of the // form N,uninterpreted, in which case we need to parse N j=sscanf(pair,"%d,%14s", &i, temp); // if no match to pattern, unrecognized if (j!=2 || i<0 || i >255) return 1; // check for recognized strings if (!strcmp(temp, "raw8")) { defs[i]=253; return 0; } // check for recognized strings if (!strcmp(temp, "raw16")) { defs[i]=254; return 0; } // check for recognized strings if (!strcmp(temp, "raw48")) { defs[i]=255; return 0; } // didn't recognize the string return 1;}// Structure used in sorting the array vendorattributeargs[].typedef struct vaa_pair_s { const char *vaa; const char *padded_vaa;} vaa_pair;// Returns a copy of s with all numbers of less than three digits padded with// leading zeros. Returns NULL if there isn't enough memory available. The// memory for the string is dynamically allocated and should be freed by the// caller.char *pad_numbers(const char *s){ char c, *t, *u; const char *r; int i, len, ndigits = 0; // Allocate the maximum possible amount of memory needed. if (!(t = (char *)malloc(strlen(s)*2+2))) return NULL; // Copy the string s to t, padding any numbers of less than three digits // with leading zeros. The string is copied backwards to simplify the code. r = s + strlen(s); u = t; while (( r-- >= s)) { if (isdigit((int)*r)) ndigits++; else if (ndigits > 0) { while (ndigits++ < 3) *u++ = '0'; ndigits = 0; } *u++ = *r; } *u = '\0'; // Reverse the string in t. len = strlen(t); for (i = 0; i < len/2; i++) { c = t[i]; t[i] = t[len-1-i]; t[len-1-i] = c; } return t;}// Comparison function for qsort(). Used by sort_vendorattributeargs().int compare_vaa_pairs(const void *a, const void *b){ vaa_pair *p = (vaa_pair *)a; vaa_pair *q = (vaa_pair *)b; return strcmp(p->padded_vaa, q->padded_vaa);}// Returns a sorted list of vendorattributeargs or NULL if there is not enough// memory available. The memory for the list is allocated dynamically and// should be freed by the caller.// To perform the sort, any numbers in the strings are padded out to three// digits by adding leading zeros. For example,//// "9,minutes" becomes "009,minutes"// "N,raw16" becomes "N,raw016"//// and the original strings are paired with the padded strings. The list of// pairs is then sorted by comparing the padded strings (using strcmp) and the// result is then the list of unpadded strings.//const char **sort_vendorattributeargs(void) { const char **ps, **sorted_list = NULL; vaa_pair *pairs, *pp; int count, i; // Figure out how many strings are in vendorattributeargs[] (not including // the terminating NULL). count = (sizeof vendorattributeargs) / sizeof(char *) - 1; // Construct a list of pairs of strings from vendorattributeargs[] and their // padded equivalents. if (!(pairs = (vaa_pair *)malloc(sizeof(vaa_pair) * count))) goto END; for (ps = vendorattributeargs, pp = pairs; *ps; ps++, pp++) { pp->vaa = *ps; if (!(pp->padded_vaa = pad_numbers(*ps))) goto END; } // Sort the array of vaa_pair structures by comparing the padded strings // using strcmp(). qsort(pairs, count, sizeof(vaa_pair), compare_vaa_pairs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -