root/trunk/smartmontools/knowndrives.cpp @ 2968

Revision 2968, 56.3 KB (checked in by manfred99, 4 years ago)

attributes updates:
- attributes 225, 232 and 233 for Intel X25-E SSD
- non-conflicting attributes extracted from wdidle3.exe

(thanks to Franc Zabkar and Dan Lukes)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * knowndrives.cpp
3 *
4 * Home page of code is: http://smartmontools.sourceforge.net
5 * Address of support mailing list: smartmontools-support@lists.sourceforge.net
6 *
7 * Copyright (C) 2003-9 Philip Williams, Bruce Allen
8 * Copyright (C) 2008-9 Christian Franke <smartmontools-support@lists.sourceforge.net>
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 */
20
21#include "config.h"
22#include "int64.h"
23#include <stdio.h>
24#include "atacmds.h"
25#include "extern.h"
26#include "knowndrives.h"
27#include "utility.h"
28
29#ifdef HAVE_UNISTD_H
30#include <unistd.h>
31#endif
32#ifdef _WIN32
33#include <io.h> // access()
34#endif
35
36#include <stdexcept>
37
38const char *knowndrives_c_cvsid="$Id$"
39ATACMDS_H_CVSID CONFIG_H_CVSID EXTERN_H_CVSID INT64_H_CVSID KNOWNDRIVES_H_CVSID UTILITY_H_CVSID;
40
41#define MODEL_STRING_LENGTH                         40
42#define FIRMWARE_STRING_LENGTH                       8
43#define TABLEPRINTWIDTH                             19
44
45
46/* Table of settings for known drives terminated by an element containing all
47 * zeros.  The drivesettings structure is described in knowndrives.h.  Note
48 * that lookupdrive() will search knowndrives[] from the start to end or
49 * until it finds the first match, so the order in knowndrives[] is important
50 * for distinct entries that could match the same drive. */
51
52// Note that the table just below uses EXTENDED REGULAR EXPRESSIONS.
53// A good on-line reference for these is:
54// http://www.zeus.com/extra/docsystem/docroot/apps/web/docs/modules/access/regex.html
55
56// Starting with CVS version 1.179 of this file, the regular expressions
57// for drive model and firmware must match the full string.  The effect of
58// "^FULLSTRING$" is identical to "FULLSTRING".  The special characters '^'
59// and '$' are no longer required, but still allowed. The form ".*SUBSTRING.*"
60// can be used if substring match is desired.
61
62static const drive_settings builtin_knowndrives[] = {
63// BEGIN drivedb.h (DO NOT DELETE - used by Makefile)
64  { "Apple SSD SM128",
65    "APPLE SSD SM128",
66    "", "", ""
67  },
68  { "Asus-Phison SSD",
69    "ASUS-PHISON SSD",
70    "", "", ""
71  },
72  { "OCZ Vertex SSD",
73    "OCZ-VERTEX.*",
74    "", "", ""
75  },
76  { "Intel X25-E SSD",
77    "SSDSA2SH(032|064)G1.* INTEL",
78    "", "",
79    "-v 225,hostwritescount"
80  },
81  { "Transcend Solid-State Drive",
82    "TS(8|16|32|64|128)GSSD25-(M|S)",
83    "", "", ""
84  },
85  { "Transcend Solid-State Drive V series",
86    "TS(8|16|32|64|128|192)GSSD25S-(M|S)",
87    "", "", ""
88  },
89  { "Marvell SSD SD88SA024BA0 (SUN branded)",
90    "MARVELL SD88SA024BA0 SUN24G 0902M0054V",
91    "", "", ""
92  },
93  { "HP 1TB SATA disk GB1000EAFJL",
94    "GB1000EAFJL",
95    "", "", ""
96  },
97  { "IBM Deskstar 60GXP series",  // ER60A46A firmware
98    "(IBM-|Hitachi )?IC35L0[12346]0AVER07.*",
99    "ER60A46A",
100    "", ""
101  },
102  { "IBM Deskstar 60GXP series",  // All other firmware
103    "(IBM-|Hitachi )?IC35L0[12346]0AVER07.*",
104    "",
105    "IBM Deskstar 60GXP drives may need upgraded SMART firmware.\n"
106    "Please see http://www.geocities.com/dtla_update/index.html#rel and\n"
107    "http://www.ibm.com/pc/support/site.wss/MIGR-42215.html",
108    ""
109  },
110  { "IBM Deskstar 40GV & 75GXP series (A5AA/A6AA firmware)",
111    "(IBM-)?DTLA-30[57]0[123467][05].*",
112    "T[WX][123468AG][OF]A[56]AA",
113    "", ""
114  },
115  { "IBM Deskstar 40GV & 75GXP series (all other firmware)",
116    "(IBM-)?DTLA-30[57]0[123467][05].*",
117    "",
118    "IBM Deskstar 40GV and 75GXP drives may need upgraded SMART firmware.\n"
119    "Please see http://www.geocities.com/dtla_update/ and\n"
120    "http://www.ibm.com/pc/support/site.wss/MIGR-42215.html",
121    ""
122  },
123  { "", // ExcelStor J240, J340, J360, J680, and J880
124    "ExcelStor Technology J(24|34|36|68|88)0",
125    "", "", ""
126  },
127  { "", // Fujitsu M1623TAU
128    "FUJITSU M1623TAU",
129    "",
130    "",
131    "-v 9,seconds"
132  },
133  { "Fujitsu MHG series",
134    "FUJITSU MHG2...ATU?.*",
135    "",
136    "",
137    "-v 9,seconds"
138  },
139  { "Fujitsu MHH series",
140    "FUJITSU MHH2...ATU?.*",
141    "",
142    "",
143    "-v 9,seconds"
144  },
145  { "Fujitsu MHJ series",
146    "FUJITSU MHJ2...ATU?.*",
147    "",
148    "",
149    "-v 9,seconds"
150  },
151  { "Fujitsu MHK series",
152    "FUJITSU MHK2...ATU?.*",
153    "",
154    "",
155    "-v 9,seconds"
156  },
157  { "",  // Fujitsu MHL2300AT
158    "FUJITSU MHL2300AT",
159    "",
160    "This drive's firmware has a harmless Drive Identity Structure\n"
161      "checksum error bug.",
162    "-v 9,seconds"
163  },
164  { "",  // MHM2200AT, MHM2150AT, MHM2100AT, MHM2060AT
165    "FUJITSU MHM2(20|15|10|06)0AT",
166    "",
167    "This drive's firmware has a harmless Drive Identity Structure\n"
168      "checksum error bug.",
169    "-v 9,seconds"
170  },
171  { "Fujitsu MHN series",
172    "FUJITSU MHN2...AT",
173    "",
174    "",
175    "-v 9,seconds"
176  },
177  { "", // Fujitsu MHR2020AT
178    "FUJITSU MHR2020AT",
179    "",
180    "",
181    "-v 9,seconds"
182  },
183  { "", // Fujitsu MHR2040AT
184    "FUJITSU MHR2040AT",
185    "",    // Tested on 40BA
186    "",
187    "-v 9,seconds -v 192,emergencyretractcyclect "
188    "-v 198,offlinescanuncsectorct -v 200,writeerrorcount"
189  },
190  { "Fujitsu MHSxxxxAT family",
191    "FUJITSU MHS20[6432]0AT(  .)?",
192    "",
193    "",
194    "-v 9,seconds -v 192,emergencyretractcyclect "
195    "-v 198,offlinescanuncsectorct -v 200,writeerrorcount "
196    "-v 201,detectedtacount"
197  },
198  { "Fujitsu MHT series",
199    "FUJITSU MHT2...(AH|AS|AT|BH)U?.*",
200    "",
201    "",
202    "-v 9,seconds"
203  },
204  { "Fujitsu MHU series",
205    "FUJITSU MHU2...ATU?.*",
206    "",
207    "",
208    "-v 9,seconds"
209  },
210  { "Fujitsu MHV series",
211    "FUJITSU MHV2...(AH|AS|AT|BH|BS|BT).*",
212    "",
213    "",
214    "-v 9,seconds"
215  },
216  { "Fujitsu MPA..MPG series",
217    "FUJITSU MP[A-G]3...A[HTEV]U?.*",
218    "",
219    "",
220    "-v 9,seconds"
221  },
222  { "Fujitsu MHY2 BH series",
223    "FUJITSU MHY2(04|06|08|10|12|16|20|25)0BH.*",
224    "", "", ""
225  },
226  { "Fujitsu MHW2 BH series",
227    "FUJITSU MHW2(04|06|08|10|12|16)0BH.*",
228    "", "", ""
229  },
230  { "Fujitsu MHW2 BJ series",
231    "FUJITSU MHW2(08|12|16)0BJ.*",
232    "", "", ""
233  },
234  { "Fujitsu MHZ2 BH series",
235    "FUJITSU MHZ2(04|08|12|16|20|25|32)0BH.*",
236    "", "", ""
237  },
238  { "Fujitsu MHZ2 BJ series",
239    "FUJITSU MHZ2(08|12|16|20|25|32)0BJ.*",
240    "",
241    "",
242    "-v 9,minutes"
243  },
244  { "Fujitsu MHZ2 BS series",
245    "FUJITSU MHZ2(12|25)0BS.*",
246    "", "", ""
247  },
248  { "", // Samsung SV4012H (known firmware)
249    "SAMSUNG SV4012H",
250    "RM100-08",
251    "",
252    "-v 9,halfminutes -F samsung"
253  },
254  { "", // Samsung SV4012H (all other firmware)
255    "SAMSUNG SV4012H",
256    "",
257    "May need -F samsung disabled; see manual for details.",
258    "-v 9,halfminutes -F samsung"
259  },
260  { "", // Samsung SV0412H (known firmware)
261    "SAMSUNG SV0412H",
262    "SK100-01",
263    "",
264    "-v 9,halfminutes -v 194,10xCelsius -F samsung"
265  },
266  { "", // Samsung SV0412H (all other firmware)
267    "SAMSUNG SV0412H",
268    "",
269    "May need -F samsung disabled; see manual for details.",
270    "-v 9,halfminutes -v 194,10xCelsius -F samsung"
271  },
272  { "", // Samsung SV1204H (known firmware)
273    "SAMSUNG SV1204H",
274    "RK100-1[3-5]",
275    "",
276    "-v 9,halfminutes -v 194,10xCelsius -F samsung"
277  },
278  { "", // Samsung SV1204H (all other firmware)
279    "SAMSUNG SV1204H",
280    "",
281    "May need -F samsung disabled; see manual for details.",
282    "-v 9,halfminutes -v 194,10xCelsius -F samsung"
283  },
284  { "", // SAMSUNG SV0322A tested with FW JK200-35
285    "SAMSUNG SV0322A",
286    "", "", ""
287  },
288  { "", // SAMSUNG SP40A2H with RR100-07 firmware
289    "SAMSUNG SP40A2H",
290    "RR100-07",
291    "",
292    "-v 9,halfminutes -F samsung"
293  },
294  { "", // SAMSUNG SP80A4H with RT100-06 firmware
295    "SAMSUNG SP80A4H",
296    "RT100-06",
297    "",
298    "-v 9,halfminutes -F samsung"
299  },
300  { "", // SAMSUNG SP8004H with QW100-61 firmware
301    "SAMSUNG SP8004H",
302    "QW100-61",
303    "",
304    "-v 9,halfminutes -F samsung"
305  },
306  { "SAMSUNG SpinPoint F1 DT series", // tested with HD103UJ/1AA01113
307    "SAMSUNG HD(083G|16[12]G|25[12]H|32[12]H|50[12]I|642J|75[23]L|10[23]U)J",
308    "", "", ""
309  },
310  { "SAMSUNG SpinPoint F1 RE series", // tested with HE103UJ/1AA01113
311    "SAMSUNG HE(252H|322H|502I|642J|753L|103U)J",
312    "", "", ""
313  },
314  { "SAMSUNG SpinPoint S250 series", // tested with HD200HJ/KF100-06
315    "SAMSUNG HD(162|200|250)HJ",
316    "", "", ""
317  },
318  { "SAMSUNG SpinPoint T133 series", // tested with HD300LJ/ZT100-12, HD400LJ/ZZ100-14, HD401LJ/ZZ100-15
319    "SAMSUNG HD(250KD|(30[01]|320|40[01])L[DJ])",
320    "", "", ""
321  },
322  { "SAMSUNG SpinPoint T166 series", // tested with HD501LJ/CR100-10
323    "SAMSUNG HD(080G|160H|32[01]K|403L|50[01]L)J",
324    "", "", ""
325  },
326  { "SAMSUNG SpinPoint P120 series", // VF100-37 firmware, tested with SP2514N/VF100-37
327    "SAMSUNG SP(16[01]3|2[05][01]4)[CN]",
328    "VF100-37",
329    "",
330    "-F samsung3"
331  },
332  { "SAMSUNG SpinPoint P120 series", // other firmware, tested with SP2504C/VT100-33
333    "SAMSUNG SP(16[01]3|2[05][01]4)[CN]",
334    "",
335    "May need -F samsung3 enabled; see manual for details.",
336    ""
337  },
338  { "SAMSUNG SpinPoint P80 SD series", // tested with HD160JJ/ZM100-33
339    "SAMSUNG HD(080H|120I|160J)J",
340    "", "", ""
341  },
342  { "SAMSUNG SpinPoint P80 series", // BH100-35 firmware, tested with SP0842N/BH100-35
343    "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]",
344    "BH100-35",
345    "",
346    "-F samsung3"
347  },
348  { "SAMSUNG SpinPoint P80 series", // firmware *-35 or later
349    "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]",
350    ".*-3[5-9]",
351    "May need -F samsung3 enabled; see manual for details.",
352    ""
353  },
354  { "SAMSUNG SpinPoint P80 series", // firmware *-25...34, tested with SP1614C/SW100-25 and -34
355    "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]",
356    ".*-(2[5-9]|3[0-4])",
357    "",
358    "-v 9,halfminutes -v 198,increasing"
359  },
360  { "SAMSUNG SpinPoint P80 series", // firmware *-23...24, tested with
361    // SP0802N/TK100-23,
362    // SP1213N/TL100-23,
363    // SP1604N/TM100-23 and -24
364    "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]",
365    ".*-2[34]",
366    "",
367    "-v 9,halfminutes -F samsung2"
368  },
369  { "SAMSUNG SpinPoint P80 series", // unknown firmware
370    "SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]",
371    "",
372    "May need -F samsung2 or -F samsung3 enabled; see manual for details.",
373    ""
374  },
375/*
376  // TODO: Make the entries below more specific.
377  // These entries produce misleading results, because newer
378  // Samsung disks reuse the version numbers *-NN.
379  { "", // All Samsung drives with '.*-25' firmware
380    "SAMSUNG.*",
381    ".*-25",
382    "May need -F samsung2 disabled; see manual for details.",
383    "-v 9,halfminutes -F samsung2"
384  },
385  { "", // All Samsung drives with '.*-26 or later (currently to -39)' firmware
386    "SAMSUNG.*",
387    ".*-(2[6789]|3[0-9])",
388    "",
389    "-v 9,halfminutes"
390  },
391  { "", // Samsung ALL OTHER DRIVES
392    "SAMSUNG.*",
393    "",
394    "May need -F samsung or -F samsung2 enabled; see manual for details.",
395    ""
396  },
397*/
398  { "Maxtor Fireball 541DX family",
399    "Maxtor 2B0(0[468]|1[05]|20)H1",
400    "",
401    "",
402    "-v 9,minutes -v 194,unknown"
403  },
404  { "Maxtor Fireball 3 family",
405    "Maxtor 2F0[234]0[JL]0",
406    "",
407    "",
408    "-v 9,minutes"
409  },
410  { "Maxtor DiamondMax 1280 ATA family",  // no self-test log, ATA2-Fast
411    "Maxtor 8(1280A2|2160A4|2560A4|3840A6|4000A6|5120A8)",
412    "",
413    "",
414    "-v 9,minutes"
415  },
416  { "Maxtor DiamondMax 2160 Ultra ATA family",
417    "Maxtor 8(2160D2|3228D3|3240D3|4320D4|6480D6|8400D8|8455D8)",
418    "",
419    "",
420    "-v 9,minutes"
421  },
422  { "Maxtor DiamondMax 2880 Ultra ATA family",
423    "Maxtor 9(0510D4|0576D4|0648D5|0720D5|0840D6|0845D6|0864D6|1008D7|1080D8|1152D8)",
424    "",
425    "",
426    "-v 9,minutes"
427  },
428  { "Maxtor DiamondMax 3400 Ultra ATA family",
429    "Maxtor 9(1(360|350|202)D8|1190D7|10[12]0D6|0840D5|06[48]0D4|0510D3|1(350|202)E8|1010E6|0840E5|0640E4)",
430    "",
431    "",
432    "-v 9,minutes"
433  },
434  { "Maxtor DiamondMax D540X-4G family",
435    "Maxtor 4G(120J6|160J[68])",
436    "",
437    "",
438    "-v 9,minutes -v 194,unknown"
439  },
440  { "Maxtor DiamondMax D540X-4K family",
441    "MAXTOR 4K(020H1|040H2|060H3|080H4)",
442    "", "", ""
443  },
444  { "Maxtor DiamondMax Plus D740X family",
445    "MAXTOR 6L0(20[JL]1|40[JL]2|60[JL]3|80[JL]4)",
446    "", "", ""
447  },
448  { "Maxtor DiamondMax Plus 5120 Ultra ATA 33 family",
449    "Maxtor 9(0512D2|0680D3|0750D3|0913D4|1024D4|1360D6|1536D6|1792D7|2048D8)",
450    "",
451    "",
452    "-v 9,minutes"
453  },
454  { "Maxtor DiamondMax Plus 6800 Ultra ATA 66 family",
455    "Maxtor 9(2732U8|2390U7|204[09]U6|1707U5|1366U4|1024U3|0845U3|0683U2)",
456    "",
457    "",
458    "-v 9,minutes"
459  },
460  { "Maxtor DiamondMax D540X-4D",
461    "Maxtor 4D0(20H1|40H2|60H3|80H4)",
462    "",
463    "",
464    "-v 9,minutes -v 194,unknown"
465  },
466  { "Maxtor DiamondMax 16 family",
467    "Maxtor 4(R0[68]0[JL]0|R1[26]0L0|A160J0|R120L4)",
468    "",
469    "",
470    "-v 9,minutes"
471  },
472  { "Maxtor DiamondMax 4320 Ultra ATA family",
473    "Maxtor (91728D8|91512D7|91303D6|91080D5|90845D4|90645D3|90648D[34]|90432D2)",
474    "",
475    "",
476    "-v 9,minutes"
477  },
478  { "Maxtor DiamondMax 17 VL family",
479    "Maxtor 9(0431U1|0641U2|0871U2|1301U3|1741U4)",
480    "",
481    "",
482    "-v 9,minutes"
483  },
484  { "Maxtor DiamondMax 20 VL family",
485    "Maxtor (94091U8|93071U6|92561U5|92041U4|91731U4|91531U3|91361U3|91021U2|90841U2|90651U2)",
486    "",
487    "",
488    "-v 9,minutes"
489  },
490  { "Maxtor DiamondMax VL 30 family",  // U: ATA66, H: ATA100
491    "Maxtor (33073U4|32049U3|31536U2|30768U1|33073H4|32305H3|31536H2|30768H1)",
492    "",
493    "",
494    "-v 9,minutes"
495  },
496  { "Maxtor DiamondMax 36 family",
497    "Maxtor (93652U8|92739U6|91826U4|91369U3|90913U2|90845U2|90435U1)",
498    "",
499    "",
500    "-v 9,minutes"
501  },
502  { "Maxtor DiamondMax 40 ATA 66 series",
503    "Maxtor 9(0684U2|1024U2|1362U3|1536U3|2049U4|2562U5|3073U6|4098U8)",
504    "",
505    "",
506    "-v 9,minutes"
507  },
508  { "Maxtor DiamondMax Plus 40 series (Ultra ATA 66 and Ultra ATA 100)",
509    "Maxtor (54098[UH]8|53073[UH]6|52732[UH]6|52049[UH]4|51536[UH]3|51369[UH]3|51024[UH]2)",
510    "",
511    "",
512    "-v 9,minutes"
513  },
514  { "Maxtor DiamondMax 40 VL Ultra ATA 100 series",
515    "Maxtor 3(1024H1|1535H2|2049H2|3073H3|4098H4)( B)?",
516    "",
517    "",
518    "-v 9,minutes"
519  },
520  { "Maxtor DiamondMax Plus 45 Ulta ATA 100 family",
521    "Maxtor 5(4610H6|4098H6|3073H4|2049H3|1536H2|1369H2|1023H2)",
522    "",
523    "",
524    "-v 9,minutes"
525  },
526  { "Maxtor DiamondMax 60 ATA 66 family",
527    "Maxtor 9(1023U2|1536U2|2049U3|2305U3|3073U4|4610U6|6147U8)",
528    "",
529    "",
530    "-v 9,minutes"
531  },
532  { "Maxtor DiamondMax 60 ATA 100 family",
533    "Maxtor 9(1023H2|1536H2|2049H3|2305H3|3073H4|4098H6|4610H6|6147H8)",
534    "",
535    "",
536    "-v 9,minutes"
537  },
538  { "Maxtor DiamondMax Plus 60 family",
539    "Maxtor 5T0(60H6|40H4|30H3|20H2|10H1)",
540    "",
541    "",
542    "-v 9,minutes"
543  },
544  { "Maxtor DiamondMax 80 family",
545    "Maxtor (98196H8|96147H6)",
546    "",
547    "",
548    "-v 9,minutes"
549  },
550  { "Maxtor DiamondMax 536DX family",
551    "Maxtor 4W(100H6|080H6|060H4|040H3|030H2)",
552    "",
553    "",
554    "-v 9,minutes"
555  },
556  { "Maxtor DiamondMax Plus 8 family",
557    "Maxtor 6(E0[234]|K04)0L0",
558    "",
559    "",
560    "-v 9,minutes"
561  },
562  { "Maxtor DiamondMax 10 family (ATA/133 and SATA/150)",
563    "Maxtor 6(B(30|25|20|16|12|10|08)0[MPRS]|L(080[MLP]|(100|120)[MP]|160[MP]|200[MPRS]|250[RS]|300[RS]))0",
564    "",
565    "",
566    "-v 9,minutes"
567  },
568  { "Maxtor DiamondMax 10 family (SATA/300)",
569    "Maxtor 6V(080E|160E|200E|250F|300F|320F)0",
570    "", "", ""
571  },
572  { "Maxtor DiamondMax Plus 9 family",
573    "Maxtor 6Y((060|080|120|160)L0|(060|080|120|160|200|250)P0|(060|080|120|160|200|250)M0)",
574    "",
575    "",
576    "-v 9,minutes"
577  },
578  { "Maxtor DiamondMax 11 family",
579    "Maxtor 6H[45]00[FR]0",
580    "", "", ""
581  },
582  { "Maxtor DiamondMax 17",
583    "Maxtor 6G(080L|160[PE])0",
584    "", "", ""
585  },
586  { "Seagate Maxtor DiamondMax 20",
587    "MAXTOR STM3(40|80|160)[28]1[12]0?AS?",
588    "", "", ""
589  },
590  { "Seagate Maxtor DiamondMax 21",
591    "MAXTOR STM3(160215|(250|320)820|320620|500630)AS?",
592    "", "", ""
593  },
594  { "Seagate Maxtor DiamondMax 22", // fixed firmware
595    "(MAXTOR )?STM3(500320|750330|1000340)AS?",
596    "MX1A", // http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207969
597    "", ""
598  },
599  { "Seagate Maxtor DiamondMax 22", // fixed firmware
600    "(MAXTOR )?STM3(160813|320614|640323|1000334)AS?",
601    "MX1B", // http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207975
602    "", ""
603  },
604  { "Seagate Maxtor DiamondMax 22", // buggy firmware
605    "(MAXTOR )?STM3(500320|750330|1000340)AS?",
606    "MX15",
607    "There are known problems with these drives,\n"
608    "AND THIS FIRMWARE VERSION IS AFFECTED,\n"
609    "see the following Seagate web pages:\n"
610    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207931\n"
611    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207969",
612    ""
613  },
614  { "Seagate Maxtor DiamondMax 22", // unknown firmware
615    "(MAXTOR )?STM3(160813|32061[34]|500320|640323|750330|10003(34|40))AS?",
616    "",
617    "There are known problems with these drives,\n"
618    "see the following Seagate web pages:\n"
619    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207931\n"
620    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207969\n"
621    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207975",
622    ""
623  },
624  { "Seagate Maxtor DiamondMax 23",
625    "STM3((160|250)31|(320|500)41|(750|1000)52)8AS?",
626    "", "", ""
627  },
628  { "Maxtor MaXLine Plus II",
629    "Maxtor 7Y250[PM]0",
630    "",
631    "",
632    "-v 9,minutes"
633  },
634  { "Maxtor MaXLine II family",
635    "Maxtor [45]A(25|30|32)0[JN]0",
636    "",
637    "",
638    "-v 9,minutes"
639  },
640  { "Maxtor MaXLine III family (ATA/133 and SATA/150)",
641    "Maxtor 7L(25|30)0[SR]0",
642    "",
643    "",
644    "-v 9,minutes"
645  },
646  { "Maxtor MaXLine III family (SATA/300)",
647    "Maxtor 7V(25|30)0F0",
648    "", "", ""
649  },
650  { "Maxtor MaXLine Pro 500 family",  // There is also a 7H500R0 model, but I
651    "Maxtor 7H500F0",               // haven't added it because I suspect
652    "",                               // it might need vendoropts_9_minutes
653    "", ""                            // and nobody has submitted a report yet
654  },
655  { "", // HITACHI_DK14FA-20B
656    "HITACHI_DK14FA-20B",
657    "",
658    "",
659    "-v 9,minutes -v 193,loadunload"
660  },
661  { "HITACHI Travelstar DK23XX/DK23XXB series",
662    "HITACHI_DK23..-..B?",
663    "",
664    "",
665    "-v 9,minutes -v 193,loadunload"
666  },
667  { "Hitachi Endurastar J4K20/N4K20 (formerly DK23FA-20J)",
668    "(HITACHI_DK23FA-20J|HTA422020F9AT[JN]0)",
669    "",
670    "",
671    "-v 9,minutes -v 193,loadunload"
672  },
673  { "Hitachi Endurastar J4K30/N4K30",
674    "HE[JN]4230[23]0F9AT00",
675    "",
676    "",
677    "-v 9,minutes -v 193,loadunload"
678  },
679  { "Hitachi Travelstar C4K60 family",  // 1.8" slim drive
680    "HTC4260[23]0G5CE00|HTC4260[56]0G8CE00",
681    "",
682    "",
683    "-v 9,minutes -v 193,loadunload"
684  },
685  { "IBM Travelstar 4GT family",
686    "IBM-DTCA-2(324|409)0",
687    "", "", ""
688  },
689  { "IBM Travelstar 6GN family",
690    "IBM-DBCA-20(324|486|648)0",
691    "", "", ""
692  },
693  { "IBM Travelstar 25GS, 18GT, and 12GN family",
694    "IBM-DARA-2(25|18|15|12|09|06)000",
695    "", "", ""
696  },
697  { "IBM Travelstar 14GS",
698    "IBM-DCYA-214000",
699    "", "", ""
700  },
701  { "IBM Travelstar 4LP",
702    "IBM-DTNA-2(180|216)0",
703    "", "", ""
704  },
705  { "IBM Travelstar 48GH, 30GN, and 15GN family",
706    "(IBM-|Hitachi )?IC25(T048ATDA05|N0(30|20|15|12|10|07|06|05)ATDA04)-.",
707    "", "", ""
708  },
709  { "IBM Travelstar 32GH, 30GT, and 20GN family",
710    "IBM-DJSA-2(32|30|20|10|05)",
711    "", "", ""
712  },
713  { "IBM Travelstar 4GN family",
714    "IBM-DKLA-2(216|324|432)0",
715    "", "", ""
716  },
717  { "IBM/Hitachi Travelstar 60GH and 40GN family",
718    "(IBM-|Hitachi )?IC25(T060ATC[SX]05|N0[4321]0ATC[SX]04)-.",
719    "", "", ""
720  },
721  { "IBM/Hitachi Travelstar 40GNX family",
722    "(IBM-|Hitachi )?IC25N0[42]0ATC[SX]05-.",
723    "", "", ""
724  },
725  { "Hitachi Travelstar 80GN family",
726    "(Hitachi )?IC25N0[23468]0ATMR04-.",
727    "", "", ""
728  },
729  { "Hitachi Travelstar 4K40",
730    "(Hitachi )?HTS4240[234]0M9AT00",
731    "", "", ""
732  },
733  { "Hitachi Travelstar 4K120",
734    "(Hitachi )?(HTS4212(60|80|10|12)H9AT00|HTS421260G9AT00)",
735    "", "", ""
736  },
737  { "Hitachi Travelstar 5K80 family",
738    "(Hitachi )?HTS5480[8642]0M9AT00",
739    "", "", ""
740  },
741  { "Hitachi Travelstar 5K100 series",
742    "(Hitachi )?HTS5410[1864]0G9(AT|SA)00",
743    "", "", ""
744  },
745  { "Hitachi Travelstar E5K100 series",
746    "(Hitachi )?HTE541040G9(AT|SA)00",
747    "", "", ""
748  },
749  { "Hitachi Travelstar 5K120",
750    "(Hitachi )?HTS5412(60|80|10|12)H9(AT|SA)00",
751    "", "", ""
752  },
753  { "Hitachi Travelstar 5K160 series",
754    "(Hitachi |HITACHI )?HTS5416([468]0|1[26])J9(AT|SA)00",
755    "", "", ""
756  },
757  { "Hitachi Travelstar E5K160 series",
758    "(Hitachi )?HTE5416(12|16|60|80)J9(AT|SA)00",
759    "", "", ""
760  },
761  { "Hitachi Travelstar 5K250 series",
762    "(Hitachi |HITACHI )?HTS5425(80|12|16|20|25)K9(A3|SA)00",
763    "", "", ""
764  },
765  { "Hitachi Travelstar 7K60",
766    "(Hitachi )?HTS726060M9AT00",
767    "", "", ""
768  },
769  { "Hitachi Travelstar E7K60",
770    "(Hitachi )?HTE7260[46]0M9AT00",
771    "", "", ""
772  },
773  { "Hitachi Travelstar 7K100",
774    "(Hitachi )?HTS7210[168]0G9(AT|SA)00",
775    "", "", ""
776  },
777  { "Hitachi Travelstar E7K100",
778    "(Hitachi )?HTE7210[168]0G9(AT|SA)00",
779    "", "", ""
780  },
781  { "Hitachi Travelstar 7K200",
782    "(Hitachi )?HTS7220(80|10|12|16|20)K9(A3|SA)00",
783    "", "", ""
784  },
785  { "IBM Deskstar 14GXP and 16GP series",
786    "IBM-DTTA-3(7101|7129|7144|5032|5043|5064|5084|5101|5129|5168)0",
787    "", "", ""
788  },
789  { "IBM Deskstar 25GP and 22GXP family",
790    "IBM-DJNA-3(5(101|152|203|250)|7(091|135|180|220))0",
791    "", "", ""
792  },
793  { "IBM Deskstar 37GP and 34GXP family",
794    "IBM-DPTA-3(5(375|300|225|150)|7(342|273|205|136))0",
795    "", "", ""
796  },
797  { "IBM/Hitachi Deskstar 120GXP family",
798    "(IBM-)?IC35L((020|040|060|080|120)AVVA|0[24]0AVVN)07-[01]",
799    "", "", ""
800  },
801  { "IBM/Hitachi Deskstar GXP-180 family",
802    "(IBM-)?IC35L(030|060|090|120|180)AVV207-[01]",
803    "", "", ""
804  },
805  { "Hitachi Deskstar 7K80 series",
806    "(Hitachi )?HDS7280([48]0PLAT20|(40)?PLA320|80PLA380).*",
807    "", "", ""
808  },
809  { "Hitachi Deskstar 7K160",
810    "(Hitachi )?HDS7216(80|16)PLA[3T]80.*",
811    "", "", ""
812  },
813  { "Hitachi Deskstar 7K250 series",
814    "(Hitachi )?HDS7225((40|80|12|16)VLAT20|(12|16|25)VLAT80|(80|12|16|25)VLSA80)",
815    "", "", ""
816  },
817  { "Hitachi Deskstar 7K250 (SUN branded)",
818    "HITACHI HDS7225SBSUN250G.*",
819    "", "", ""
820  },
821  { "Hitachi Deskstar T7K250 series",
822    "(Hitachi )?HDT7225((25|20|16)DLA(T80|380))",
823    "", "", ""
824  },
825  { "Hitachi Deskstar 7K400 series",
826    "(Hitachi )?HDS724040KL(AT|SA)80",
827    "", "", ""
828  },
829  { "Hitachi Deskstar 7K500 series",
830    "(Hitachi )?HDS725050KLA(360|T80)",
831    "", "", ""
832  },
833  { "Hitachi Deskstar P7K500 series",
834    "(Hitachi )?HDP7250(16|25|32|40|50)GLA(36|38|T8)0",
835    "", "", ""
836  },
837  { "Hitachi Deskstar T7K500",
838    "(Hitachi )?HDT7250(25|32|40|50)VLA(360|380|T80)",
839    "", "", ""
840  },
841  { "Hitachi Deskstar 7K1000",
842    "(Hitachi )?HDS7210(50|75|10)KLA330",
843    "", "", ""
844  },
845  { "Hitachi Deskstar 7K1000.B",
846    "(Hitachi )?HDT7210((16|25)SLA380|(32|50|64|75|10)SLA360)",
847    "", "", ""
848  },
849  { "Hitachi Ultrastar 7K1000",
850    "(Hitachi )?HUA7210(50|75|10)KLA330",
851    "", "", ""
852  },
853  { "Toshiba 2.5\" HDD series (10-20 GB)",
854    "TOSHIBA MK(101[67]GAP|15[67]GAP|20(1[678]GAP|(18|23)GAS))",
855    "", "", ""
856  },
857  { "Toshiba 2.5\" HDD series (30-60 GB)",
858    "TOSHIBA MK((6034|4032)GSX|(6034|4032)GAX|(6026|4026|4019|3019)GAXB?|(6025|6021|4025|4021|4018|3025|3021|3018)GAS|(4036|3029)GACE?|(4018|3017)GAP)",
859    "", "", ""
860  },
861  { "Toshiba 2.5\" HDD series (80 GB and above)",
862    "TOSHIBA MK(80(25GAS|26GAX|32GAX|32GSX)|10(31GAS|32GAX)|12(33GAS|34G[AS]X)|2035GSS)",
863    "", "", ""
864  },
865  { "Toshiba 2.5\" HDD MK..52GSX series",
866    "TOSHIBA MK(80|12|16|25|32)52GSX",
867    "", "", ""
868  },
869  { "Toshiba 1.8\" HDD series",
870    "TOSHIBA MK[23468]00[4-9]GA[HL]",
871    "", "", ""
872  },
873  { "", // TOSHIBA MK6022GAX
874    "TOSHIBA MK6022GAX",
875    "", "", ""
876  },
877  { "", // TOSHIBA MK6409MAV
878    "TOSHIBA MK6409MAV",
879    "", "", ""
880  },
881  { "Toshiba MKx019GAXB (SUN branded)",
882    "TOS MK[34]019GAXB SUN[34]0G",
883    "", "", ""
884  },
885  { "Seagate Momentus family",
886    "ST9(20|28|40|48)11A",
887    "", "", ""
888  },
889  { "Seagate Momentus 42 family",
890    "ST9(2014|3015|4019)A",
891    "", "", ""
892  },
893  { "Seagate Momentus 4200.2 series",
894    "ST9(100822|808210|60821|50212|402113|30219)A",
895    "", "", ""
896  },
897  { "Seagate Momentus 5400.2 series",
898    "ST9(808211|60822|408114|308110|120821|10082[34]|8823|6812|4813|3811)AS?",
899    "", "", ""
900  },
901  { "Seagate Momentus 5400.3 series",
902    "ST9(4081[45]|6081[35]|8081[15]|100828|120822|160821)AS?",
903    "", "", ""
904  },
905  { "Seagate Momentus 5400.3 ED series",
906    "ST9(4081[45]|6081[35]|8081[15]|100828|120822|160821)AB",
907    "", "", ""
908  },
909  { "Seagate Momentus 5400.4 series",
910    "ST9(120817|(160|200|250)827)AS",
911    "", "", ""
912  },
913  { "Seagate Momentus 5400.5 series",
914    "ST9((80|120|160)310|(250|320)320)AS",
915    "", "", ""
916  },
917  { "Seagate Momentus 5400.6 series",
918    "ST9((12|25)0315AS|500325)ASG?",
919    "", "", ""
920  },
921  { "Seagate Momentus 5400 PSD series", // Hybrid drives
922    "ST9(808212|(120|160)8220)AS",
923    "", "", ""
924  },
925  { "Seagate Momentus 7200.1 series",
926    "ST9(10021|80825|6023|4015)AS?",
927    "", "", ""
928  },
929  { "Seagate Momentus 7200.2 series",
930    "ST9(80813|100821|120823|160823|200420)ASG?",
931    "", "", ""
932  },
933  { "Seagate Momentus 7200.3 series",
934    "ST9((80|120|160)411|(250|320)421)ASG?",
935    "", "", ""
936  },
937  { "Seagate Momentus 7200.4 series",
938    "ST9(160412|250410|320423|500420)ASG?",
939    "", "", ""
940  },
941  { "Seagate Medalist 1010, 1721, 2120, 3230 and 4340",  // ATA2, with -t permissive
942    "ST3(1010|1721|2120|3230|4340)A",
943    "", "", ""
944  },
945  { "Seagate Medalist 2110, 3221, 4321, 6531, and 8641",
946    "ST3(2110|3221|4321|6531|8641)A",
947    "", "", ""
948  },
949  { "Seagate U Series X family",
950    "ST3(10014A(CE)?|20014A)",
951    "", "", ""
952  },
953  { "Seagate U8 family",
954    "ST3(4313|6811|8410|13021|17221)A",
955    "", "", ""
956  },
957  { "Seagate U7 family",
958    "ST3(30012|40012|60012|80022|120020)A",
959    "", "", ""
960  },
961  { "Seagate U Series 6 family",
962    "ST3(8002|6002|4081|3061|2041)0A",
963    "", "", ""
964  },
965  { "Seagate U Series 5 family",
966    "ST3(40823|30621|20413|15311|10211)A",
967    "", "", ""
968  },
969  { "Seagate U4 family",
970    "ST3(2112|4311|6421|8421)A",
971    "", "", ""
972  },
973  { "Seagate U8 family",
974    "ST3(8410|4313|17221|13021)A",
975    "", "", ""
976  },
977  { "Seagate U10 family",
978    "ST3(20423|15323|10212)A",
979    "", "", ""
980  },
981  { "Seagate Barracuda ATA family",
982    "ST3(2804|2724|2043|1362|1022|681)0A",
983    "", "", ""
984  },
985  { "Seagate Barracuda ATA II family",
986    "ST3(3063|2042|1532|1021)0A",
987    "", "", ""
988  },
989  { "Seagate Barracuda ATA III family",
990    "ST3(40824|30620|20414|15310|10215)A",
991    "", "", ""
992  },
993  { "Seagate Barracuda ATA IV family",
994    "ST3(20011|30011|40016|60021|80021)A",
995    "", "", ""
996  },
997  { "Seagate Barracuda ATA V family",
998    "ST3(12002(3A|4A|9A|3AS)|800(23A|15A|23AS)|60(015A|210A)|40017A)",
999    "", "", ""
1000  },
1001  { "Seagate Barracuda 5400.1",
1002    "ST340015A",
1003    "", "", ""
1004  },
1005  { "Seagate Barracuda 7200.7 and 7200.7 Plus family",
1006    "ST3(200021A|200822AS?|16002[13]AS?|12002[26]AS?|1[26]082[78]AS|8001[13]AS?|8081[79]AS|60014A|40111AS|40014AS?)",
1007    "", "", ""
1008  },
1009  { "Seagate Barracuda 7200.8 family",
1010    "ST3(400[68]32|300[68]31|250[68]23|200826)AS?",
1011    "", "", ""
1012  },
1013  { "Seagate Barracuda 7200.9 family",
1014    "ST3(402111?|80[28]110?|120[28]1[0134]|160[28]1[012]|200827|250[68]24|300[68]22|(320|400)[68]33|500[68](32|41))AS?.*",
1015    "", "", ""
1016  },
1017  { "Seagate Barracuda 7200.10 family",
1018    "ST3((80|160)[28]15|200820|250[34]10|(250|300|320|400)[68]20|500[68]30|750[68]40)AS?",
1019    "", "", ""
1020  },
1021  { "Seagate Barracuda 7200.11 family", // unaffected firmware
1022    "ST3(160813|320[68]13|500[368]20|640[36]23|640[35]30|750[36]30|1000(333|[36]40)|1500341)AS?",
1023    "CC.?.?", // http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207957
1024    "", ""
1025  },
1026  { "Seagate Barracuda 7200.11 family", // fixed firmware
1027    "ST3(500[368]20|750[36]30|1000340)AS?",
1028    "SD1A", // http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207951
1029    "", ""
1030  },
1031  { "Seagate Barracuda 7200.11 family", // fixed firmware
1032    "ST3(160813|320[68]13|640[36]23|1000333|1500341)AS?",
1033    "SD[12]B", // http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207957
1034    "", ""
1035  },
1036  { "Seagate Barracuda 7200.11 family", // buggy firmware
1037    "ST3(500[368]20|640[35]30|750[36]30|1000340)AS?",
1038    "(AD14|SD1[5-9])",
1039    "There are known problems with these drives,\n"
1040    "AND THIS FIRMWARE VERSION IS AFFECTED,\n"
1041    "see the following Seagate web pages:\n"
1042    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207931\n"
1043    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207951",
1044    ""
1045  },
1046  { "Seagate Barracuda 7200.11 family", // unknown firmware
1047    "ST3(160813|320[68]13|500[368]20|640[36]23|640[35]30|750[36]30|1000(333|[36]40)|1500341)AS?",
1048    "",
1049    "There are known problems with these drives,\n"
1050    "see the following Seagate web pages:\n"
1051    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207931\n"
1052    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207951\n"
1053    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207957",
1054    ""
1055  },
1056  { "Seagate Barracuda 7200.12 family",
1057    "ST3((160|250)318|(320|500)418|500410|(750|1000)528)AS",
1058    "", "", ""
1059  },
1060  { "Seagate Barracuda ES",
1061    "ST3(250[68]2|32062|40062|50063|75064)0NS",
1062    "", "", ""
1063  },
1064  { "Seagate Barracuda ES.2", // fixed firmware
1065    "ST3(25031|50032|75033|100034)0NS",
1066    "SN[01]6", // http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207963
1067    "", ""
1068  },
1069  { "Seagate Barracuda ES.2", // unknown firmware
1070    "ST3(25031|50032|75033|100034)0NS",
1071    "",
1072    "There are known problems with these drives,\n"
1073    "see the following Seagate web pages:\n"
1074    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207931\n"
1075    "http://seagate.custkb.com/seagate/crm/selfservice/search.jsp?DocId=207963",
1076    ""
1077  },
1078  { "Seagate Medalist 17240, 13030, 10231, 8420, and 4310",
1079    "ST3(17240|13030|10231|8420|4310)A",
1080    "", "", ""
1081  },
1082  { "Seagate Medalist 17242, 13032, 10232, 8422, and 4312",
1083    "ST3(1724|1303|1023|842|431)2A",
1084    "", "", ""
1085  },
1086  { "Seagate NL35 family",
1087    "ST3(250623|250823|400632|400832|250824|250624|400633|400833|500641|500841)NS",
1088    "", "", ""
1089  },
1090  { "Seagate SV35.2 Series",
1091    "ST3(160815|250820|320620|500630|750640)(A|S)V",
1092    "", "", ""
1093  },
1094  { "Seagate DB35.3 Series",
1095    "ST3(750640SCE|((80|160)215|(250|320|400)820|500830|750840)(A|S)CE)",
1096    "", "", ""
1097  },
1098  { "Western Digital Protege",
1099  /* Western Digital drives with this comment all appear to use Attribute 9 in
1100   * a  non-standard manner.  These entries may need to be updated when it
1101   * is understood exactly how Attribute 9 should be interpreted.
1102   * UPDATE: this is probably explained by the WD firmware bug described in the
1103   * smartmontools FAQ */
1104    "WDC WD([2468]00E|1[26]00A)B-.*",
1105    "", "", ""
1106  },
1107  { "Western Digital Caviar family",
1108  /* Western Digital drives with this comment all appear to use Attribute 9 in
1109   * a  non-standard manner.  These entries may need to be updated when it
1110   * is understood exactly how Attribute 9 should be interpreted.
1111   * UPDATE: this is probably explained by the WD firmware bug described in the
1112   * smartmontools FAQ */
1113    "WDC WD(2|3|4|6|8|10|12|16|18|20|25)00BB-.*",
1114    "", "", ""
1115  },
1116  { "Western Digital Caviar WDxxxAB series",
1117  /* Western Digital drives with this comment all appear to use Attribute 9 in
1118   * a  non-standard manner.  These entries may need to be updated when it
1119   * is understood exactly how Attribute 9 should be interpreted.
1120   * UPDATE: this is probably explained by the WD firmware bug described in the
1121   * smartmontools FAQ */
1122    "WDC WD(3|4|6|8|25)00AB-.*",
1123    "", "", ""
1124  },
1125  { "Western Digital Caviar WDxxxAA series",
1126  /* Western Digital drives with this comment all appear to use Attribute 9 in
1127   * a  non-standard manner.  These entries may need to be updated when it
1128   * is understood exactly how Attribute 9 should be interpreted.
1129   * UPDATE: this is probably explained by the WD firmware bug described in the
1130   * smartmontools FAQ */
1131    "WDC WD...?AA(-.*)?",
1132    "", "", ""
1133  },
1134  { "Western Digital Caviar WDxxxBA series",
1135  /* Western Digital drives with this comment all appear to use Attribute 9 in
1136   * a  non-standard manner.  These entries may need to be updated when it
1137   * is understood exactly how Attribute 9 should be interpreted.
1138   * UPDATE: this is probably explained by the WD firmware bug described in the
1139   * smartmontools FAQ */
1140    "WDC WD...BA",
1141    "", "", ""
1142  },
1143  { "Western Digital Caviar AC series", // add only 5400rpm/7200rpm (ata33 and faster)
1144    "WDC AC((116|121|125|225|132|232)|([1-4][4-9][0-9])|([1-4][0-9][0-9][0-9]))00[A-Z]?.*",
1145    "", "", ""
1146  },
1147  { "Western Digital Caviar SE family",
1148  /* Western Digital drives with this comment all appear to use Attribute 9 in
1149   * a  non-standard manner.  These entries may need to be updated when it
1150   * is understood exactly how Attribute 9 should be interpreted.
1151   * UPDATE: this is probably explained by the WD firmware bug described in the
1152   * smartmontools FAQ
1153   * UPDATE 2: this does not apply to more recent models, at least WD3200AAJB */
1154    "WDC WD(4|6|8|10|12|16|18|20|25|30|32|40|50)00(JB|PB)-.*",
1155    "", "", ""
1156  },
1157  { "Western Digital Caviar Blue EIDE family",  // WD Caviar SE EIDE family
1158    /* not completely accurate: at least also WD800JB, WD(4|8|20|25)00BB sold as Caviar Blue */
1159    "WDC WD(16|25|32|40|50)00AAJB-.*",
1160    "", "", ""
1161  },
1162  { "Western Digital Caviar Blue EIDE family",  // WD Caviar SE16 EIDE family
1163    "WDC WD(25|32|40|50)00AAKB-.*",
1164    "", "", ""
1165  },
1166  { "Western Digital RE EIDE family",
1167    "WDC WD(12|16|25|32)00SB-.*",
1168    "", "", ""
1169  },
1170  { "Western Digital Caviar Serial ATA family",
1171    "WDC WD(4|8|20|32)00BD-.*",
1172    "", "", ""
1173  },
1174  { "Western Digital Caviar SE Serial ATA family",
1175    "WDC WD(4|8|12|16|20|25|32|40)00(JD|KD|PD)-.*",
1176    "", "", ""
1177  },
1178  { "Western Digital Caviar SE Serial ATA family",
1179    "WDC WD(8|12|16|20|25|30|32|40|50)00JS-.*",
1180    "", "", ""
1181  },
1182  { "Western Digital Caviar SE16 Serial ATA family",
1183    "WDC WD(16|20|25|32|40|50|75)00KS-.*",
1184    "", "", ""
1185  },
1186  { "Western Digital Caviar Blue Serial ATA family",  // WD Caviar SE Serial ATA family
1187    /* not completely accurate: at least also WD800BD, (4|8)00JD sold as Caviar Blue */
1188    "WDC WD((8|12|16|25|32)00AABS|(12|16|25|32|40|50)00AAJS)-.*",
1189    "", "", ""
1190  },
1191  { "Western Digital Caviar Blue Serial ATA family",  // WD Caviar SE16 Serial ATA family
1192    "WDC WD(16|20|25|32|40|50|64|75)00AAKS-.*",
1193    "", "", ""
1194  },
1195  { "Western Digital RE Serial ATA family",
1196    "WDC WD(12|16|25|32)00(SD|YD|YS)-.*",
1197    "", "", ""
1198  },
1199  { "Western Digital RE2 Serial ATA family",
1200    "WDC WD((40|50|75)00(YR|YS|AYYS)|(16|32|40|50)0[01]ABYS)-.*",
1201    "", "", ""
1202  },
1203  { "Western Digital RE2-GP family",
1204    "WDC WD(5000AB|7500AY|1000FY)PS-.*",
1205    "", "", ""
1206  },
1207  { "Western Digital RE3 Serial ATA family",
1208    "WDC WD((25|32|50)02A|(75|10)02F)BYS-.*",
1209    "", "", ""
1210  },
1211  { "Western Digital Caviar Green family",
1212    "WDC WD((50|64|75)00AA(C|V)S|(50|75)00AADS|10EA(C|V)S|(10|15|20)EADS)-.*",
1213    "", "", ""
1214  },
1215  { "Western Digital Caviar Black family",
1216    "WDC WD((500|640|750)1AA|1001FA)LS-.*",
1217    "", "", ""
1218  },
1219  { "Western Digital AV ATA family",
1220    "WDC WD(8|16|50)00AV(B|J)B-.*",
1221    "", "", ""
1222  },
1223  { "Western Digital AV-GP family",
1224    "WDC WD((16|25|32|50|64|75)00AVVS|(50|75)00AVCS|10EVVS|(10|20)EVCS|WD(10|15|20)EVDS)-.*",
1225    "", "", ""
1226  },
1227  { "Western Digital Raptor family",
1228    "WDC WD((360|740|800)GD|(360|740|1500)ADF[DS])-.*",
1229    "", "", ""
1230  },
1231  { "Western Digital Raptor X",
1232    "WDC WD1500AHFD-.*",
1233    "", "", ""
1234  },
1235  { "Western Digital VelociRaptor family",
1236    "WDC WD((1500|3000)B|3000G)LFS-.*",
1237    "", "", ""
1238  },
1239  { "Western Digital Scorpio EIDE family",
1240    "WDC WD(4|6|8|10|12|16)00(UE|VE)-.*",
1241    "", "", ""
1242  },
1243  { "Western Digital Scorpio Blue EIDE family",
1244    "WDC WD(4|6|8|10|12|16|25)00BEVE-.*",
1245    "", "", ""
1246  },
1247  { "Western Digital Scorpio Serial ATA family",
1248    "WDC WD(4|6|8|10|12|16|25)00BEAS-.*",
1249    "", "", ""
1250  },
1251  { "Western Digital Scorpio Blue Serial ATA family",
1252    "WDC WD((4|6|8|10|12|16|25)00BEVS|(8|12|16|25|32|40|50)00BEVT)-.*",
1253    "", "", ""
1254  },
1255  { "Western Digital Scorpio Black Serial ATA family",
1256    "WDC WD(8|12|16|25|32)00B[EJ]KT-.*",
1257    "", "", ""
1258  },
1259  { "Western Digital MyPassport Essential hard drive (USB interface)",
1260    "WDC WD3200BMVU-.*",
1261    "", "", ""
1262  },
1263  { "Quantum Bigfoot series",
1264    "QUANTUM BIGFOOT TS10.0A",
1265    "", "", ""
1266  },
1267  { "Quantum Fireball lct15 series",
1268    "QUANTUM FIREBALLlct15 ([123]0|22)",
1269    "", "", ""
1270  },
1271  { "Quantum Fireball lct20 series",
1272    "QUANTUM FIREBALLlct20 [234]0",
1273    "", "", ""
1274  },
1275  { "Quantum Fireball CX series", 
1276    "QUANTUM FIREBALL CX10.2A",
1277    "", "", ""
1278  },
1279  { "Quantum Fireball CR series",
1280    "QUANTUM FIREBALL CR(4.3|6.4|8.4|13.0)A",
1281    "", "", ""
1282  },
1283  { "Quantum Fireball EX series",
1284    "QUANTUM FIREBALL EX(3.2|6.4)A",
1285    "", "", ""
1286  },
1287  { "Quantum Fireball ST series",
1288    "QUANTUM FIREBALL ST(3.2|4.3|4300)A",
1289    "", "", ""
1290  },
1291  { "Quantum Fireball SE series",
1292    "QUANTUM FIREBALL SE4.3A",
1293    "", "", ""
1294  },
1295  { "Quantum Fireball Plus LM series",
1296    "QUANTUM FIREBALLP LM(10.2|15|20.[45]|30)",
1297    "", "", ""
1298  },
1299  { "Quantum Fireball Plus AS series",
1300    "QUANTUM FIREBALLP AS(10.2|20.5|30.0|40.0)",
1301    "", "", ""
1302  },
1303  { "Quantum Fireball Plus KX series",
1304    "QUANTUM FIREBALLP KX27.3",
1305    "", "", ""
1306  },
1307  { "Quantum Fireball Plus KA series",
1308    "QUANTUM FIREBALLP KA(9|10).1",
1309    "", "", ""
1310  },
1311// END drivedb.h (DO NOT DELETE - used by Makefile)
1312};
1313
1314
1315/// Drive database class. Stores custom entries read from file.
1316/// Provides transparent access to concatenation of custom and
1317/// default table.
1318class drive_database
1319{
1320public:
1321  drive_database();
1322
1323  ~drive_database();
1324
1325  /// Get total number of entries.
1326  unsigned size() const
1327    { return m_custom_tab.size() + m_builtin_size; }
1328
1329  /// Get number of custom entries.
1330  unsigned custom_size() const
1331    { return m_custom_tab.size(); }
1332
1333  /// Array access.
1334  const drive_settings & operator[](unsigned i);
1335
1336  /// Append new custom entry.
1337  void push_back(const drive_settings & src);
1338
1339  /// Append builtin table.
1340  void append(const drive_settings * builtin_tab, unsigned builtin_size)
1341    { m_builtin_tab = builtin_tab; m_builtin_size = builtin_size; }
1342
1343private:
1344  const drive_settings * m_builtin_tab;
1345  unsigned m_builtin_size;
1346
1347  std::vector<drive_settings> m_custom_tab;
1348  std::vector<char *> m_custom_strings;
1349
1350  const char * copy_string(const char * str);
1351
1352  drive_database(const drive_database &);
1353  void operator=(const drive_database &);
1354};
1355
1356drive_database::drive_database()
1357: m_builtin_tab(0), m_builtin_size(0)
1358{
1359}
1360
1361drive_database::~drive_database()
1362{
1363  for (unsigned i = 0; i < m_custom_strings.size(); i++)
1364    delete [] m_custom_strings[i];
1365}
1366
1367const drive_settings & drive_database::operator[](unsigned i)
1368{
1369  return (i < m_custom_tab.size() ? m_custom_tab[i]
1370          : m_builtin_tab[i - m_custom_tab.size()] );
1371}
1372
1373void drive_database::push_back(const drive_settings & src)
1374{
1375  drive_settings dest;
1376  dest.modelfamily    = copy_string(src.modelfamily);
1377  dest.modelregexp    = copy_string(src.modelregexp);
1378  dest.firmwareregexp = copy_string(src.firmwareregexp);
1379  dest.warningmsg     = copy_string(src.warningmsg);
1380  dest.presets        = copy_string(src.presets);
1381  m_custom_tab.push_back(dest);
1382}
1383
1384const char * drive_database::copy_string(const char * src)
1385{
1386  char * dest = new char[strlen(src)+1];
1387  try {
1388    m_custom_strings.push_back(dest);
1389  }
1390  catch (...) {
1391    delete [] dest; throw;
1392  }
1393  return strcpy(dest, src);
1394}
1395
1396
1397/// The drive database.
1398static drive_database knowndrives;
1399
1400
1401// Compile regular expression, print message on failure.
1402static bool compile(regular_expression & regex, const char *pattern)
1403{
1404  if (!regex.compile(pattern, REG_EXTENDED)) {
1405    pout("Internal error: unable to compile regular expression \"%s\": %s\n"
1406         "Please inform smartmontools developers at " PACKAGE_BUGREPORT "\n",
1407      pattern, regex.get_errmsg());
1408    return false;
1409  }
1410  return true;
1411}
1412
1413// Compile & match a regular expression.
1414static bool match(const char * pattern, const char * str)
1415{
1416  regular_expression regex;
1417  if (!compile(regex, pattern))
1418    return false;
1419  return regex.full_match(str);
1420}
1421
1422// Searches knowndrives[] for a drive with the given model number and firmware
1423// string.  If either the drive's model or firmware strings are not set by the
1424// manufacturer then values of NULL may be used.  Returns the entry of the
1425// first match in knowndrives[] or 0 if no match if found.
1426const drive_settings * lookup_drive(const char * model, const char * firmware)
1427{
1428  if (!model)
1429    model = "";
1430  if (!firmware)
1431    firmware = "";
1432
1433  for (unsigned i = 0; i < knowndrives.size(); i++) {
1434    // Check whether model matches the regular expression in knowndrives[i].
1435    if (!match(knowndrives[i].modelregexp, model))
1436      continue;
1437
1438    // Model matches, now check firmware. "" matches always.
1439    if (!(  !*knowndrives[i].firmwareregexp
1440          || match(knowndrives[i].firmwareregexp, firmware)))
1441      continue;
1442
1443    // Found
1444    return &knowndrives[i];
1445  }
1446
1447  // Not found
1448  return 0;
1449}
1450
1451// Parse '-v' and '-F' options in preset string, return false on error.
1452static bool parse_presets(const char * presets, unsigned char * opts, unsigned char & fix_firmwarebug)
1453{
1454  for (int i = 0; ; ) {
1455    i += strspn(presets+i, " \t");
1456    if (!presets[i])
1457      break;
1458    char opt, arg[40+1+13]; int len = -1;
1459    if (!(sscanf(presets+i, "-%c %40[^ ]%n", &opt, arg, &len) >= 2 && len > 0))
1460      return false;
1461    if (opt == 'v') {
1462      // Parse "-v N,option"
1463      unsigned char newopts[MAX_ATTRIBUTE_NUM] = {0, };
1464      if (parse_attribute_def(arg, newopts))
1465        return false;
1466      // Set only if not set by user
1467      for (int j = 0; j < MAX_ATTRIBUTE_NUM; j++)
1468        if (newopts[j] && !opts[j])
1469          opts[j] = newopts[j];
1470    }
1471    else if (opt == 'F') {
1472      unsigned char fix;
1473      if (!strcmp(arg, "samsung"))
1474        fix = FIX_SAMSUNG;
1475      else if (!strcmp(arg, "samsung2"))
1476        fix = FIX_SAMSUNG2;
1477      else if (!strcmp(arg, "samsung3"))
1478        fix = FIX_SAMSUNG3;
1479      else
1480        return false;
1481      // Set only if not set by user
1482      if (fix_firmwarebug == FIX_NOTSPECIFIED)
1483        fix_firmwarebug = fix;
1484    }
1485    else
1486      return false;
1487
1488    i += len;
1489  }
1490  return true;
1491}
1492
1493// Shows one entry of knowndrives[], returns #errors.
1494static int showonepreset(const drive_settings * dbentry)
1495{
1496  // Basic error check
1497  if (!(   dbentry
1498        && dbentry->modelfamily
1499        && dbentry->modelregexp && *dbentry->modelregexp
1500        && dbentry->firmwareregexp
1501        && dbentry->warningmsg
1502        && dbentry->presets                             )) {
1503    pout("Invalid drive database entry. Please report\n"
1504         "this error to smartmontools developers at " PACKAGE_BUGREPORT ".\n");
1505    return 1;
1506  }
1507 
1508  // print and check model and firmware regular expressions
1509  int errcnt = 0;
1510  regular_expression regex;
1511  pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL REGEXP:", dbentry->modelregexp);
1512  if (!compile(regex, dbentry->modelregexp))
1513    errcnt++;
1514
1515  pout("%-*s %s\n", TABLEPRINTWIDTH, "FIRMWARE REGEXP:", *dbentry->firmwareregexp ?
1516    dbentry->firmwareregexp : ".*"); // preserve old output (TODO: Change)
1517  if (*dbentry->firmwareregexp && !compile(regex, dbentry->firmwareregexp))
1518    errcnt++;
1519
1520  pout("%-*s %s\n", TABLEPRINTWIDTH, "MODEL FAMILY:", dbentry->modelfamily);
1521
1522  // if there are any presets, then show them
1523  unsigned char fix_firmwarebug = 0;
1524  bool first_preset = true;
1525  if (*dbentry->presets) {
1526    unsigned char opts[MAX_ATTRIBUTE_NUM] = {0,};
1527    if (!parse_presets(dbentry->presets, opts, fix_firmwarebug)) {
1528      pout("Syntax error in preset option string \"%s\"\n", dbentry->presets);
1529      errcnt++;
1530    }
1531    for (int i = 0; i < MAX_ATTRIBUTE_NUM; i++) {
1532      char out[256];
1533      if (opts[i]) {
1534        ataPrintSmartAttribName(out, i, opts);
1535        // Use leading zeros instead of spaces so that everything lines up.
1536        out[0] = (out[0] == ' ') ? '0' : out[0];
1537        out[1] = (out[1] == ' ') ? '0' : out[1];
1538        pout("%-*s %s\n", TABLEPRINTWIDTH, first_preset ? "ATTRIBUTE OPTIONS:" : "", out);
1539        first_preset = false;
1540      }
1541    }
1542  }
1543  if (first_preset)
1544    pout("%-*s %s\n", TABLEPRINTWIDTH, "ATTRIBUTE OPTIONS:", "None preset; no -v options are required.");
1545
1546  // describe firmwarefix
1547  if (fix_firmwarebug) {
1548    const char * fixdesc;
1549    switch (fix_firmwarebug) {
1550      case FIX_SAMSUNG:
1551        fixdesc = "Fixes byte order in some SMART data (same as -F samsung)";
1552        break;
1553      case FIX_SAMSUNG2:
1554        fixdesc = "Fixes byte order in some SMART data (same as -F samsung2)";
1555        break;
1556      case FIX_SAMSUNG3:
1557        fixdesc = "Fixes completed self-test reported as in progress (same as -F samsung3)";
1558        break;
1559      default:
1560        fixdesc = "UNKNOWN"; errcnt++;
1561        break;
1562    }
1563    pout("%-*s %s\n", TABLEPRINTWIDTH, "OTHER PRESETS:", fixdesc);
1564  }
1565
1566  // Print any special warnings
1567  if (*dbentry->warningmsg)
1568    pout("%-*s %s\n", TABLEPRINTWIDTH, "WARNINGS:", dbentry->warningmsg);
1569  return errcnt;
1570}
1571
1572// Shows all presets for drives in knowndrives[].
1573// Returns #syntax errors.
1574int showallpresets()
1575{
1576  // loop over all entries in the knowndrives[] table, printing them
1577  // out in a nice format
1578  int errcnt = 0;
1579  for (unsigned i = 0; i < knowndrives.size(); i++) {
1580    errcnt += showonepreset(&knowndrives[i]);
1581    pout("\n");
1582  }
1583
1584  pout("Total number of entries  :%5u\n"
1585       "Entries read from file(s):%5u\n\n",
1586    knowndrives.size(), knowndrives.custom_size());
1587
1588  pout("For information about adding a drive to the database see the FAQ on the\n");
1589  pout("smartmontools home page: " PACKAGE_HOMEPAGE "\n");
1590
1591  if (errcnt > 0)
1592    pout("\nFound %d syntax error(s) in database.\n"
1593         "Please inform smartmontools developers at " PACKAGE_BUGREPORT "\n", errcnt);
1594  return errcnt;
1595}
1596
1597// Shows all matching presets for a drive in knowndrives[].
1598// Returns # matching entries.
1599int showmatchingpresets(const char *model, const char *firmware)
1600{
1601  int cnt = 0;
1602  const char * firmwaremsg = (firmware ? firmware : "(any)");
1603
1604  for (unsigned i = 0; i < knowndrives.size(); i++) {
1605    if (!match(knowndrives[i].modelregexp, model))
1606      continue;
1607    if (   firmware && *knowndrives[i].firmwareregexp
1608        && !match(knowndrives[i].firmwareregexp, firmware))
1609        continue;
1610    // Found
1611    if (++cnt == 1)
1612      pout("Drive found in smartmontools Database.  Drive identity strings:\n"
1613           "%-*s %s\n"
1614           "%-*s %s\n"
1615           "match smartmontools Drive Database entry:\n",
1616           TABLEPRINTWIDTH, "MODEL:", model, TABLEPRINTWIDTH, "FIRMWARE:", firmwaremsg);
1617    else if (cnt == 2)
1618      pout("and match these additional entries:\n");
1619    showonepreset(&knowndrives[i]);
1620    pout("\n");
1621  }
1622  if (cnt == 0)
1623    pout("No presets are defined for this drive.  Its identity strings:\n"
1624         "MODEL:    %s\n"
1625         "FIRMWARE: %s\n"
1626         "do not match any of the known regular expressions.\n",
1627         model, firmwaremsg);
1628  return cnt;
1629}
1630
1631// Shows the presets (if any) that are available for the given drive.
1632void show_presets(const ata_identify_device * drive, bool fix_swapped_id)
1633{
1634  char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1];
1635
1636  // get the drive's model/firmware strings
1637  format_ata_string(model, drive->model, MODEL_STRING_LENGTH, fix_swapped_id);
1638  format_ata_string(firmware, drive->fw_rev, FIRMWARE_STRING_LENGTH, fix_swapped_id);
1639 
1640  // and search to see if they match values in the table
1641  const drive_settings * dbentry = lookup_drive(model, firmware);
1642  if (!dbentry) {
1643    // no matches found
1644    pout("No presets are defined for this drive.  Its identity strings:\n"
1645         "MODEL:    %s\n"
1646         "FIRMWARE: %s\n"
1647         "do not match any of the known regular expressions.\n"
1648         "Use -P showall to list all known regular expressions.\n",
1649         model, firmware);
1650    return;
1651  }
1652 
1653  // We found a matching drive.  Print out all information about it.
1654  pout("Drive found in smartmontools Database.  Drive identity strings:\n"
1655       "%-*s %s\n"
1656       "%-*s %s\n"
1657       "match smartmontools Drive Database entry:\n",
1658       TABLEPRINTWIDTH, "MODEL:", model, TABLEPRINTWIDTH, "FIRMWARE:", firmware);
1659  showonepreset(dbentry);
1660}
1661
1662// Sets preset vendor attribute options in opts by finding the entry
1663// (if any) for the given drive in knowndrives[].  Values that have
1664// already been set in opts will not be changed.  Returns false if drive
1665// not recognized.
1666bool apply_presets(const ata_identify_device *drive, unsigned char * opts,
1667                   unsigned char & fix_firmwarebug, bool fix_swapped_id)
1668{
1669  // get the drive's model/firmware strings
1670  char model[MODEL_STRING_LENGTH+1], firmware[FIRMWARE_STRING_LENGTH+1];
1671  format_ata_string(model, drive->model, MODEL_STRING_LENGTH, fix_swapped_id);
1672  format_ata_string(firmware, drive->fw_rev, FIRMWARE_STRING_LENGTH, fix_swapped_id);
1673 
1674  // Look up the drive in knowndrives[].
1675  const drive_settings * dbentry = lookup_drive(model, firmware);
1676  if (!dbentry)
1677    return false;
1678
1679  if (*dbentry->presets) {
1680    // Apply presets
1681    if (!parse_presets(dbentry->presets, opts, fix_firmwarebug))
1682      pout("Syntax error in preset option string \"%s\"\n", dbentry->presets);
1683  }
1684  return true;
1685}
1686
1687
1688/////////////////////////////////////////////////////////////////////////////
1689// Parser for drive database files
1690
1691// Abstract pointer to read file input.
1692// Operations supported: c = *p; c = p[1]; ++p;
1693class stdin_iterator
1694{
1695public:
1696  explicit stdin_iterator(FILE * f)
1697    : m_f(f) { get(); get(); }
1698
1699  stdin_iterator & operator++()
1700    { get(); return *this; }
1701
1702  char operator*() const
1703    { return m_c; }
1704
1705  char operator[](int i) const
1706    {
1707      if (i != 1)
1708        fail();
1709      return m_next;
1710    }
1711
1712private:
1713  FILE * m_f;
1714  char m_c, m_next;
1715  void get();
1716  void fail() const;
1717};
1718
1719void stdin_iterator::get()
1720{
1721  m_c = m_next;
1722  int ch = getc(m_f);
1723  m_next = (ch != EOF ? ch : 0);
1724}
1725
1726void stdin_iterator::fail() const
1727{
1728  throw std::runtime_error("stdin_iterator: wrong usage");
1729}
1730
1731
1732// Use above as parser input 'pointer'. Can easily be changed later
1733// to e.g. 'const char *' if above is too slow.
1734typedef stdin_iterator parse_ptr;
1735
1736// Skip whitespace and comments.
1737static parse_ptr skip_white(parse_ptr src, const char * path, int & line)
1738{
1739  for ( ; ; ++src) switch (*src) {
1740    case ' ': case '\t':
1741      continue;
1742
1743    case '\n':
1744      ++line;
1745      continue;
1746
1747    case '/':
1748      switch (src[1]) {
1749        case '/':
1750          // skip '// comment'
1751          ++src; ++src;
1752          while (*src && *src != '\n')
1753            ++src;
1754          if (*src)
1755            ++line;
1756          break;
1757        case '*':
1758          // skip '/* comment */'
1759          ++src; ++src;
1760          for (;;) {
1761            if (!*src) {
1762              pout("%s(%d): Missing '*/'\n", path, line);
1763              return src;
1764            }
1765            char c = *src; ++src;
1766            if (c == '\n')
1767              ++line;
1768            else if (c == '*' && *src == '/')
1769              break;
1770          }
1771          break;
1772        default:
1773          return src;
1774      }
1775      continue;
1776
1777    default:
1778      return src;
1779  }
1780}
1781
1782// Info about a token.
1783struct token_info
1784{
1785  char type;
1786  int line;
1787  std::string value;
1788
1789  token_info() : type(0), line(0) { }
1790};
1791
1792// Get next token.
1793static parse_ptr get_token(parse_ptr src, token_info & token, const char * path, int & line)
1794{
1795  src = skip_white(src, path, line);
1796  switch (*src) {
1797    case '{': case '}': case ',':
1798      // Simple token
1799      token.type = *src; token.line = line;
1800      ++src;
1801      break;
1802
1803    case '"':
1804      // String constant
1805      token.type = '"'; token.line = line;
1806      token.value = "";
1807      do {
1808        for (++src; *src != '"'; ++src) {
1809          char c = *src;
1810          if (!c || c == '\n' || (c == '\\' && !src[1])) {
1811            pout("%s(%d): Missing terminating '\"'\n", path, line);
1812            token.type = '?'; token.line = line;
1813            return src;
1814          }
1815          if (c == '\\') {
1816            c = *++src;
1817            switch (c) {
1818              case 'n' : c = '\n'; break;
1819              case '\n': ++line; break;
1820              case '\\': case '"': break;
1821              default:
1822                pout("%s(%d): Unknown escape sequence '\\%c'\n", path, line, c);
1823                token.type = '?'; token.line = line;
1824                continue;
1825            }
1826          }
1827          token.value += c;
1828        }
1829        // Lookahead to detect string constant concatentation
1830        src = skip_white(++src, path, line);
1831      } while (*src == '"');
1832      break;
1833
1834    case 0:
1835      // EOF
1836      token.type = 0; token.line = line;
1837      break;
1838
1839    default:
1840      pout("%s(%d): Syntax error, invalid char '%c'\n", path, line, *src);
1841      token.type = '?'; token.line = line;
1842      while (*src && *src != '\n')
1843        ++src;
1844      break;
1845  }
1846
1847  return src;
1848}
1849
1850// Parse drive database from abstract input pointer.
1851static bool parse_drive_database(parse_ptr src, drive_database & db, const char * path)
1852{
1853  int state = 0, field = 0;
1854  std::string values[5];
1855  bool ok = true;
1856
1857  token_info token; int line = 1;
1858  src = get_token(src, token, path, line);
1859  for (;;) {
1860    // EOF is ok after '}', trailing ',' is also allowed.
1861    if (!token.type && (state == 0 || state == 4))
1862      break;
1863
1864    // Check expected token
1865    const char expect[] = "{\",},";
1866    if (token.type != expect[state]) {
1867      if (token.type != '?')
1868        pout("%s(%d): Syntax error, '%c' expected\n", path, token.line, expect[state]);
1869      ok = false;
1870      // Skip to next entry
1871      while (token.type && token.type != '{')
1872        src = get_token(src, token, path, line);
1873      state = 0;
1874      if (token.type)
1875        continue;
1876      break;
1877    }
1878
1879    // Interpret parser state
1880    switch (state) {
1881      case 0: // ... ^{...}
1882        state = 1; field = 0;
1883        break;
1884      case 1: // {... ^"..." ...}
1885        switch (field) {
1886          case 1: case 2:
1887            if (!token.value.empty()) {
1888              regular_expression regex;
1889              if (!regex.compile(token.value.c_str(), REG_EXTENDED)) {
1890                pout("%s(%d): Error in regular expression: %s\n", path, token.line, regex.get_errmsg());
1891                ok = false;
1892              }
1893            }
1894            else if (field == 1) {
1895              pout("%s(%d): Missing regular expression for drive model\n", path, token.line);
1896              ok = false;
1897            }
1898            break;
1899          case 4:
1900            if (!token.value.empty()) {
1901              unsigned char opts[MAX_ATTRIBUTE_NUM] = {0, }; unsigned char fix = 0;
1902              if (!parse_presets(token.value.c_str(), opts, fix)) {
1903                pout("%s(%d): Syntax error in preset option string\n", path, token.line);
1904                ok = false;
1905              }
1906            }
1907            break;
1908        }
1909        values[field] = token.value;
1910        state = (++field < 5 ? 2 : 3);
1911        break;
1912      case 2: // {... "..."^, ...}
1913        state = 1;
1914        break;
1915      case 3: // {...^}, ...
1916        {
1917          drive_settings entry;
1918          entry.modelfamily    = values[0].c_str();
1919          entry.modelregexp    = values[1].c_str();
1920          entry.firmwareregexp = values[2].c_str();
1921          entry.warningmsg     = values[3].c_str();
1922          entry.presets        = values[4].c_str();
1923          db.push_back(entry);
1924        }
1925        state = 4;
1926        break;
1927      case 4: // {...}^, ...
1928        state = 0;
1929        break;
1930      default:
1931        pout("Bad state %d\n", state);
1932        return false;
1933    }
1934    src = get_token(src, token, path, line);
1935  }
1936  return ok;
1937}
1938
1939// Read drive database from file.
1940bool read_drive_database(const char * path)
1941{
1942  stdio_file f(path, "r");
1943  if (!f) {
1944    pout("%s: cannot open drive database file\n", path);
1945    return false;
1946  }
1947
1948  return parse_drive_database(parse_ptr(f), knowndrives, path);
1949}
1950
1951// Read drive databases from standard places.
1952bool read_default_drive_databases()
1953{
1954#ifndef _WIN32
1955  // Read file for local additions: /{,usr/local/}etc/smart_drivedb.h
1956  static const char db1[] = SMARTMONTOOLS_SYSCONFDIR"/smart_drivedb.h";
1957#else
1958  static const char db1[] = "./smart_drivedb.h";
1959#endif
1960  if (!access(db1, 0)) {
1961    if (!read_drive_database(db1))
1962      return false;
1963  }
1964
1965#ifdef SMARTMONTOOLS_DRIVEDBDIR
1966  // Read file from package: // /usr/{,local/}share/smartmontools/drivedb.h
1967  static const char db2[] = SMARTMONTOOLS_DRIVEDBDIR"/drivedb.h";
1968  if (!access(db2, 0)) {
1969    if (!read_drive_database(db2))
1970      return false;
1971  }
1972  else
1973#endif
1974  {
1975    // Append builtin table.
1976    knowndrives.append(builtin_knowndrives,
1977      sizeof(builtin_knowndrives)/sizeof(builtin_knowndrives[0]));
1978  }
1979
1980  return true;
1981}
Note: See TracBrowser for help on using the browser.