diff options
author | Alasdair G Kergon <agk@redhat.com> | 2016-03-22 21:39:52 +0000 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2016-03-22 21:39:52 +0000 |
commit | 1056894f1f1d48eb295d283859473cd9bc6b9df5 (patch) | |
tree | 40b2a69fa66bfeca6b81e44d1fb710e5af6916dd | |
parent | cf393466976a226faba924c6d14fa04bd7b37c89 (diff) | |
download | lvm2-1056894f1f1d48eb295d283859473cd9bc6b9df5.tar.gz |
raid: Tidy dm_get_status_raid. [HM]
-rw-r--r-- | libdm/libdm-targets.c | 87 |
1 files changed, 53 insertions, 34 deletions
diff --git a/libdm/libdm-targets.c b/libdm/libdm-targets.c index 8a8a328d1..b91c7e9af 100644 --- a/libdm/libdm-targets.c +++ b/libdm/libdm-targets.c @@ -67,6 +67,23 @@ static const char *_skip_fields(const char *p, unsigned nr) } /* + * Count number of single-space delimited fields. + * Number of fields is number of spaces plus one. + */ +static unsigned _count_fields(const char *p) +{ + unsigned nr = 1; + + if (!p || !*p) + return 0; + + while ((p = _skip_fields(p, 1))) + nr++; + + return nr; +} + +/* * Various RAID status versions include: * Versions < 1.5.0 (4 fields): * <raid_type> <#devs> <health_str> <sync_ratio> @@ -77,69 +94,71 @@ int dm_get_status_raid(struct dm_pool *mem, const char *params, struct dm_status_raid **status) { int i; - const char *pp, *p; - struct dm_status_raid *s; + unsigned num_fields; + const char *p, *pp, *msg_fields = ""; + struct dm_status_raid *s = NULL; - if (!params || !(p = strchr(params, ' '))) { - log_error("Failed to parse invalid raid params."); - return 0; - } - p++; + if ((num_fields = _count_fields(params)) < 4) + goto_bad; - /* second field holds the device count */ - if (sscanf(p, "%d", &i) != 1) - return_0; + /* Second field holds the device count */ + msg_fields = "<#devs> "; + if (!(p = _skip_fields(params, 1)) || (sscanf(p, "%d", &i) != 1)) + goto_bad; + msg_fields = ""; if (!(s = dm_pool_zalloc(mem, sizeof(struct dm_status_raid)))) - return_0; + goto_bad; if (!(s->raid_type = dm_pool_zalloc(mem, p - params))) goto_bad; /* memory is freed when pool is destroyed */ - if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) + if (!(s->dev_health = dm_pool_zalloc(mem, i + 1))) /* Space for health chars */ goto_bad; + msg_fields = "<raid_type> <#devices> <health_chars> and <sync_ratio> "; if (sscanf(params, "%s %u %s %" PRIu64 "/%" PRIu64, s->raid_type, &s->dev_count, s->dev_health, &s->insync_regions, - &s->total_regions) != 5) { - log_error("Failed to parse raid params: %s", params); - goto bad; - } - - *status = s; + &s->total_regions) != 5) + goto_bad; /* * All pre-1.5.0 version parameters are read. Now we check - * for additional 1.5.0+ parameters. + * for additional 1.5.0+ parameters (i.e. num_fields at least 6). * * Note that 'sync_action' will be NULL (and mismatch_count * will be 0) if the kernel returns a pre-1.5.0 status. */ - for (p = params, i = 0; i < 4; i++, p++) - if (!(p = strchr(p, ' '))) - return 1; /* return pre-1.5.0 status */ + if (num_fields < 6) + goto out; - pp = p; - if (!(p = strchr(p, ' '))) { - log_error(INTERNAL_ERROR "Bad RAID status received."); - goto bad; - } - p++; + msg_fields = "<sync_action> and <mismatch_cnt> "; - if (!(s->sync_action = dm_pool_zalloc(mem, p - pp))) + /* Skip pre-1.5.0 params */ + if (!(p = _skip_fields(params, 4)) || !(pp = _skip_fields(p, 1))) goto_bad; - if (sscanf(pp, "%s %" PRIu64, s->sync_action, &s->mismatch_count) != 2) { - log_error("Failed to parse raid params: %s", params); - goto bad; - } + if (!(s->sync_action = dm_pool_zalloc(mem, pp - p))) + goto_bad; + + if (sscanf(p, "%s %" PRIu64, s->sync_action, &s->mismatch_count) != 2) + goto_bad; + +out: + *status = s; return 1; + bad: - dm_pool_free(mem, s); + log_error("Failed to parse %sraid params: %s", msg_fields, params); + + if (s) + dm_pool_free(mem, s); + + *status = NULL; return 0; } |