2008-04-13 Robert Millan <rmh@aybabtu.com>

Improve robustness when handling LVM.

        * disk/lvm.c (grub_lvm_getvalue): Return 0 when `*p' is NULL
        (and leave `*p' unmodified).
        (grub_lvm_iterate): Don't assume `vg->lvs != NULL' when iterating
        through it.
        (grub_lvm_memberlist): Don't assume `lv->vg->pvs != NULL' when
        iterating through it.
        (grub_lvm_open): Don't assume `vg->lvs != NULL' when iterating
        through it.
        (grub_lvm_scan_device): Check the return value (and fail gracefuly
        when due) on each grub_lvm_getvalue() or grub_strstr() call.
        Don't assume `vg->pvs != NULL' when iterating through it.
This commit is contained in:
robertmh 2008-04-13 12:22:22 +00:00
parent 5325687fc6
commit 7ceeee39d7
2 changed files with 206 additions and 132 deletions

View file

@ -1,3 +1,19 @@
2008-04-13 Robert Millan <rmh@aybabtu.com>
Improve robustness when handling LVM.
* disk/lvm.c (grub_lvm_getvalue): Return 0 when `*p' is NULL
(and leave `*p' unmodified).
(grub_lvm_iterate): Don't assume `vg->lvs != NULL' when iterating
through it.
(grub_lvm_memberlist): Don't assume `lv->vg->pvs != NULL' when
iterating through it.
(grub_lvm_open): Don't assume `vg->lvs != NULL' when iterating
through it.
(grub_lvm_scan_device): Check the return value (and fail gracefuly
when due) on each grub_lvm_getvalue() or grub_strstr() call.
Don't assume `vg->pvs != NULL' when iterating through it.
2008-04-13 Robert Millan <rmh@aybabtu.com> 2008-04-13 Robert Millan <rmh@aybabtu.com>
* gendistlist.sh (EXTRA_DISTFILES): Add `genpartmaplist.sh'. * gendistlist.sh (EXTRA_DISTFILES): Add `genpartmaplist.sh'.

View file

@ -29,11 +29,15 @@ static int lv_count;
/* Go the string STR and return the number after STR. *P will point /* Go the string STR and return the number after STR. *P will point
at the number. */ at the number. In case STR is not found, *P will be NULL and the
return value will be 0. */
static int static int
grub_lvm_getvalue (char **p, char *str) grub_lvm_getvalue (char **p, char *str)
{ {
*p = grub_strstr (*p, str) + grub_strlen (str); *p = grub_strstr (*p, str);
if (! *p)
return 0;
*p += grub_strlen (str);
return grub_strtoul (*p, NULL, 10); return grub_strtoul (*p, NULL, 10);
} }
@ -44,9 +48,10 @@ grub_lvm_iterate (int (*hook) (const char *name))
for (vg = vg_list; vg; vg = vg->next) for (vg = vg_list; vg; vg = vg->next)
{ {
struct grub_lvm_lv *lv; struct grub_lvm_lv *lv;
for (lv = vg->lvs; lv; lv = lv->next) if (vg->lvs)
if (hook (lv->name)) for (lv = vg->lvs; lv; lv = lv->next)
return 1; if (hook (lv->name))
return 1;
} }
return 0; return 0;
@ -60,13 +65,14 @@ grub_lvm_memberlist (grub_disk_t disk)
grub_disk_memberlist_t list = NULL, tmp; grub_disk_memberlist_t list = NULL, tmp;
struct grub_lvm_pv *pv; struct grub_lvm_pv *pv;
for (pv = lv->vg->pvs; pv; pv = pv->next) if (lv->vg->pvs)
{ for (pv = lv->vg->pvs; pv; pv = pv->next)
tmp = grub_malloc (sizeof (*tmp)); {
tmp->disk = pv->disk; tmp = grub_malloc (sizeof (*tmp));
tmp->next = list; tmp->disk = pv->disk;
list = tmp; tmp->next = list;
} list = tmp;
}
return list; return list;
} }
@ -79,9 +85,10 @@ grub_lvm_open (const char *name, grub_disk_t disk)
struct grub_lvm_lv *lv = NULL; struct grub_lvm_lv *lv = NULL;
for (vg = vg_list; vg; vg = vg->next) for (vg = vg_list; vg; vg = vg->next)
{ {
for (lv = vg->lvs; lv; lv = lv->next) if (vg->lvs)
if (! grub_strcmp (lv->name, name)) for (lv = vg->lvs; lv; lv = lv->next)
break; if (! grub_strcmp (lv->name, name))
break;
if (lv) if (lv)
break; break;
@ -330,141 +337,191 @@ grub_lvm_scan_device (const char *name)
grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1); grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1);
vg->extent_size = grub_lvm_getvalue (&p, "extent_size = "); vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
if (p == NULL)
goto fail2;
vg->lvs = NULL; vg->lvs = NULL;
vg->pvs = NULL; vg->pvs = NULL;
vg->next = vg_list; vg->next = vg_list;
vg_list = vg; vg_list = vg;
p = grub_strstr (p, "physical_volumes {") p = grub_strstr (p, "physical_volumes {");
+ sizeof ("physical_volumes {") - 1; if (p)
/* Add all the pvs to the volume group. */
while (1)
{ {
int s; p += sizeof ("physical_volumes {") - 1;
while (grub_isspace (*p))
p++;
if (*p == '}') /* Add all the pvs to the volume group. */
break; while (1)
{
pv = grub_malloc (sizeof (*pv)); int s;
q = p; while (grub_isspace (*p))
while (*q != ' ') p++;
q++;
if (*p == '}')
s = q - p; break;
pv->name = grub_malloc (s + 1);
grub_memcpy (pv->name, p, s); pv = grub_malloc (sizeof (*pv));
pv->name[s] = '\0'; q = p;
while (*q != ' ')
p = grub_strstr (p, "id = \"") + sizeof("id = \"") - 1; q++;
grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN); s = q - p;
pv->id[GRUB_LVM_ID_STRLEN] = '\0'; pv->name = grub_malloc (s + 1);
grub_memcpy (pv->name, p, s);
pv->start = grub_lvm_getvalue (&p, "pe_start = "); pv->name[s] = '\0';
pv->disk = NULL;
pv->next = vg->pvs; p = grub_strstr (p, "id = \"") + sizeof("id = \"") - 1;
vg->pvs = pv; if (p == NULL)
goto pvs_fail;
p = grub_strchr (p, '}') + 1;
grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN);
pv->id[GRUB_LVM_ID_STRLEN] = '\0';
pv->start = grub_lvm_getvalue (&p, "pe_start = ");
if (p == NULL)
goto pvs_fail;
pv->disk = NULL;
pv->next = vg->pvs;
vg->pvs = pv;
p = grub_strchr (p, '}') + 1;
continue;
pvs_fail:
grub_free (pv->name);
grub_free (pv);
goto fail2;
}
} }
p = grub_strstr (p, "logical_volumes"); p = grub_strstr (p, "logical_volumes");
p += 18; if (p)
/* And add all the lvs to the volume group. */
while (1)
{ {
int s; p += 18;
struct grub_lvm_lv *lv;
struct grub_lvm_segment *seg;
while (grub_isspace (*p)) /* And add all the lvs to the volume group. */
p++; while (1)
if (*p == '}')
break;
lv = grub_malloc (sizeof (*lv));
q = p;
while (*q != ' ')
q++;
s = q - p;
lv->name = grub_malloc (vgname_len + 1 + s + 1);
grub_memcpy (lv->name, vgname, vgname_len);
lv->name[vgname_len] = '-';
grub_memcpy (lv->name + vgname_len + 1, p, s);
lv->name[vgname_len + 1 + s] = '\0';
lv->size = 0;
lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
seg = lv->segments;
for (i = 0; i < lv->segment_count; i++)
{ {
struct grub_lvm_stripe *stripe; int s;
struct grub_lvm_lv *lv;
p = grub_strstr (p, "segment"); struct grub_lvm_segment *seg;
seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = ");
lv->size += seg->extent_count * vg->extent_size;
if (seg->stripe_count != 1) while (grub_isspace (*p))
seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = "); p++;
seg->stripes = grub_malloc (sizeof (*stripe)
* seg->stripe_count);
stripe = seg->stripes;
p = grub_strstr (p, "stripes = [") if (*p == '}')
+ sizeof("stripes = [") - 1; break;
for (j = 0; j < seg->stripe_count; j++) lv = grub_malloc (sizeof (*lv));
q = p;
while (*q != ' ')
q++;
s = q - p;
lv->name = grub_malloc (vgname_len + 1 + s + 1);
grub_memcpy (lv->name, vgname, vgname_len);
lv->name[vgname_len] = '-';
grub_memcpy (lv->name + vgname_len + 1, p, s);
lv->name[vgname_len + 1 + s] = '\0';
lv->size = 0;
lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
if (p == NULL)
goto lvs_fail;
lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
seg = lv->segments;
for (i = 0; i < lv->segment_count; i++)
{ {
char pvname[10]; struct grub_lvm_stripe *stripe;
q = p = grub_strchr (p, '"') + 1; p = grub_strstr (p, "segment");
while (*q != '"') if (p == NULL)
q++; goto lvs_segment_fail;
s = q - p;
grub_memcpy (pvname, p, s);
pvname[s] = '\0';
for (pv = vg->pvs; pv; pv = pv->next) seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
if (p == NULL)
goto lvs_segment_fail;
seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
if (p == NULL)
goto lvs_segment_fail;
seg->stripe_count = grub_lvm_getvalue (&p, "stripe_count = ");
if (p == NULL)
goto lvs_segment_fail;
lv->size += seg->extent_count * vg->extent_size;
if (seg->stripe_count != 1)
seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
seg->stripes = grub_malloc (sizeof (*stripe)
* seg->stripe_count);
stripe = seg->stripes;
p = grub_strstr (p, "stripes = [");
if (p == NULL)
goto lvs_segment_fail2;
p += sizeof("stripes = [") - 1;
for (j = 0; j < seg->stripe_count; j++)
{ {
if (! grub_strcmp (pvname, pv->name)) char pvname[10];
{
stripe->pv = pv; p = grub_strchr (p, '"');
break; if (p == NULL)
} continue;
} q = ++p;
while (*q != '"')
q++;
p = grub_strchr (p, ',') + 1; s = q - p;
stripe->start = grub_strtoul (p, NULL, 10); grub_memcpy (pvname, p, s);
pvname[s] = '\0';
if (vg->pvs)
for (pv = vg->pvs; pv; pv = pv->next)
{
if (! grub_strcmp (pvname, pv->name))
{
stripe->pv = pv;
break;
}
}
stripe->start = grub_lvm_getvalue (&p, ",");
if (p == NULL)
continue;
stripe++;
}
stripe++; seg++;
continue;
lvs_segment_fail2:
grub_free (seg->stripes);
lvs_segment_fail:
goto fail2;
} }
seg++; lv->number = lv_count++;
lv->vg = vg;
lv->next = vg->lvs;
vg->lvs = lv;
p = grub_strchr (p, '}');
if (p == NULL)
goto lvs_fail;
p += 3;
continue;
lvs_fail:
grub_free (lv->name);
grub_free (lv);
goto fail2;
} }
lv->number = lv_count++;
lv->vg = vg;
lv->next = vg->lvs;
vg->lvs = lv;
p = grub_strchr (p, '}') + 3;
} }
} }
else else
@ -474,14 +531,15 @@ grub_lvm_scan_device (const char *name)
/* Match the device we are currently reading from with the right /* Match the device we are currently reading from with the right
PV. */ PV. */
for (pv = vg->pvs; pv; pv = pv->next) if (vg->pvs)
{ for (pv = vg->pvs; pv; pv = pv->next)
if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN)) {
{ if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN))
pv->disk = grub_disk_open (name); {
break; pv->disk = grub_disk_open (name);
} break;
} }
}
fail2: fail2:
grub_free (metadatabuf); grub_free (metadatabuf);