Commit bce036ce authored by Mark Lord's avatar Mark Lord Committed by Jeff Garzik

libata: glob_match for ata_device_blacklist (v2)

Replace rudimentry pattern matching with more capable shell-style globbing.
This will enable shrinking ata_device_blacklist[] table in subsequent patches,
and helps with future editions to the table, such as matching only the end
of a firmware revision string etc..
Signed-off-by: default avatarMark Lord <mlord@pobox.com>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent da10a200
...@@ -4326,29 +4326,65 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ...@@ -4326,29 +4326,65 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
{ } { }
}; };
static int strn_pattern_cmp(const char *patt, const char *name, int wildchar) /**
* glob_match - match a text string against a glob-style pattern
* @text: the string to be examined
* @pattern: the glob-style pattern to be matched against
*
* Either/both of text and pattern can be empty strings.
*
* Match text against a glob-style pattern, with wildcards and simple sets:
*
* ? matches any single character.
* * matches any run of characters.
* [xyz] matches a single character from the set: x, y, or z.
*
* Note: hyphenated ranges [0-9] are _not_ supported here.
* The special characters ?, [, or *, can be matched using a set, eg. [*]
*
* Example patterns: "SD1?", "SD1[012345]", "*R0", SD*1?[012]*xx"
*
* This function uses one level of recursion per '*' in pattern.
* Since it calls _nothing_ else, and has _no_ explicit local variables,
* this will not cause stack problems for any reasonable use here.
*
* RETURNS:
* 0 on match, 1 otherwise.
*/
static int glob_match (const char *text, const char *pattern)
{ {
const char *p; do {
int len; /* Match single character or a '?' wildcard */
if (*text == *pattern || *pattern == '?') {
/* if (!*pattern++)
* check for trailing wildcard: *\0 return 0; /* End of both strings: match */
*/ } else {
p = strchr(patt, wildchar); /* Match single char against a '[' bracketed ']' pattern set */
if (p && ((*(p + 1)) == 0)) if (!*text || *pattern != '[')
len = p - patt; break; /* Not a pattern set */
else { while (*++pattern && *pattern != ']' && *text != *pattern);
len = strlen(name); if (!*pattern || *pattern == ']')
if (!len) { return 1; /* No match */
if (!*patt) while (*pattern && *pattern++ != ']');
return 0; }
return -1; } while (*++text && *pattern);
/* Match any run of chars against a '*' wildcard */
if (*pattern == '*') {
if (!*++pattern)
return 0; /* Match: avoid recursion at end of pattern */
/* Loop to handle additional pattern chars after the wildcard */
while (*text) {
if (glob_match(text, pattern) == 0)
return 0; /* Remainder matched */
++text; /* Absorb (match) this char and try again */
} }
} }
if (!*text && !*pattern)
return strncmp(patt, name, len); return 0; /* End of both strings: match */
return 1; /* No match */
} }
static unsigned long ata_dev_blacklisted(const struct ata_device *dev) static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
{ {
unsigned char model_num[ATA_ID_PROD_LEN + 1]; unsigned char model_num[ATA_ID_PROD_LEN + 1];
...@@ -4359,10 +4395,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev) ...@@ -4359,10 +4395,10 @@ static unsigned long ata_dev_blacklisted(const struct ata_device *dev)
ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev));
while (ad->model_num) { while (ad->model_num) {
if (!strn_pattern_cmp(ad->model_num, model_num, '*')) { if (!glob_match(model_num, ad->model_num)) {
if (ad->model_rev == NULL) if (ad->model_rev == NULL)
return ad->horkage; return ad->horkage;
if (!strn_pattern_cmp(ad->model_rev, model_rev, '*')) if (!glob_match(model_rev, ad->model_rev))
return ad->horkage; return ad->horkage;
} }
ad++; ad++;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment