mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 15:44:20 +00:00 
			
		
		
		
	 16f7455b04
			
		
	
	
		16f7455b04
		
	
	
	
	
		
			
			* grub-core/commands/parttool.c: Fix grammar. * grub-core/disk/ldm.c: Use consistent capitalisation for "LDM Embedding Partition".
		
			
				
	
	
		
			1053 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1053 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | ||
|  *  GRUB  --  GRand Unified Bootloader
 | ||
|  *  Copyright (C) 2006,2007,2008,2009,2011  Free Software Foundation, Inc.
 | ||
|  *
 | ||
|  *  GRUB is free software: you can redistribute it and/or modify
 | ||
|  *  it under the terms of the GNU General Public License as published by
 | ||
|  *  the Free Software Foundation, either version 3 of the License, or
 | ||
|  *  (at your option) any later version.
 | ||
|  *
 | ||
|  *  GRUB is distributed in the hope that it will be useful,
 | ||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||
|  *  GNU General Public License for more details.
 | ||
|  *
 | ||
|  *  You should have received a copy of the GNU General Public License
 | ||
|  *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 | ||
|  */
 | ||
| 
 | ||
| #include <grub/dl.h>
 | ||
| #include <grub/disk.h>
 | ||
| #include <grub/mm.h>
 | ||
| #include <grub/err.h>
 | ||
| #include <grub/misc.h>
 | ||
| #include <grub/diskfilter.h>
 | ||
| #include <grub/msdos_partition.h>
 | ||
| #include <grub/gpt_partition.h>
 | ||
| #include <grub/i18n.h>
 | ||
| 
 | ||
| #ifdef GRUB_UTIL
 | ||
| #include <grub/emu/misc.h>
 | ||
| #include <grub/emu/hostdisk.h>
 | ||
| #endif
 | ||
| 
 | ||
| GRUB_MOD_LICENSE ("GPLv3+");
 | ||
| 
 | ||
| #define LDM_GUID_STRLEN 64
 | ||
| #define LDM_NAME_STRLEN 32
 | ||
| 
 | ||
| typedef grub_uint8_t *grub_ldm_id_t;
 | ||
| 
 | ||
| enum { STRIPE = 1, SPANNED = 2, RAID5 = 3 };
 | ||
| 
 | ||
| #define LDM_LABEL_SECTOR 6
 | ||
| struct grub_ldm_vblk {
 | ||
|   char magic[4];
 | ||
|   grub_uint8_t unused1[12];
 | ||
|   grub_uint16_t update_status;
 | ||
|   grub_uint8_t flags;
 | ||
|   grub_uint8_t type;
 | ||
|   grub_uint32_t unused2;
 | ||
|   grub_uint8_t dynamic[104];
 | ||
| } GRUB_PACKED;
 | ||
| #define LDM_VBLK_MAGIC "VBLK"
 | ||
| 
 | ||
| enum
 | ||
|   {
 | ||
|     STATUS_CONSISTENT = 0,
 | ||
|     STATUS_STILL_ACTIVE = 1,
 | ||
|     STATUS_NOT_ACTIVE_YET = 2
 | ||
|   };
 | ||
| 
 | ||
| enum
 | ||
|   {
 | ||
|     ENTRY_COMPONENT = 0x32,
 | ||
|     ENTRY_PARTITION = 0x33,
 | ||
|     ENTRY_DISK = 0x34,
 | ||
|     ENTRY_VOLUME = 0x51,
 | ||
|   };
 | ||
| 
 | ||
| struct grub_ldm_label
 | ||
| {
 | ||
|   char magic[8];
 | ||
|   grub_uint32_t unused1;
 | ||
|   grub_uint16_t ver_major;
 | ||
|   grub_uint16_t ver_minor;
 | ||
|   grub_uint8_t unused2[32];
 | ||
|   char disk_guid[LDM_GUID_STRLEN];
 | ||
|   char host_guid[LDM_GUID_STRLEN];
 | ||
|   char group_guid[LDM_GUID_STRLEN];
 | ||
|   char group_name[LDM_NAME_STRLEN];
 | ||
|   grub_uint8_t unused3[11];
 | ||
|   grub_uint64_t pv_start;
 | ||
|   grub_uint64_t pv_size;
 | ||
|   grub_uint64_t config_start;
 | ||
|   grub_uint64_t config_size;
 | ||
| } GRUB_PACKED;
 | ||
| 
 | ||
| 
 | ||
| #define LDM_MAGIC "PRIVHEAD"
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| static inline grub_uint64_t
 | ||
| read_int (grub_uint8_t *in, grub_size_t s)
 | ||
| {
 | ||
|   grub_uint8_t *ptr2;
 | ||
|   grub_uint64_t ret;
 | ||
|   ret = 0;
 | ||
|   for (ptr2 = in; ptr2 < in + s; ptr2++)
 | ||
|     {
 | ||
|       ret <<= 8;
 | ||
|       ret |= *ptr2;
 | ||
|     }
 | ||
|   return ret;
 | ||
| }
 | ||
| 
 | ||
| static int
 | ||
| check_ldm_partition (grub_disk_t disk __attribute__ ((unused)), const grub_partition_t p, void *data)
 | ||
| {
 | ||
|   int *has_ldm = data;
 | ||
| 
 | ||
|   if (p->number >= 4)
 | ||
|     return 1;
 | ||
|   if (p->msdostype == GRUB_PC_PARTITION_TYPE_LDM)
 | ||
|     {
 | ||
|       *has_ldm = 1;
 | ||
|       return 1;
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| static int
 | ||
| msdos_has_ldm_partition (grub_disk_t dsk)
 | ||
| {
 | ||
|   grub_err_t err;
 | ||
|   int has_ldm = 0;
 | ||
| 
 | ||
|   err = grub_partition_msdos_iterate (dsk, check_ldm_partition, &has_ldm);
 | ||
|   if (err)
 | ||
|     {
 | ||
|       grub_errno = GRUB_ERR_NONE;
 | ||
|       return 0;
 | ||
|     }
 | ||
| 
 | ||
|   return has_ldm;
 | ||
| }
 | ||
| 
 | ||
| static const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
 | ||
| 
 | ||
| /* Helper for gpt_ldm_sector.  */
 | ||
| static int
 | ||
| gpt_ldm_sector_iter (grub_disk_t disk, const grub_partition_t p, void *data)
 | ||
| {
 | ||
|   grub_disk_addr_t *sector = data;
 | ||
|   struct grub_gpt_partentry gptdata;
 | ||
|   grub_partition_t p2;
 | ||
| 
 | ||
|   p2 = disk->partition;
 | ||
|   disk->partition = p->parent;
 | ||
|   if (grub_disk_read (disk, p->offset, p->index,
 | ||
| 		      sizeof (gptdata), &gptdata))
 | ||
|     {
 | ||
|       disk->partition = p2;
 | ||
|       return 0;
 | ||
|     }
 | ||
|   disk->partition = p2;
 | ||
| 
 | ||
|   if (! grub_memcmp (&gptdata.type, &ldm_type, 16))
 | ||
|     {
 | ||
|       *sector = p->start + p->len - 1;
 | ||
|       return 1;
 | ||
|     }
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| static grub_disk_addr_t
 | ||
| gpt_ldm_sector (grub_disk_t dsk)
 | ||
| {
 | ||
|   grub_disk_addr_t sector = 0;
 | ||
|   grub_err_t err;
 | ||
| 
 | ||
|   err = grub_gpt_partition_map_iterate (dsk, gpt_ldm_sector_iter, §or);
 | ||
|   if (err)
 | ||
|     {
 | ||
|       grub_errno = GRUB_ERR_NONE;
 | ||
|       return 0;
 | ||
|     }
 | ||
|   return sector;
 | ||
| }
 | ||
| 
 | ||
| static struct grub_diskfilter_vg *
 | ||
| make_vg (grub_disk_t disk,
 | ||
| 	 const struct grub_ldm_label *label)
 | ||
| {
 | ||
|   grub_disk_addr_t startsec, endsec, cursec;
 | ||
|   struct grub_diskfilter_vg *vg;
 | ||
|   grub_err_t err;
 | ||
| 
 | ||
|   /* First time we see this volume group. We've to create the
 | ||
|      whole volume group structure. */
 | ||
|   vg = grub_malloc (sizeof (*vg));
 | ||
|   if (! vg)
 | ||
|     return NULL;
 | ||
|   vg->extent_size = 1;
 | ||
|   vg->name = grub_malloc (LDM_NAME_STRLEN + 1);
 | ||
|   vg->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
 | ||
|   if (! vg->uuid || !vg->name)
 | ||
|     {
 | ||
|       grub_free (vg->uuid);
 | ||
|       grub_free (vg->name);
 | ||
|       return NULL;
 | ||
|     }
 | ||
|   grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN);
 | ||
|   grub_memcpy (vg->name, label->group_name, LDM_NAME_STRLEN);
 | ||
|   vg->name[LDM_NAME_STRLEN] = 0;
 | ||
|   vg->uuid[LDM_GUID_STRLEN] = 0;
 | ||
|   vg->uuid_len = grub_strlen (vg->uuid);
 | ||
| 
 | ||
|   vg->lvs = NULL;
 | ||
|   vg->pvs = NULL;
 | ||
| 
 | ||
|   startsec = grub_be_to_cpu64 (label->config_start);
 | ||
|   endsec = startsec + grub_be_to_cpu64 (label->config_size);
 | ||
| 
 | ||
|   /* First find disks.  */
 | ||
|   for (cursec = startsec + 0x12; cursec < endsec; cursec++)
 | ||
|     {
 | ||
|       struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
 | ||
| 				/ sizeof (struct grub_ldm_vblk)];
 | ||
|       unsigned i;
 | ||
|       err = grub_disk_read (disk, cursec, 0,
 | ||
| 			    sizeof(vblk), &vblk);
 | ||
|       if (err)
 | ||
| 	goto fail2;
 | ||
| 
 | ||
|       for (i = 0; i < ARRAY_SIZE (vblk); i++)
 | ||
| 	{
 | ||
| 	  struct grub_diskfilter_pv *pv;
 | ||
| 	  grub_uint8_t *ptr;
 | ||
| 	  if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
 | ||
| 			   sizeof (vblk[i].magic)) != 0)
 | ||
| 	    continue;
 | ||
| 	  if (grub_be_to_cpu16 (vblk[i].update_status)
 | ||
| 	      != STATUS_CONSISTENT
 | ||
| 	      && grub_be_to_cpu16 (vblk[i].update_status)
 | ||
| 	      != STATUS_STILL_ACTIVE)
 | ||
| 	    continue;
 | ||
| 	  if (vblk[i].type != ENTRY_DISK)
 | ||
| 	    continue;
 | ||
| 	  pv = grub_zalloc (sizeof (*pv));
 | ||
| 	  if (!pv)
 | ||
| 	    goto fail2;
 | ||
| 
 | ||
| 	  pv->disk = 0;
 | ||
| 	  ptr = vblk[i].dynamic;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic
 | ||
| 	      + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (pv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  pv->internal_id = grub_malloc (ptr[0] + 2);
 | ||
| 	  if (!pv->internal_id)
 | ||
| 	    {
 | ||
| 	      grub_free (pv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  grub_memcpy (pv->internal_id, ptr, (grub_size_t) ptr[0] + 1);
 | ||
| 	  pv->internal_id[(grub_size_t) ptr[0] + 1] = 0;
 | ||
| 	  
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic
 | ||
| 	      + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (pv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  /* ptr = name.  */
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr + *ptr + 1
 | ||
| 	      >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (pv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  pv->id.uuidlen = *ptr;
 | ||
| 	  pv->id.uuid = grub_malloc (pv->id.uuidlen + 1);
 | ||
| 	  grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
 | ||
| 	  pv->id.uuid[pv->id.uuidlen] = 0;
 | ||
| 
 | ||
| 	  pv->next = vg->pvs;
 | ||
| 	  vg->pvs = pv;
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   /* Then find LVs.  */
 | ||
|   for (cursec = startsec + 0x12; cursec < endsec; cursec++)
 | ||
|     {
 | ||
|       struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
 | ||
| 				/ sizeof (struct grub_ldm_vblk)];
 | ||
|       unsigned i;
 | ||
|       err = grub_disk_read (disk, cursec, 0,
 | ||
| 			    sizeof(vblk), &vblk);
 | ||
|       if (err)
 | ||
| 	goto fail2;
 | ||
| 
 | ||
|       for (i = 0; i < ARRAY_SIZE (vblk); i++)
 | ||
| 	{
 | ||
| 	  struct grub_diskfilter_lv *lv;
 | ||
| 	  grub_uint8_t *ptr;
 | ||
| 	  if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
 | ||
| 			   sizeof (vblk[i].magic)) != 0)
 | ||
| 	    continue;
 | ||
| 	  if (grub_be_to_cpu16 (vblk[i].update_status)
 | ||
| 	      != STATUS_CONSISTENT
 | ||
| 	      && grub_be_to_cpu16 (vblk[i].update_status)
 | ||
| 	      != STATUS_STILL_ACTIVE)
 | ||
| 	    continue;
 | ||
| 	  if (vblk[i].type != ENTRY_VOLUME)
 | ||
| 	    continue;
 | ||
| 	  lv = grub_zalloc (sizeof (*lv));
 | ||
| 	  if (!lv)
 | ||
| 	    goto fail2;
 | ||
| 
 | ||
| 	  lv->vg = vg;
 | ||
| 	  lv->segment_count = 1;
 | ||
| 	  lv->segment_alloc = 1;
 | ||
| 	  lv->visible = 1;
 | ||
| 	  lv->segments = grub_zalloc (sizeof (*lv->segments));
 | ||
| 	  if (!lv->segments)
 | ||
| 	    goto fail2;
 | ||
| 	  lv->segments->start_extent = 0;
 | ||
| 	  lv->segments->type = GRUB_DISKFILTER_MIRROR;
 | ||
| 	  lv->segments->node_count = 0;
 | ||
| 	  lv->segments->node_alloc = 8;
 | ||
| 	  lv->segments->nodes = grub_zalloc (sizeof (*lv->segments->nodes)
 | ||
| 					     * lv->segments->node_alloc);
 | ||
| 	  if (!lv->segments->nodes)
 | ||
| 	    goto fail2;
 | ||
| 	  ptr = vblk[i].dynamic;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic
 | ||
| 	      + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  lv->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
 | ||
| 	  if (!lv->internal_id)
 | ||
| 	    {
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  grub_memcpy (lv->internal_id, ptr, ptr[0] + 1);
 | ||
| 	  lv->internal_id[ptr[0] + 1] = 0;
 | ||
| 
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic
 | ||
| 	      + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  lv->name = grub_malloc (*ptr + 1);
 | ||
| 	  if (!lv->name)
 | ||
| 	    {
 | ||
| 	      grub_free (lv->internal_id);
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  grub_memcpy (lv->name, ptr + 1, *ptr);
 | ||
| 	  lv->name[*ptr] = 0;
 | ||
| 	  lv->fullname = grub_xasprintf ("ldm/%s/%s",
 | ||
| 					 vg->uuid, lv->name);
 | ||
| 	  if (!lv->fullname)
 | ||
| 	    {
 | ||
| 	      grub_free (lv->internal_id);
 | ||
| 	      grub_free (lv->name);
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr + *ptr + 1
 | ||
| 	      >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (lv->internal_id);
 | ||
| 	      grub_free (lv->name);
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  /* ptr = volume type.  */
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (lv->internal_id);
 | ||
| 	      grub_free (lv->name);
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  /* ptr = flags.  */
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (lv->internal_id);
 | ||
| 	      grub_free (lv->name);
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 
 | ||
| 	  /* Skip state, type, unknown, volume number, zeros, flags. */
 | ||
| 	  ptr += 14 + 1 + 1 + 1 + 3 + 1;
 | ||
| 	  /* ptr = number of children.  */
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (lv->internal_id);
 | ||
| 	      grub_free (lv->name);
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (lv->internal_id);
 | ||
| 	      grub_free (lv->name);
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 
 | ||
| 	  /* Skip 2 more fields.  */
 | ||
| 	  ptr += 8 + 8;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
 | ||
| 	      || ptr + *ptr + 1>= vblk[i].dynamic
 | ||
| 	      + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (lv->internal_id);
 | ||
| 	      grub_free (lv->name);
 | ||
| 	      grub_free (lv);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  lv->size = read_int (ptr + 1, *ptr);
 | ||
| 	  lv->segments->extent_count = lv->size;
 | ||
| 
 | ||
| 	  lv->next = vg->lvs;
 | ||
| 	  vg->lvs = lv;
 | ||
| 	}
 | ||
|     }
 | ||
| 
 | ||
|   /* Now the components.  */
 | ||
|   for (cursec = startsec + 0x12; cursec < endsec; cursec++)
 | ||
|     {
 | ||
|       struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
 | ||
| 				/ sizeof (struct grub_ldm_vblk)];
 | ||
|       unsigned i;
 | ||
|       err = grub_disk_read (disk, cursec, 0,
 | ||
| 			    sizeof(vblk), &vblk);
 | ||
|       if (err)
 | ||
| 	goto fail2;
 | ||
| 
 | ||
|       for (i = 0; i < ARRAY_SIZE (vblk); i++)
 | ||
| 	{
 | ||
| 	  struct grub_diskfilter_lv *comp;
 | ||
| 	  struct grub_diskfilter_lv *lv;
 | ||
| 	  grub_uint8_t type;
 | ||
| 
 | ||
| 	  grub_uint8_t *ptr;
 | ||
| 	  if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
 | ||
| 			   sizeof (vblk[i].magic)) != 0)
 | ||
| 	    continue;
 | ||
| 	  if (grub_be_to_cpu16 (vblk[i].update_status)
 | ||
| 	      != STATUS_CONSISTENT
 | ||
| 	      && grub_be_to_cpu16 (vblk[i].update_status)
 | ||
| 	      != STATUS_STILL_ACTIVE)
 | ||
| 	    continue;
 | ||
| 	  if (vblk[i].type != ENTRY_COMPONENT)
 | ||
| 	    continue;
 | ||
| 	  comp = grub_zalloc (sizeof (*comp));
 | ||
| 	  if (!comp)
 | ||
| 	    goto fail2;
 | ||
| 	  comp->visible = 0;
 | ||
| 	  comp->name = 0;
 | ||
| 	  comp->fullname = 0;
 | ||
| 
 | ||
| 	  ptr = vblk[i].dynamic;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  comp->internal_id = grub_malloc ((grub_size_t) ptr[0] + 2);
 | ||
| 	  if (!comp->internal_id)
 | ||
| 	    {
 | ||
| 	      grub_free (comp);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  grub_memcpy (comp->internal_id, ptr, ptr[0] + 1);
 | ||
| 	  comp->internal_id[ptr[0] + 1] = 0;
 | ||
| 
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (comp->internal_id);
 | ||
| 	      grub_free (comp);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  /* ptr = name.  */
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (comp->internal_id);
 | ||
| 	      grub_free (comp);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  /* ptr = state.  */
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  type = *ptr++;
 | ||
| 	  /* skip zeros.  */
 | ||
| 	  ptr += 4;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (comp->internal_id);
 | ||
| 	      grub_free (comp);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 
 | ||
| 	  /* ptr = number of children. */
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (comp->internal_id);
 | ||
| 	      grub_free (comp);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  ptr += 8 + 8;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic
 | ||
| 	      + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      grub_free (comp->internal_id);
 | ||
| 	      grub_free (comp);
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  for (lv = vg->lvs; lv; lv = lv->next)
 | ||
| 	    {
 | ||
| 	      if (lv->internal_id[0] == ptr[0]
 | ||
| 		  && grub_memcmp (lv->internal_id + 1, ptr + 1, ptr[0]) == 0)
 | ||
| 		break;
 | ||
| 	    }
 | ||
| 	  if (!lv)
 | ||
| 	    {
 | ||
| 	      grub_free (comp->internal_id);
 | ||
| 	      grub_free (comp);
 | ||
| 	      continue;
 | ||
| 	    }
 | ||
| 	  comp->size = lv->size;
 | ||
| 	  if (type == SPANNED)
 | ||
| 	    {
 | ||
| 	      comp->segment_alloc = 8;
 | ||
| 	      comp->segment_count = 0;
 | ||
| 	      comp->segments = grub_malloc (sizeof (*comp->segments)
 | ||
| 					    * comp->segment_alloc);
 | ||
| 	      if (!comp->segments)
 | ||
| 		goto fail2;
 | ||
| 	    }
 | ||
| 	  else
 | ||
| 	    {
 | ||
| 	      comp->segment_alloc = 1;
 | ||
| 	      comp->segment_count = 1;
 | ||
| 	      comp->segments = grub_malloc (sizeof (*comp->segments));
 | ||
| 	      if (!comp->segments)
 | ||
| 		goto fail2;
 | ||
| 	      comp->segments->start_extent = 0;
 | ||
| 	      comp->segments->extent_count = lv->size;
 | ||
| 	      comp->segments->layout = 0;
 | ||
| 	      if (type == STRIPE)
 | ||
| 		comp->segments->type = GRUB_DISKFILTER_STRIPED;
 | ||
| 	      else if (type == RAID5)
 | ||
| 		{
 | ||
| 		  comp->segments->type = GRUB_DISKFILTER_RAID5;
 | ||
| 		  comp->segments->layout = GRUB_RAID_LAYOUT_SYMMETRIC_MASK;
 | ||
| 		}
 | ||
| 	      else
 | ||
| 		goto fail2;
 | ||
| 	      ptr += *ptr + 1;
 | ||
| 	      ptr++;
 | ||
| 	      if (!(vblk[i].flags & 0x10))
 | ||
| 		goto fail2;
 | ||
| 	      if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
 | ||
| 		  || ptr + *ptr + 1 >= vblk[i].dynamic
 | ||
| 		  + sizeof (vblk[i].dynamic))
 | ||
| 		{
 | ||
| 		  grub_free (comp->internal_id);
 | ||
| 		  grub_free (comp);
 | ||
| 		  goto fail2;
 | ||
| 		}
 | ||
| 	      comp->segments->stripe_size = read_int (ptr + 1, *ptr);
 | ||
| 	      ptr += *ptr + 1;
 | ||
| 	      if (ptr + *ptr + 1 >= vblk[i].dynamic
 | ||
| 		  + sizeof (vblk[i].dynamic))
 | ||
| 		{
 | ||
| 		  grub_free (comp->internal_id);
 | ||
| 		  grub_free (comp);
 | ||
| 		  goto fail2;
 | ||
| 		}
 | ||
| 	      comp->segments->node_count = read_int (ptr + 1, *ptr);
 | ||
| 	      comp->segments->node_alloc = comp->segments->node_count;
 | ||
| 	      comp->segments->nodes = grub_zalloc (sizeof (*comp->segments->nodes)
 | ||
| 						   * comp->segments->node_alloc);
 | ||
| 	      if (!lv->segments->nodes)
 | ||
| 		goto fail2;
 | ||
| 	    }
 | ||
| 
 | ||
| 	  if (lv->segments->node_alloc == lv->segments->node_count)
 | ||
| 	    {
 | ||
| 	      void *t;
 | ||
| 	      lv->segments->node_alloc *= 2; 
 | ||
| 	      t = grub_realloc (lv->segments->nodes,
 | ||
| 				sizeof (*lv->segments->nodes)
 | ||
| 				* lv->segments->node_alloc);
 | ||
| 	      if (!t)
 | ||
| 		goto fail2;
 | ||
| 	      lv->segments->nodes = t;
 | ||
| 	    }
 | ||
| 	  lv->segments->nodes[lv->segments->node_count].pv = 0;
 | ||
| 	  lv->segments->nodes[lv->segments->node_count].start = 0;
 | ||
| 	  lv->segments->nodes[lv->segments->node_count++].lv = comp;
 | ||
| 	  comp->next = vg->lvs;
 | ||
| 	  vg->lvs = comp;
 | ||
| 	}
 | ||
|     }
 | ||
|   /* Partitions.  */
 | ||
|   for (cursec = startsec + 0x12; cursec < endsec; cursec++)
 | ||
|     {
 | ||
|       struct grub_ldm_vblk vblk[GRUB_DISK_SECTOR_SIZE
 | ||
| 				/ sizeof (struct grub_ldm_vblk)];
 | ||
|       unsigned i;
 | ||
|       err = grub_disk_read (disk, cursec, 0,
 | ||
| 			    sizeof(vblk), &vblk);
 | ||
|       if (err)
 | ||
| 	goto fail2;
 | ||
| 
 | ||
|       for (i = 0; i < ARRAY_SIZE (vblk); i++)
 | ||
| 	{
 | ||
| 	  struct grub_diskfilter_lv *comp;
 | ||
| 	  struct grub_diskfilter_node part;
 | ||
| 	  grub_disk_addr_t start, size;
 | ||
| 
 | ||
| 	  grub_uint8_t *ptr;
 | ||
| 	  part.name = 0;
 | ||
| 	  if (grub_memcmp (vblk[i].magic, LDM_VBLK_MAGIC,
 | ||
| 			   sizeof (vblk[i].magic)) != 0)
 | ||
| 	    continue;
 | ||
| 	  if (grub_be_to_cpu16 (vblk[i].update_status)
 | ||
| 	      != STATUS_CONSISTENT
 | ||
| 	      && grub_be_to_cpu16 (vblk[i].update_status)
 | ||
| 	      != STATUS_STILL_ACTIVE)
 | ||
| 	    continue;
 | ||
| 	  if (vblk[i].type != ENTRY_PARTITION)
 | ||
| 	    continue;
 | ||
| 	  part.lv = 0;
 | ||
| 	  part.pv = 0;
 | ||
| 
 | ||
| 	  ptr = vblk[i].dynamic;
 | ||
| 	  if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  /* ID */
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  /* ptr = name.  */
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 
 | ||
| 	  /* skip zeros and logcommit id.  */
 | ||
| 	  ptr += 4 + 8;
 | ||
| 	  if (ptr + 16 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  part.start = read_int (ptr, 8);
 | ||
| 	  start = read_int (ptr + 8, 8);
 | ||
| 	  ptr += 16;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
 | ||
| 	      || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  size = read_int (ptr + 1, *ptr);
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
 | ||
| 	      || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 
 | ||
| 	  for (comp = vg->lvs; comp; comp = comp->next)
 | ||
| 	    if (comp->internal_id[0] == ptr[0]
 | ||
| 		&& grub_memcmp (ptr + 1, comp->internal_id + 1,
 | ||
| 				comp->internal_id[0]) == 0)
 | ||
| 	      goto out;
 | ||
| 	  continue;
 | ||
| 	out:
 | ||
| 	  if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
 | ||
| 	      || ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
 | ||
| 	    {
 | ||
| 	      goto fail2;
 | ||
| 	    }
 | ||
| 	  ptr += *ptr + 1;
 | ||
| 	  struct grub_diskfilter_pv *pv;
 | ||
| 	  for (pv = vg->pvs; pv; pv = pv->next)
 | ||
| 	    if (pv->internal_id[0] == ptr[0]
 | ||
| 		&& grub_memcmp (pv->internal_id + 1, ptr + 1, ptr[0]) == 0)
 | ||
| 	      part.pv = pv;
 | ||
| 
 | ||
| 	  if (comp->segment_alloc == 1)
 | ||
| 	    {
 | ||
| 	      unsigned node_index;
 | ||
| 	      ptr += *ptr + 1;
 | ||
| 	      if (ptr + *ptr + 1 >= vblk[i].dynamic
 | ||
| 		  + sizeof (vblk[i].dynamic))
 | ||
| 		{
 | ||
| 		  goto fail2;
 | ||
| 		}
 | ||
| 	      node_index = read_int (ptr + 1, *ptr);
 | ||
| 	      if (node_index < comp->segments->node_count)
 | ||
| 		comp->segments->nodes[node_index] = part;
 | ||
| 	    }
 | ||
| 	  else
 | ||
| 	    {
 | ||
| 	      if (comp->segment_alloc == comp->segment_count)
 | ||
| 		{
 | ||
| 		  void *t;
 | ||
| 		  comp->segment_alloc *= 2;
 | ||
| 		  t = grub_realloc (comp->segments,
 | ||
| 				    comp->segment_alloc
 | ||
| 				    * sizeof (*comp->segments));
 | ||
| 		  if (!t)
 | ||
| 		    goto fail2;
 | ||
| 		  comp->segments = t;
 | ||
| 		}
 | ||
| 	      comp->segments[comp->segment_count].start_extent = start;
 | ||
| 	      comp->segments[comp->segment_count].extent_count = size;
 | ||
| 	      comp->segments[comp->segment_count].type = GRUB_DISKFILTER_STRIPED;
 | ||
| 	      comp->segments[comp->segment_count].node_count = 1;
 | ||
| 	      comp->segments[comp->segment_count].node_alloc = 1;
 | ||
| 	      comp->segments[comp->segment_count].nodes
 | ||
| 		= grub_malloc (sizeof (*comp->segments[comp->segment_count].nodes));
 | ||
| 	      if (!comp->segments[comp->segment_count].nodes)
 | ||
| 		goto fail2;
 | ||
| 	      comp->segments[comp->segment_count].nodes[0] = part;
 | ||
| 	      comp->segment_count++;
 | ||
| 	    }
 | ||
| 	}
 | ||
|     }
 | ||
|   if (grub_diskfilter_vg_register (vg))
 | ||
|     goto fail2;
 | ||
|   return vg;
 | ||
|  fail2:
 | ||
|   {
 | ||
|     struct grub_diskfilter_lv *lv, *next_lv;
 | ||
|     struct grub_diskfilter_pv *pv, *next_pv;
 | ||
|     for (lv = vg->lvs; lv; lv = next_lv)
 | ||
|       {
 | ||
| 	unsigned i;
 | ||
| 	for (i = 0; i < lv->segment_count; i++)
 | ||
| 	  grub_free (lv->segments[i].nodes);
 | ||
| 
 | ||
| 	next_lv = lv->next;
 | ||
| 	grub_free (lv->segments);
 | ||
| 	grub_free (lv->internal_id);
 | ||
| 	grub_free (lv->name);
 | ||
| 	grub_free (lv->fullname);
 | ||
| 	grub_free (lv);
 | ||
|       }
 | ||
|     for (pv = vg->pvs; pv; pv = next_pv)
 | ||
|       {
 | ||
| 	next_pv = pv->next;
 | ||
| 	grub_free (pv->id.uuid);
 | ||
| 	grub_free (pv);
 | ||
|       }
 | ||
|   }
 | ||
|   grub_free (vg->uuid);
 | ||
|   grub_free (vg);
 | ||
|   return NULL;
 | ||
| }
 | ||
| 
 | ||
| static struct grub_diskfilter_vg * 
 | ||
| grub_ldm_detect (grub_disk_t disk,
 | ||
| 		 struct grub_diskfilter_pv_id *id,
 | ||
| 		 grub_disk_addr_t *start_sector)
 | ||
| {
 | ||
|   grub_err_t err;
 | ||
|   struct grub_ldm_label label;
 | ||
|   struct grub_diskfilter_vg *vg;
 | ||
| 
 | ||
| #ifdef GRUB_UTIL
 | ||
|   grub_util_info ("scanning %s for LDM", disk->name);
 | ||
| #endif
 | ||
| 
 | ||
|   {
 | ||
|     int i;
 | ||
|     int has_ldm = msdos_has_ldm_partition (disk);
 | ||
|     for (i = 0; i < 3; i++)
 | ||
|       {
 | ||
| 	grub_disk_addr_t sector = LDM_LABEL_SECTOR;
 | ||
| 	switch (i)
 | ||
| 	  {
 | ||
| 	  case 0:
 | ||
| 	    if (!has_ldm)
 | ||
| 	      continue;
 | ||
| 	    sector = LDM_LABEL_SECTOR;
 | ||
| 	    break;
 | ||
| 	  case 1:
 | ||
| 	    /* LDM is never inside a partition.  */
 | ||
| 	    if (!has_ldm || disk->partition)
 | ||
| 	      continue;
 | ||
| 	    sector = grub_disk_get_size (disk);
 | ||
| 	    if (sector == GRUB_DISK_SIZE_UNKNOWN)
 | ||
| 	      continue;
 | ||
| 	    sector--;
 | ||
| 	    break;
 | ||
| 	    /* FIXME: try the third copy.  */
 | ||
| 	  case 2:
 | ||
| 	    sector = gpt_ldm_sector (disk);
 | ||
| 	    if (!sector)
 | ||
| 	      continue;
 | ||
| 	    break;
 | ||
| 	  }
 | ||
| 	err = grub_disk_read (disk, sector, 0,
 | ||
| 			      sizeof(label), &label);
 | ||
| 	if (err)
 | ||
| 	  return NULL;
 | ||
| 	if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0
 | ||
| 	    && grub_be_to_cpu16 (label.ver_major) == 0x02
 | ||
| 	    && grub_be_to_cpu16 (label.ver_minor) >= 0x0b
 | ||
| 	    && grub_be_to_cpu16 (label.ver_minor) <= 0x0c)
 | ||
| 	  break;
 | ||
|       }
 | ||
| 
 | ||
|     /* Return if we didn't find a label. */
 | ||
|     if (i == 3)
 | ||
|       {
 | ||
| #ifdef GRUB_UTIL
 | ||
| 	grub_util_info ("no LDM signature found");
 | ||
| #endif
 | ||
| 	return NULL;
 | ||
|       }
 | ||
|   }
 | ||
| 
 | ||
|   id->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
 | ||
|   if (!id->uuid)
 | ||
|     return NULL;
 | ||
|   grub_memcpy (id->uuid, label.disk_guid, LDM_GUID_STRLEN);
 | ||
|   id->uuid[LDM_GUID_STRLEN] = 0;
 | ||
|   id->uuidlen = grub_strlen ((char *) id->uuid);
 | ||
|   *start_sector = grub_be_to_cpu64 (label.pv_start);
 | ||
| 
 | ||
|   {
 | ||
|     grub_size_t s;
 | ||
|     for (s = 0; s < LDM_GUID_STRLEN && label.group_guid[s]; s++);
 | ||
|     vg = grub_diskfilter_get_vg_by_uuid (s, label.group_guid);
 | ||
|     if (! vg)
 | ||
|       vg = make_vg (disk, &label);
 | ||
|   }
 | ||
| 
 | ||
|   if (!vg)
 | ||
|     {
 | ||
|       grub_free (id->uuid);
 | ||
|       return NULL;
 | ||
|     }
 | ||
|   return vg;
 | ||
| }
 | ||
| 
 | ||
| #ifdef GRUB_UTIL
 | ||
| 
 | ||
| char *
 | ||
| grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start)
 | ||
| {
 | ||
|   struct grub_diskfilter_pv *pv = NULL;
 | ||
|   struct grub_diskfilter_vg *vg = NULL;
 | ||
|   struct grub_diskfilter_lv *res = 0, *lv, *res_lv = 0;
 | ||
| 
 | ||
|   pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
 | ||
| 
 | ||
|   if (!pv)
 | ||
|     return NULL;
 | ||
| 
 | ||
|   for (lv = vg->lvs; lv; lv = lv->next)
 | ||
|     if (lv->segment_count == 1 && lv->segments->node_count == 1
 | ||
| 	&& lv->segments->type == GRUB_DISKFILTER_STRIPED
 | ||
| 	&& lv->segments->nodes->pv == pv
 | ||
| 	&& lv->segments->nodes->start + pv->start_sector == start)
 | ||
|       {
 | ||
| 	res_lv = lv;
 | ||
| 	break;
 | ||
|       }
 | ||
|   if (!res_lv)
 | ||
|     return NULL;
 | ||
|   for (lv = vg->lvs; lv; lv = lv->next)
 | ||
|     if (lv->segment_count == 1 && lv->segments->node_count == 1
 | ||
| 	&& lv->segments->type == GRUB_DISKFILTER_MIRROR
 | ||
| 	&& lv->segments->nodes->lv == res_lv)
 | ||
|       {
 | ||
| 	res = lv;
 | ||
| 	break;
 | ||
|       }
 | ||
|   if (res && res->fullname)
 | ||
|     return grub_strdup (res->fullname);
 | ||
|   return NULL;
 | ||
| }
 | ||
| 
 | ||
| int
 | ||
| grub_util_is_ldm (grub_disk_t disk)
 | ||
| {
 | ||
|   int i;
 | ||
|   int has_ldm = msdos_has_ldm_partition (disk);
 | ||
|   for (i = 0; i < 3; i++)
 | ||
|     {
 | ||
|       grub_disk_addr_t sector = LDM_LABEL_SECTOR;
 | ||
|       grub_err_t err;
 | ||
|       struct grub_ldm_label label;
 | ||
| 
 | ||
|       switch (i)
 | ||
| 	{
 | ||
| 	case 0:
 | ||
| 	  if (!has_ldm)
 | ||
| 	    continue;
 | ||
| 	  sector = LDM_LABEL_SECTOR;
 | ||
| 	  break;
 | ||
| 	case 1:
 | ||
| 	  /* LDM is never inside a partition.  */
 | ||
| 	  if (!has_ldm || disk->partition)
 | ||
| 	    continue;
 | ||
| 	  sector = grub_disk_get_size (disk);
 | ||
| 	  if (sector == GRUB_DISK_SIZE_UNKNOWN)
 | ||
| 	    continue;
 | ||
| 	  sector--;
 | ||
| 	  break;
 | ||
| 	  /* FIXME: try the third copy.  */
 | ||
| 	case 2:
 | ||
| 	  sector = gpt_ldm_sector (disk);
 | ||
| 	  if (!sector)
 | ||
| 	    continue;
 | ||
| 	  break;
 | ||
| 	}
 | ||
|       err = grub_disk_read (disk, sector, 0, sizeof(label), &label);
 | ||
|       if (err)
 | ||
| 	{
 | ||
| 	  grub_errno = GRUB_ERR_NONE;
 | ||
| 	  return 0;
 | ||
| 	}
 | ||
|       /* This check is more relaxed on purpose.  */
 | ||
|       if (grub_memcmp (label.magic, LDM_MAGIC, sizeof (label.magic)) == 0)
 | ||
| 	return 1;
 | ||
|     }
 | ||
| 
 | ||
|   return 0;
 | ||
| }
 | ||
| 
 | ||
| grub_err_t
 | ||
| grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
 | ||
| 		     unsigned int max_nsectors,
 | ||
| 		     grub_embed_type_t embed_type,
 | ||
| 		     grub_disk_addr_t **sectors)
 | ||
| {
 | ||
|   struct grub_diskfilter_pv *pv = NULL;
 | ||
|   struct grub_diskfilter_vg *vg;
 | ||
|   struct grub_diskfilter_lv *lv;
 | ||
|   unsigned i;
 | ||
| 
 | ||
|   if (embed_type != GRUB_EMBED_PCBIOS)
 | ||
|     return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
 | ||
| 		       "LDM curently supports only PC-BIOS embedding");
 | ||
|   if (disk->partition)
 | ||
|     return grub_error (GRUB_ERR_BUG, "disk isn't LDM");
 | ||
|   pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
 | ||
|   if (!pv)
 | ||
|     return grub_error (GRUB_ERR_BUG, "disk isn't LDM");
 | ||
|   for (lv = vg->lvs; lv; lv = lv->next)
 | ||
|     {
 | ||
|       struct grub_diskfilter_lv *comp;
 | ||
| 
 | ||
|       if (!lv->visible || !lv->fullname)
 | ||
| 	continue;
 | ||
| 
 | ||
|       if (lv->segment_count != 1)
 | ||
| 	continue;
 | ||
|       if (lv->segments->type != GRUB_DISKFILTER_MIRROR
 | ||
| 	  || lv->segments->node_count != 1
 | ||
| 	  || lv->segments->start_extent != 0
 | ||
| 	  || lv->segments->extent_count != lv->size)
 | ||
| 	continue;
 | ||
| 
 | ||
|       comp = lv->segments->nodes->lv;
 | ||
|       if (!comp)
 | ||
| 	continue;
 | ||
| 
 | ||
|       if (comp->segment_count != 1 || comp->size != lv->size)
 | ||
| 	continue;
 | ||
|       if (comp->segments->type != GRUB_DISKFILTER_STRIPED
 | ||
| 	  || comp->segments->node_count != 1
 | ||
| 	  || comp->segments->start_extent != 0
 | ||
| 	  || comp->segments->extent_count != lv->size)
 | ||
| 	continue;
 | ||
| 
 | ||
|       /* How to implement proper check is to be discussed.  */
 | ||
| #if 1
 | ||
|       if (1)
 | ||
| 	continue;
 | ||
| #else
 | ||
|       if (grub_strcmp (lv->name, "Volume5") != 0)
 | ||
| 	continue;
 | ||
| #endif
 | ||
|       if (lv->size < *nsectors)
 | ||
| 	return grub_error (GRUB_ERR_OUT_OF_RANGE,
 | ||
| 			   /* TRANSLATORS: it's a partition for embedding,
 | ||
| 			      not a partition embed into something. GRUB
 | ||
| 			      install tools put core.img into a place
 | ||
| 			      usable for bootloaders (called generically
 | ||
| 			      "embedding zone") and this operation is
 | ||
| 			      called "embedding".  */
 | ||
| 			   N_("your LDM Embedding Partition is too small;"
 | ||
| 			      " embedding won't be possible"));
 | ||
|       *nsectors = lv->size;
 | ||
|       if (*nsectors > max_nsectors)
 | ||
| 	*nsectors = max_nsectors;
 | ||
|       *sectors = grub_malloc (*nsectors * sizeof (**sectors));
 | ||
|       if (!*sectors)
 | ||
| 	return grub_errno;
 | ||
|       for (i = 0; i < *nsectors; i++)
 | ||
| 	(*sectors)[i] = (lv->segments->nodes->start
 | ||
| 			 + comp->segments->nodes->start
 | ||
| 			 + comp->segments->nodes->pv->start_sector + i);
 | ||
|       return GRUB_ERR_NONE;
 | ||
|     }
 | ||
| 
 | ||
|   return grub_error (GRUB_ERR_FILE_NOT_FOUND,
 | ||
| 		     /* TRANSLATORS: it's a partition for embedding,
 | ||
| 			not a partition embed into something.  */
 | ||
| 		     N_("this LDM has no Embedding Partition;"
 | ||
| 			" embedding won't be possible"));
 | ||
| }
 | ||
| #endif
 | ||
| 
 | ||
| static struct grub_diskfilter grub_ldm_dev = {
 | ||
|   .name = "ldm",
 | ||
|   .detect = grub_ldm_detect,
 | ||
|   .next = 0
 | ||
| };
 | ||
| 
 | ||
| GRUB_MOD_INIT (ldm)
 | ||
| {
 | ||
|   grub_diskfilter_register_back (&grub_ldm_dev);
 | ||
| }
 | ||
| 
 | ||
| GRUB_MOD_FINI (ldm)
 | ||
| {
 | ||
|   grub_diskfilter_unregister (&grub_ldm_dev);
 | ||
| }
 |