2 * GRUB -- GRand Unified Bootloader
3 * Copyright (C) 2006,2007,2008,2009,2011 Free Software Foundation, Inc.
5 * GRUB is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * GRUB is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/disk.h>
23 #include <grub/misc.h>
24 #include <grub/diskfilter.h>
25 #include <grub/msdos_partition.h>
26 #include <grub/gpt_partition.h>
27 #include <grub/i18n.h>
30 #include <grub/emu/misc.h>
31 #include <grub/emu/hostdisk.h>
34 GRUB_MOD_LICENSE ("GPLv3+");
36 #define LDM_GUID_STRLEN 64
37 #define LDM_NAME_STRLEN 32
39 typedef grub_uint8_t
*grub_ldm_id_t
;
41 enum { STRIPE
= 1, SPANNED
= 2, RAID5
= 3 };
43 #define LDM_LABEL_SECTOR 6
44 struct grub_ldm_vblk
{
46 grub_uint8_t unused1
[12];
47 grub_uint16_t update_status
;
50 grub_uint32_t unused2
;
51 grub_uint8_t dynamic
[104];
53 #define LDM_VBLK_MAGIC "VBLK"
57 STATUS_CONSISTENT
= 0,
58 STATUS_STILL_ACTIVE
= 1,
59 STATUS_NOT_ACTIVE_YET
= 2
64 ENTRY_COMPONENT
= 0x32,
65 ENTRY_PARTITION
= 0x33,
73 grub_uint32_t unused1
;
74 grub_uint16_t ver_major
;
75 grub_uint16_t ver_minor
;
76 grub_uint8_t unused2
[32];
77 char disk_guid
[LDM_GUID_STRLEN
];
78 char host_guid
[LDM_GUID_STRLEN
];
79 char group_guid
[LDM_GUID_STRLEN
];
80 char group_name
[LDM_NAME_STRLEN
];
81 grub_uint8_t unused3
[11];
82 grub_uint64_t pv_start
;
83 grub_uint64_t pv_size
;
84 grub_uint64_t config_start
;
85 grub_uint64_t config_size
;
89 #define LDM_MAGIC "PRIVHEAD"
93 static inline grub_uint64_t
94 read_int (grub_uint8_t
*in
, grub_size_t s
)
99 for (ptr2
= in
; ptr2
< in
+ s
; ptr2
++)
108 check_ldm_partition (grub_disk_t disk
__attribute__ ((unused
)), const grub_partition_t p
, void *data
)
114 if (p
->msdostype
== GRUB_PC_PARTITION_TYPE_LDM
)
123 msdos_has_ldm_partition (grub_disk_t dsk
)
128 err
= grub_partition_msdos_iterate (dsk
, check_ldm_partition
, &has_ldm
);
131 grub_errno
= GRUB_ERR_NONE
;
138 static const grub_gpt_part_type_t ldm_type
= GRUB_GPT_PARTITION_TYPE_LDM
;
140 /* Helper for gpt_ldm_sector. */
142 gpt_ldm_sector_iter (grub_disk_t disk
, const grub_partition_t p
, void *data
)
144 grub_disk_addr_t
*sector
= data
;
145 struct grub_gpt_partentry gptdata
;
148 p2
= disk
->partition
;
149 disk
->partition
= p
->parent
;
150 if (grub_disk_read (disk
, p
->offset
, p
->index
,
151 sizeof (gptdata
), &gptdata
))
153 disk
->partition
= p2
;
156 disk
->partition
= p2
;
158 if (! grub_memcmp (&gptdata
.type
, &ldm_type
, 16))
160 *sector
= p
->start
+ p
->len
- 1;
166 static grub_disk_addr_t
167 gpt_ldm_sector (grub_disk_t dsk
)
169 grub_disk_addr_t sector
= 0;
172 err
= grub_gpt_partition_map_iterate (dsk
, gpt_ldm_sector_iter
, §or
);
175 grub_errno
= GRUB_ERR_NONE
;
181 static struct grub_diskfilter_vg
*
182 make_vg (grub_disk_t disk
,
183 const struct grub_ldm_label
*label
)
185 grub_disk_addr_t startsec
, endsec
, cursec
;
186 struct grub_diskfilter_vg
*vg
;
189 /* First time we see this volume group. We've to create the
190 whole volume group structure. */
191 vg
= grub_malloc (sizeof (*vg
));
195 vg
->name
= grub_malloc (LDM_NAME_STRLEN
+ 1);
196 vg
->uuid
= grub_malloc (LDM_GUID_STRLEN
+ 1);
197 if (! vg
->uuid
|| !vg
->name
)
199 grub_free (vg
->uuid
);
200 grub_free (vg
->name
);
203 grub_memcpy (vg
->uuid
, label
->group_guid
, LDM_GUID_STRLEN
);
204 grub_memcpy (vg
->name
, label
->group_name
, LDM_NAME_STRLEN
);
205 vg
->name
[LDM_NAME_STRLEN
] = 0;
206 vg
->uuid
[LDM_GUID_STRLEN
] = 0;
207 vg
->uuid_len
= grub_strlen (vg
->uuid
);
212 startsec
= grub_be_to_cpu64 (label
->config_start
);
213 endsec
= startsec
+ grub_be_to_cpu64 (label
->config_size
);
215 /* First find disks. */
216 for (cursec
= startsec
+ 0x12; cursec
< endsec
; cursec
++)
218 struct grub_ldm_vblk vblk
[GRUB_DISK_SECTOR_SIZE
219 / sizeof (struct grub_ldm_vblk
)];
221 err
= grub_disk_read (disk
, cursec
, 0,
222 sizeof(vblk
), &vblk
);
226 for (i
= 0; i
< ARRAY_SIZE (vblk
); i
++)
228 struct grub_diskfilter_pv
*pv
;
230 if (grub_memcmp (vblk
[i
].magic
, LDM_VBLK_MAGIC
,
231 sizeof (vblk
[i
].magic
)) != 0)
233 if (grub_be_to_cpu16 (vblk
[i
].update_status
)
235 && grub_be_to_cpu16 (vblk
[i
].update_status
)
236 != STATUS_STILL_ACTIVE
)
238 if (vblk
[i
].type
!= ENTRY_DISK
)
240 pv
= grub_zalloc (sizeof (*pv
));
245 ptr
= vblk
[i
].dynamic
;
246 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
247 + sizeof (vblk
[i
].dynamic
))
252 pv
->internal_id
= grub_malloc (ptr
[0] + 2);
253 if (!pv
->internal_id
)
258 grub_memcpy (pv
->internal_id
, ptr
, (grub_size_t
) ptr
[0] + 1);
259 pv
->internal_id
[(grub_size_t
) ptr
[0] + 1] = 0;
262 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
263 + sizeof (vblk
[i
].dynamic
))
271 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
276 pv
->id
.uuidlen
= *ptr
;
277 pv
->id
.uuid
= grub_malloc (pv
->id
.uuidlen
+ 1);
278 grub_memcpy (pv
->id
.uuid
, ptr
+ 1, pv
->id
.uuidlen
);
279 pv
->id
.uuid
[pv
->id
.uuidlen
] = 0;
287 for (cursec
= startsec
+ 0x12; cursec
< endsec
; cursec
++)
289 struct grub_ldm_vblk vblk
[GRUB_DISK_SECTOR_SIZE
290 / sizeof (struct grub_ldm_vblk
)];
292 err
= grub_disk_read (disk
, cursec
, 0,
293 sizeof(vblk
), &vblk
);
297 for (i
= 0; i
< ARRAY_SIZE (vblk
); i
++)
299 struct grub_diskfilter_lv
*lv
;
301 if (grub_memcmp (vblk
[i
].magic
, LDM_VBLK_MAGIC
,
302 sizeof (vblk
[i
].magic
)) != 0)
304 if (grub_be_to_cpu16 (vblk
[i
].update_status
)
306 && grub_be_to_cpu16 (vblk
[i
].update_status
)
307 != STATUS_STILL_ACTIVE
)
309 if (vblk
[i
].type
!= ENTRY_VOLUME
)
311 lv
= grub_zalloc (sizeof (*lv
));
316 lv
->segment_count
= 1;
317 lv
->segment_alloc
= 1;
319 lv
->segments
= grub_zalloc (sizeof (*lv
->segments
));
322 lv
->segments
->start_extent
= 0;
323 lv
->segments
->type
= GRUB_DISKFILTER_MIRROR
;
324 lv
->segments
->node_count
= 0;
325 lv
->segments
->node_alloc
= 8;
326 lv
->segments
->nodes
= grub_zalloc (sizeof (*lv
->segments
->nodes
)
327 * lv
->segments
->node_alloc
);
328 if (!lv
->segments
->nodes
)
330 ptr
= vblk
[i
].dynamic
;
331 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
332 + sizeof (vblk
[i
].dynamic
))
337 lv
->internal_id
= grub_malloc ((grub_size_t
) ptr
[0] + 2);
338 if (!lv
->internal_id
)
343 grub_memcpy (lv
->internal_id
, ptr
, ptr
[0] + 1);
344 lv
->internal_id
[ptr
[0] + 1] = 0;
347 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
348 + sizeof (vblk
[i
].dynamic
))
353 lv
->name
= grub_malloc (*ptr
+ 1);
356 grub_free (lv
->internal_id
);
360 grub_memcpy (lv
->name
, ptr
+ 1, *ptr
);
362 lv
->fullname
= grub_xasprintf ("ldm/%s/%s",
366 grub_free (lv
->internal_id
);
367 grub_free (lv
->name
);
373 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
375 grub_free (lv
->internal_id
);
376 grub_free (lv
->name
);
380 /* ptr = volume type. */
382 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
384 grub_free (lv
->internal_id
);
385 grub_free (lv
->name
);
391 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
393 grub_free (lv
->internal_id
);
394 grub_free (lv
->name
);
399 /* Skip state, type, unknown, volume number, zeros, flags. */
400 ptr
+= 14 + 1 + 1 + 1 + 3 + 1;
401 /* ptr = number of children. */
402 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
404 grub_free (lv
->internal_id
);
405 grub_free (lv
->name
);
410 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
412 grub_free (lv
->internal_id
);
413 grub_free (lv
->name
);
418 /* Skip 2 more fields. */
420 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
)
421 || ptr
+ *ptr
+ 1>= vblk
[i
].dynamic
422 + sizeof (vblk
[i
].dynamic
))
424 grub_free (lv
->internal_id
);
425 grub_free (lv
->name
);
429 lv
->size
= read_int (ptr
+ 1, *ptr
);
430 lv
->segments
->extent_count
= lv
->size
;
437 /* Now the components. */
438 for (cursec
= startsec
+ 0x12; cursec
< endsec
; cursec
++)
440 struct grub_ldm_vblk vblk
[GRUB_DISK_SECTOR_SIZE
441 / sizeof (struct grub_ldm_vblk
)];
443 err
= grub_disk_read (disk
, cursec
, 0,
444 sizeof(vblk
), &vblk
);
448 for (i
= 0; i
< ARRAY_SIZE (vblk
); i
++)
450 struct grub_diskfilter_lv
*comp
;
451 struct grub_diskfilter_lv
*lv
;
455 if (grub_memcmp (vblk
[i
].magic
, LDM_VBLK_MAGIC
,
456 sizeof (vblk
[i
].magic
)) != 0)
458 if (grub_be_to_cpu16 (vblk
[i
].update_status
)
460 && grub_be_to_cpu16 (vblk
[i
].update_status
)
461 != STATUS_STILL_ACTIVE
)
463 if (vblk
[i
].type
!= ENTRY_COMPONENT
)
465 comp
= grub_zalloc (sizeof (*comp
));
472 ptr
= vblk
[i
].dynamic
;
473 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
477 comp
->internal_id
= grub_malloc ((grub_size_t
) ptr
[0] + 2);
478 if (!comp
->internal_id
)
483 grub_memcpy (comp
->internal_id
, ptr
, ptr
[0] + 1);
484 comp
->internal_id
[ptr
[0] + 1] = 0;
487 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
489 grub_free (comp
->internal_id
);
495 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
497 grub_free (comp
->internal_id
);
506 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
508 grub_free (comp
->internal_id
);
513 /* ptr = number of children. */
515 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
517 grub_free (comp
->internal_id
);
522 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
523 + sizeof (vblk
[i
].dynamic
))
525 grub_free (comp
->internal_id
);
529 for (lv
= vg
->lvs
; lv
; lv
= lv
->next
)
531 if (lv
->internal_id
[0] == ptr
[0]
532 && grub_memcmp (lv
->internal_id
+ 1, ptr
+ 1, ptr
[0]) == 0)
537 grub_free (comp
->internal_id
);
541 comp
->size
= lv
->size
;
544 comp
->segment_alloc
= 8;
545 comp
->segment_count
= 0;
546 comp
->segments
= grub_malloc (sizeof (*comp
->segments
)
547 * comp
->segment_alloc
);
553 comp
->segment_alloc
= 1;
554 comp
->segment_count
= 1;
555 comp
->segments
= grub_malloc (sizeof (*comp
->segments
));
558 comp
->segments
->start_extent
= 0;
559 comp
->segments
->extent_count
= lv
->size
;
560 comp
->segments
->layout
= 0;
562 comp
->segments
->type
= GRUB_DISKFILTER_STRIPED
;
563 else if (type
== RAID5
)
565 comp
->segments
->type
= GRUB_DISKFILTER_RAID5
;
566 comp
->segments
->layout
= GRUB_RAID_LAYOUT_SYMMETRIC_MASK
;
572 if (!(vblk
[i
].flags
& 0x10))
574 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
)
575 || ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
576 + sizeof (vblk
[i
].dynamic
))
578 grub_free (comp
->internal_id
);
582 comp
->segments
->stripe_size
= read_int (ptr
+ 1, *ptr
);
584 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
585 + sizeof (vblk
[i
].dynamic
))
587 grub_free (comp
->internal_id
);
591 comp
->segments
->node_count
= read_int (ptr
+ 1, *ptr
);
592 comp
->segments
->node_alloc
= comp
->segments
->node_count
;
593 comp
->segments
->nodes
= grub_zalloc (sizeof (*comp
->segments
->nodes
)
594 * comp
->segments
->node_alloc
);
595 if (!lv
->segments
->nodes
)
599 if (lv
->segments
->node_alloc
== lv
->segments
->node_count
)
602 lv
->segments
->node_alloc
*= 2;
603 t
= grub_realloc (lv
->segments
->nodes
,
604 sizeof (*lv
->segments
->nodes
)
605 * lv
->segments
->node_alloc
);
608 lv
->segments
->nodes
= t
;
610 lv
->segments
->nodes
[lv
->segments
->node_count
].pv
= 0;
611 lv
->segments
->nodes
[lv
->segments
->node_count
].start
= 0;
612 lv
->segments
->nodes
[lv
->segments
->node_count
++].lv
= comp
;
613 comp
->next
= vg
->lvs
;
618 for (cursec
= startsec
+ 0x12; cursec
< endsec
; cursec
++)
620 struct grub_ldm_vblk vblk
[GRUB_DISK_SECTOR_SIZE
621 / sizeof (struct grub_ldm_vblk
)];
623 err
= grub_disk_read (disk
, cursec
, 0,
624 sizeof(vblk
), &vblk
);
628 for (i
= 0; i
< ARRAY_SIZE (vblk
); i
++)
630 struct grub_diskfilter_lv
*comp
;
631 struct grub_diskfilter_node part
;
632 grub_disk_addr_t start
, size
;
636 if (grub_memcmp (vblk
[i
].magic
, LDM_VBLK_MAGIC
,
637 sizeof (vblk
[i
].magic
)) != 0)
639 if (grub_be_to_cpu16 (vblk
[i
].update_status
)
641 && grub_be_to_cpu16 (vblk
[i
].update_status
)
642 != STATUS_STILL_ACTIVE
)
644 if (vblk
[i
].type
!= ENTRY_PARTITION
)
649 ptr
= vblk
[i
].dynamic
;
650 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
656 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
662 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
667 /* skip zeros and logcommit id. */
669 if (ptr
+ 16 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
673 part
.start
= read_int (ptr
, 8);
674 start
= read_int (ptr
+ 8, 8);
676 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
)
677 || ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
681 size
= read_int (ptr
+ 1, *ptr
);
683 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
)
684 || ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
689 for (comp
= vg
->lvs
; comp
; comp
= comp
->next
)
690 if (comp
->internal_id
[0] == ptr
[0]
691 && grub_memcmp (ptr
+ 1, comp
->internal_id
+ 1,
692 comp
->internal_id
[0]) == 0)
696 if (ptr
>= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
)
697 || ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
+ sizeof (vblk
[i
].dynamic
))
702 struct grub_diskfilter_pv
*pv
;
703 for (pv
= vg
->pvs
; pv
; pv
= pv
->next
)
704 if (pv
->internal_id
[0] == ptr
[0]
705 && grub_memcmp (pv
->internal_id
+ 1, ptr
+ 1, ptr
[0]) == 0)
708 if (comp
->segment_alloc
== 1)
712 if (ptr
+ *ptr
+ 1 >= vblk
[i
].dynamic
713 + sizeof (vblk
[i
].dynamic
))
717 node_index
= read_int (ptr
+ 1, *ptr
);
718 if (node_index
< comp
->segments
->node_count
)
719 comp
->segments
->nodes
[node_index
] = part
;
723 if (comp
->segment_alloc
== comp
->segment_count
)
726 comp
->segment_alloc
*= 2;
727 t
= grub_realloc (comp
->segments
,
729 * sizeof (*comp
->segments
));
734 comp
->segments
[comp
->segment_count
].start_extent
= start
;
735 comp
->segments
[comp
->segment_count
].extent_count
= size
;
736 comp
->segments
[comp
->segment_count
].type
= GRUB_DISKFILTER_STRIPED
;
737 comp
->segments
[comp
->segment_count
].node_count
= 1;
738 comp
->segments
[comp
->segment_count
].node_alloc
= 1;
739 comp
->segments
[comp
->segment_count
].nodes
740 = grub_malloc (sizeof (*comp
->segments
[comp
->segment_count
].nodes
));
741 if (!comp
->segments
[comp
->segment_count
].nodes
)
743 comp
->segments
[comp
->segment_count
].nodes
[0] = part
;
744 comp
->segment_count
++;
748 if (grub_diskfilter_vg_register (vg
))
753 struct grub_diskfilter_lv
*lv
, *next_lv
;
754 struct grub_diskfilter_pv
*pv
, *next_pv
;
755 for (lv
= vg
->lvs
; lv
; lv
= next_lv
)
758 for (i
= 0; i
< lv
->segment_count
; i
++)
759 grub_free (lv
->segments
[i
].nodes
);
762 grub_free (lv
->segments
);
763 grub_free (lv
->internal_id
);
764 grub_free (lv
->name
);
765 grub_free (lv
->fullname
);
768 for (pv
= vg
->pvs
; pv
; pv
= next_pv
)
771 grub_free (pv
->id
.uuid
);
775 grub_free (vg
->uuid
);
780 static struct grub_diskfilter_vg
*
781 grub_ldm_detect (grub_disk_t disk
,
782 struct grub_diskfilter_pv_id
*id
,
783 grub_disk_addr_t
*start_sector
)
786 struct grub_ldm_label label
;
787 struct grub_diskfilter_vg
*vg
;
790 grub_util_info ("scanning %s for LDM", disk
->name
);
795 int has_ldm
= msdos_has_ldm_partition (disk
);
796 for (i
= 0; i
< 3; i
++)
798 grub_disk_addr_t sector
= LDM_LABEL_SECTOR
;
804 sector
= LDM_LABEL_SECTOR
;
807 /* LDM is never inside a partition. */
808 if (!has_ldm
|| disk
->partition
)
810 sector
= grub_disk_get_size (disk
);
811 if (sector
== GRUB_DISK_SIZE_UNKNOWN
)
815 /* FIXME: try the third copy. */
817 sector
= gpt_ldm_sector (disk
);
822 err
= grub_disk_read (disk
, sector
, 0,
823 sizeof(label
), &label
);
826 if (grub_memcmp (label
.magic
, LDM_MAGIC
, sizeof (label
.magic
)) == 0
827 && grub_be_to_cpu16 (label
.ver_major
) == 0x02
828 && grub_be_to_cpu16 (label
.ver_minor
) >= 0x0b
829 && grub_be_to_cpu16 (label
.ver_minor
) <= 0x0c)
833 /* Return if we didn't find a label. */
837 grub_util_info ("no LDM signature found");
843 id
->uuid
= grub_malloc (LDM_GUID_STRLEN
+ 1);
846 grub_memcpy (id
->uuid
, label
.disk_guid
, LDM_GUID_STRLEN
);
847 id
->uuid
[LDM_GUID_STRLEN
] = 0;
848 id
->uuidlen
= grub_strlen ((char *) id
->uuid
);
849 *start_sector
= grub_be_to_cpu64 (label
.pv_start
);
853 for (s
= 0; s
< LDM_GUID_STRLEN
&& label
.group_guid
[s
]; s
++);
854 vg
= grub_diskfilter_get_vg_by_uuid (s
, label
.group_guid
);
856 vg
= make_vg (disk
, &label
);
861 grub_free (id
->uuid
);
870 grub_util_get_ldm (grub_disk_t disk
, grub_disk_addr_t start
)
872 struct grub_diskfilter_pv
*pv
= NULL
;
873 struct grub_diskfilter_vg
*vg
= NULL
;
874 struct grub_diskfilter_lv
*res
= 0, *lv
, *res_lv
= 0;
876 pv
= grub_diskfilter_get_pv_from_disk (disk
, &vg
);
881 for (lv
= vg
->lvs
; lv
; lv
= lv
->next
)
882 if (lv
->segment_count
== 1 && lv
->segments
->node_count
== 1
883 && lv
->segments
->type
== GRUB_DISKFILTER_STRIPED
884 && lv
->segments
->nodes
->pv
== pv
885 && lv
->segments
->nodes
->start
+ pv
->start_sector
== start
)
892 for (lv
= vg
->lvs
; lv
; lv
= lv
->next
)
893 if (lv
->segment_count
== 1 && lv
->segments
->node_count
== 1
894 && lv
->segments
->type
== GRUB_DISKFILTER_MIRROR
895 && lv
->segments
->nodes
->lv
== res_lv
)
900 if (res
&& res
->fullname
)
901 return grub_strdup (res
->fullname
);
906 grub_util_is_ldm (grub_disk_t disk
)
909 int has_ldm
= msdos_has_ldm_partition (disk
);
910 for (i
= 0; i
< 3; i
++)
912 grub_disk_addr_t sector
= LDM_LABEL_SECTOR
;
914 struct grub_ldm_label label
;
921 sector
= LDM_LABEL_SECTOR
;
924 /* LDM is never inside a partition. */
925 if (!has_ldm
|| disk
->partition
)
927 sector
= grub_disk_get_size (disk
);
928 if (sector
== GRUB_DISK_SIZE_UNKNOWN
)
932 /* FIXME: try the third copy. */
934 sector
= gpt_ldm_sector (disk
);
939 err
= grub_disk_read (disk
, sector
, 0, sizeof(label
), &label
);
942 grub_errno
= GRUB_ERR_NONE
;
945 /* This check is more relaxed on purpose. */
946 if (grub_memcmp (label
.magic
, LDM_MAGIC
, sizeof (label
.magic
)) == 0)
954 grub_util_ldm_embed (struct grub_disk
*disk
, unsigned int *nsectors
,
955 unsigned int max_nsectors
,
956 grub_embed_type_t embed_type
,
957 grub_disk_addr_t
**sectors
)
959 struct grub_diskfilter_pv
*pv
= NULL
;
960 struct grub_diskfilter_vg
*vg
;
961 struct grub_diskfilter_lv
*lv
;
964 if (embed_type
!= GRUB_EMBED_PCBIOS
)
965 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
966 "LDM curently supports only PC-BIOS embedding");
968 return grub_error (GRUB_ERR_BUG
, "disk isn't LDM");
969 pv
= grub_diskfilter_get_pv_from_disk (disk
, &vg
);
971 return grub_error (GRUB_ERR_BUG
, "disk isn't LDM");
972 for (lv
= vg
->lvs
; lv
; lv
= lv
->next
)
974 struct grub_diskfilter_lv
*comp
;
976 if (!lv
->visible
|| !lv
->fullname
)
979 if (lv
->segment_count
!= 1)
981 if (lv
->segments
->type
!= GRUB_DISKFILTER_MIRROR
982 || lv
->segments
->node_count
!= 1
983 || lv
->segments
->start_extent
!= 0
984 || lv
->segments
->extent_count
!= lv
->size
)
987 comp
= lv
->segments
->nodes
->lv
;
991 if (comp
->segment_count
!= 1 || comp
->size
!= lv
->size
)
993 if (comp
->segments
->type
!= GRUB_DISKFILTER_STRIPED
994 || comp
->segments
->node_count
!= 1
995 || comp
->segments
->start_extent
!= 0
996 || comp
->segments
->extent_count
!= lv
->size
)
999 /* How to implement proper check is to be discussed. */
1004 if (grub_strcmp (lv
->name
, "Volume5") != 0)
1007 if (lv
->size
< *nsectors
)
1008 return grub_error (GRUB_ERR_OUT_OF_RANGE
,
1009 /* TRANSLATORS: it's a partition for embedding,
1010 not a partition embed into something. GRUB
1011 install tools put core.img into a place
1012 usable for bootloaders (called generically
1013 "embedding zone") and this operation is
1014 called "embedding". */
1015 N_("your LDM Embedding Partition is too small;"
1016 " embedding won't be possible"));
1017 *nsectors
= lv
->size
;
1018 if (*nsectors
> max_nsectors
)
1019 *nsectors
= max_nsectors
;
1020 *sectors
= grub_malloc (*nsectors
* sizeof (**sectors
));
1023 for (i
= 0; i
< *nsectors
; i
++)
1024 (*sectors
)[i
] = (lv
->segments
->nodes
->start
1025 + comp
->segments
->nodes
->start
1026 + comp
->segments
->nodes
->pv
->start_sector
+ i
);
1027 return GRUB_ERR_NONE
;
1030 return grub_error (GRUB_ERR_FILE_NOT_FOUND
,
1031 /* TRANSLATORS: it's a partition for embedding,
1032 not a partition embed into something. */
1033 N_("this LDM has no Embedding Partition;"
1034 " embedding won't be possible"));
1038 static struct grub_diskfilter grub_ldm_dev
= {
1040 .detect
= grub_ldm_detect
,
1046 grub_diskfilter_register_back (&grub_ldm_dev
);
1051 grub_diskfilter_unregister (&grub_ldm_dev
);