diff options
author | Mark Lord <kernel@teksavvy.com> | 2010-07-01 18:16:14 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2010-08-01 19:36:03 -0400 |
commit | bce036cea10a8dd21eb8c9bf1b641d8790429c8e (patch) | |
tree | 2e0d87245467b30fced2d65e7cfe9352ee930f2c /drivers/ata | |
parent | da10a2002cf25a11f18fa1b5e327b9ed717f819c (diff) |
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: Mark Lord <mlord@pobox.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r-- | drivers/ata/libata-core.c | 78 |
1 files changed, 57 insertions, 21 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index ddf8e486278..f8c72a1867f 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c | |||
@@ -4326,29 +4326,65 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { | |||
4326 | { } | 4326 | { } |
4327 | }; | 4327 | }; |
4328 | 4328 | ||
4329 | static int strn_pattern_cmp(const char *patt, const char *name, int wildchar) | 4329 | /** |
4330 | * glob_match - match a text string against a glob-style pattern | ||
4331 | * @text: the string to be examined | ||
4332 | * @pattern: the glob-style pattern to be matched against | ||
4333 | * | ||
4334 | * Either/both of text and pattern can be empty strings. | ||
4335 | * | ||
4336 | * Match text against a glob-style pattern, with wildcards and simple sets: | ||
4337 | * | ||
4338 | * ? matches any single character. | ||
4339 | * * matches any run of characters. | ||
4340 | * [xyz] matches a single character from the set: x, y, or z. | ||
4341 | * | ||
4342 | * Note: hyphenated ranges [0-9] are _not_ supported here. | ||
4343 | * The special characters ?, [, or *, can be matched using a set, eg. [*] | ||
4344 | * | ||
4345 | * Example patterns: "SD1?", "SD1[012345]", "*R0", SD*1?[012]*xx" | ||
4346 | * | ||
4347 | * This function uses one level of recursion per '*' in pattern. | ||
4348 | * Since it calls _nothing_ else, and has _no_ explicit local variables, | ||
4349 | * this will not cause stack problems for any reasonable use here. | ||
4350 | * | ||
4351 | * RETURNS: | ||
4352 | * 0 on match, 1 otherwise. | ||
4353 | */ | ||
4354 | static int glob_match (const char *text, const char *pattern) | ||
4330 | { | 4355 | { |
4331 | const char *p; | 4356 | do { |
4332 | int len; | 4357 | /* Match single character or a '?' wildcard */ |
4333 | 4358 | if (*text == *pattern || *pattern == '?') { | |
4334 | /* | 4359 | if (!*pattern++) |
4335 | * check for trailing wildcard: *\0 | 4360 | return 0; /* End of both strings: match */ |
4336 | */ | 4361 | } else { |
4337 | p = strchr(patt, wildchar); | 4362 | /* Match single char against a '[' bracketed ']' pattern set */ |
4338 | if (p && ((*(p + 1)) == 0)) | 4363 | if (!*text || *pattern != '[') |
4339 | len = p - patt; | 4364 | break; /* Not a pattern set */ |
4340 | else { | 4365 | while (*++pattern && *pattern != ']' && *text != *pattern); |
4341 | len = strlen(name); | 4366 | if (!*pattern || *pattern == ']') |
4342 | if (!len) { | 4367 | return 1; /* No match */ |
4343 | if (!*patt) | 4368 | while (*pattern && *pattern++ != ']'); |
4344 | return 0; | 4369 | } |
4345 | return -1; | 4370 | } while (*++text && *pattern); |
4371 | |||
4372 | /* Match any run of chars against a '*' wildcard */ | ||
4373 | if (*pattern == '*') { | ||
4374 | if (!*++pattern) | ||
4375 | return 0; /* Match: avoid recursion at end of pattern */ | ||
4376 | /* Loop to handle additional pattern chars after the wildcard */ | ||
4377 | while (*text) { | ||
4378 | if (glob_match(text, pattern) == 0) | ||
4379 | return 0; /* Remainder matched */ | ||
4380 | ++text; /* Absorb (match) this char and try again */ | ||
4346 | } | 4381 | } |
4347 | } | 4382 | } |
4348 | 4383 | if (!*text && !*pattern) | |
4349 | return strncmp(patt, name, len); | 4384 | return 0; /* End of both strings: match */ |
4385 | return 1; /* No match */ | ||
4350 | } | 4386 | } |
4351 | 4387 | ||
4352 | static unsigned long ata_dev_blacklisted(const struct ata_device *dev) | 4388 | static unsigned long ata_dev_blacklisted(const struct ata_device *dev) |
4353 | { | 4389 | { |
4354 | unsigned char model_num[ATA_ID_PROD_LEN + 1]; | 4390 | 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 | ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); | 4395 | ata_id_c_string(dev->id, model_rev, ATA_ID_FW_REV, sizeof(model_rev)); |
4360 | 4396 | ||
4361 | while (ad->model_num) { | 4397 | while (ad->model_num) { |
4362 | if (!strn_pattern_cmp(ad->model_num, model_num, '*')) { | 4398 | if (!glob_match(model_num, ad->model_num)) { |
4363 | if (ad->model_rev == NULL) | 4399 | if (ad->model_rev == NULL) |
4364 | return ad->horkage; | 4400 | return ad->horkage; |
4365 | if (!strn_pattern_cmp(ad->model_rev, model_rev, '*')) | 4401 | if (!glob_match(model_rev, ad->model_rev)) |
4366 | return ad->horkage; | 4402 | return ad->horkage; |
4367 | } | 4403 | } |
4368 | ad++; | 4404 | ad++; |