tags 474931 patch thanks On Tue, Apr 08, 2008 at 02:20:25AM +0300, Sami Liedes wrote: > (gdb) print q > $2 = 0x66b5b4 " LVM2 x[5A%r0N*>\001"
This could mean that your LVM is corrupt, or that our LVM logic is incomplete. Unfortunately I don't have the time to review that, but I improved the parser to make it more robust, failing safely when problems like this one arise. This fixes the issue at hand (using grub-probe in update-grub). Please, could you try the attached patch and report your results? Thanks -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.)
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/disk/lvm.c ./disk/lvm.c --- ../grub2/disk/lvm.c 2008-02-09 11:49:29.000000000 +0100 +++ ./disk/lvm.c 2008-04-10 10:06:00.000000000 +0200 @@ -29,11 +29,15 @@ static int lv_count; /* 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 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); } @@ -44,6 +48,7 @@ grub_lvm_iterate (int (*hook) (const cha for (vg = vg_list; vg; vg = vg->next) { struct grub_lvm_lv *lv; +if (vg->lvs) for (lv = vg->lvs; lv; lv = lv->next) if (hook (lv->name)) return 1; @@ -60,6 +65,7 @@ grub_lvm_memberlist (grub_disk_t disk) grub_disk_memberlist_t list = NULL, tmp; struct grub_lvm_pv *pv; + if (lv->vg->pvs) for (pv = lv->vg->pvs; pv; pv = pv->next) { tmp = grub_malloc (sizeof (*tmp)); @@ -79,6 +85,7 @@ grub_lvm_open (const char *name, grub_di struct grub_lvm_lv *lv = NULL; for (vg = vg_list; vg; vg = vg->next) { +if (vg->lvs) for (lv = vg->lvs; lv; lv = lv->next) if (! grub_strcmp (lv->name, name)) break; @@ -330,14 +337,19 @@ grub_lvm_scan_device (const char *name) grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1); vg->extent_size = grub_lvm_getvalue (&p, "extent_size = "); + if (p == NULL) + goto fail2; vg->lvs = NULL; vg->pvs = NULL; vg->next = vg_list; vg_list = vg; - p = grub_strstr (p, "physical_volumes {") - + sizeof ("physical_volumes {") - 1; + p = grub_strstr (p, "physical_volumes {"); + if (p) + { + + p += sizeof ("physical_volumes {") - 1; /* Add all the pvs to the volume group. */ while (1) @@ -360,19 +372,33 @@ grub_lvm_scan_device (const char *name) pv->name[s] = '\0'; p = grub_strstr (p, "id = \"") + sizeof("id = \"") - 1; + if (p == NULL) + goto pvs_fail; 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"); +if (p) +{ p += 18; /* And add all the lvs to the volume group. */ @@ -404,6 +430,8 @@ grub_lvm_scan_device (const char *name) 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; @@ -412,10 +440,18 @@ grub_lvm_scan_device (const char *name) struct grub_lvm_stripe *stripe; p = grub_strstr (p, "segment"); + if (p == NULL) + goto lvs_segment_fail; 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; @@ -426,14 +462,19 @@ grub_lvm_scan_device (const char *name) * seg->stripe_count); stripe = seg->stripes; - p = grub_strstr (p, "stripes = [") - + sizeof("stripes = [") - 1; + p = grub_strstr (p, "stripes = ["); + if (p == NULL) + goto lvs_segment_fail2; + p += sizeof("stripes = [") - 1; for (j = 0; j < seg->stripe_count; j++) { char pvname[10]; - q = p = grub_strchr (p, '"') + 1; + p = grub_strchr (p, '"'); + if (p == NULL) + continue; + q = ++p; while (*q != '"') q++; @@ -441,6 +482,7 @@ grub_lvm_scan_device (const char *name) 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)) @@ -450,13 +492,20 @@ grub_lvm_scan_device (const char *name) } } - p = grub_strchr (p, ',') + 1; - stripe->start = grub_strtoul (p, NULL, 10); + stripe->start = grub_lvm_getvalue (&p, ","); + if (p == NULL) + continue; stripe++; } seg++; + + continue; + lvs_segment_fail2: + grub_free (seg->stripes); + lvs_segment_fail: + goto fail2; } lv->number = lv_count++; @@ -464,8 +513,18 @@ grub_lvm_scan_device (const char *name) lv->next = vg->lvs; vg->lvs = lv; - p = grub_strchr (p, '}') + 3; + p = grub_strchr (p, '}'); + if (p == NULL) + goto lvs_fail; + p += 3; + + continue; + lvs_fail: + grub_free (lv->name); + grub_free (lv); + goto fail2; } +} } else { @@ -474,6 +533,7 @@ grub_lvm_scan_device (const char *name) /* Match the device we are currently reading from with the right PV. */ + if (vg->pvs) for (pv = vg->pvs; pv; pv = pv->next) { if (! grub_memcmp (pv->id, pv_id, GRUB_LVM_ID_STRLEN))