Add LDM support using the same framework.
* Makefile.util.def (libgrubkern): Add grub-core/disk/ldm.c,
grub-core/disk/diskfilter.c and grub-core/partmap/gpt.c.
(libgrubmods): Remove grub-core/disk/raid.c and
grub-core/partmap/gpt.c.
* grub-core/Makefile.core.def (ldm): New module.
(raid): Renamed to diskfilter. All users updated.
* grub-core/disk/raid.c: Moved to ...
* grub-core/disk/diskfilter.c: ... here.
* grub-core/disk/diskfilter.c: Rename grub_raid_ to grub_diskfilter_.
(lv_num): New var.
(find_array): Renamed to ...
(find_lv): ... this. Support multi-LV. Skip nameless LVs
(grub_is_array_readable): Renamed to ...
(grub_is_lv_readable): ... this. Support multinode hierarchy.
(insert_array): New argument id.
(is_node_readable): New function.
(scan_device): Rename to ...
(scan_disk): .. this. Restrict to one disk.
(scan_devices): New function.
(grub_diskfilter_iterate): Support multi-LV.
Skip invisible and nameless LVs.
(grub_diskfilter_memberlist): Support multi-LV.
(grub_diskfilter_read_node): New function.
(grub_raid_read): Most of logic moved to ...
(read_segment): ... here
(read_lv): New function.
(grub_diskfilter_get_vg_by_uuid): New function.
(grub_diskfilter_make_raid): Likewise.
* grub-core/disk/ldm.c: New file.
* grub-core/disk/lvm.c (vg_list): Removed.
(lv_count): Likewise.
(scan_depth): Likewise.
(is_lv_readable): Likewise.
(grub_lvm_getvalue): Advance pointer past the number.
(find_lv): Removed.
(do_lvm_scan): Refactored into ...
(grub_lvm_detect): ... this. Support raid.
(grub_lvm_iterate): Removed.
(grub_lvm_memberlist): Likewise.
(grub_lvm_open): Likewise.
(grub_lvm_close): Likewise.
(read_lv): Likewise.
(read_node): Likewise.
(is_node_readable): Likewise.
(is_lv_readable): Likewise.
(grub_lvm_read): Likewise.
(grub_lvm_write): Likewise.
(grub_lvm_dev): Use diskfilter
(GRUB_MOD_INIT): Likewise.
(GRUB_MOD_FINI): Likewise.
* grub-core/disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Use
new interface.
* grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Likewise.
* grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise.
* grub-core/disk/raid5_recover.c (grub_raid5_recover): Use
grub_diskfilter_read_node.
Fix a bug with xor.
* grub-core/disk/raid6_recover.c (grub_raid6_recover): Use
grub_diskfilter_read_node.
Support GRUB_RAID_LAYOUT_MUL_FROM_POS.
* grub-core/kern/disk.c (grub_disk_dev_list): Make global.
(grub_disk_dev_iterate): Move from here...
* include/grub/disk.h (grub_disk_dev_iterate): ... to here. Inlined.
* grub-core/kern/emu/hostdisk.c (grub_hostdisk_find_partition_start):
Make global.
(grub_hostdisk_find_partition_start): Likewise.
(grub_hostdisk_os_dev_to_grub_drive): New function.
(grub_util_biosdisk_get_osdev): Check that disk is biosdisk.
* grub-core/kern/emu/hostdisk.c (make_device_name): Move to ...
* util/getroot.c (make_device_name): ... here.
* grub-core/kern/emu/hostdisk.c (grub_util_get_dm_node_linear_info):
Move to ...
* util/getroot.c (grub_util_get_dm_node_linear_info): ...here.
* grub-core/kern/emu/hostdisk.c
(convert_system_partition_to_system_disk): Move to ...
* util/getroot.c (convert_system_partition_to_system_disk): ...here.
* grub-core/kern/emu/hostdisk.c (device_is_wholedisk): Move to ...
* util/getroot.c (device_is_wholedisk): ... here.
* grub-core/kern/emu/hostdisk.c (find_system_device): Move to ...
* util/getroot.c (find_system_device): ... here.
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_present):
Move to ...
* util/getroot.c (grub_util_biosdisk_is_present): ...here.
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev):
Move to ...
* util/getroot.c (grub_util_biosdisk_get_grub_dev): ... here.
Handle LDM.
* grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy):
Move to ...
* util/getroot.c (grub_util_biosdisk_is_floppy): ... here.
* grub-core/partmap/gpt.c (grub_gpt_partition_map_iterate): Made global.
* include/grub/disk.h (grub_disk_dev_id): Replaced RAID and LVM with
DISKFILTER.
* include/grub/raid.h: Renamed to ...
* include/grub/diskfilter.h: ... this.
* include/grub/diskfilter.h: Rename grub_raid_* to grub_diskfilter_*
(GRUB_RAID_LAYOUT_*): Make into array.
(GRUB_RAID_LAYOUT_MUL_FROM_POS): New value.
(grub_diskfilter_vg): New struct.
(grub_diskfilter_pv_id): Likewise.
(grub_raid_member): Removed.
(grub_raid_array): Likewise.
(grub_diskfilter_pv): New struct.
(grub_diskfilter_lv): Likewise.
(grub_diskfilter_segment): Likewise.
(grub_diskfilter_node): Likewise.
(grub_diskfilter_get_vg_by_uuid): New proto.
(grub_raid_register): Inline.
(grub_diskfilter_unregister): Likewise.
(grub_diskfilter_make_raid): New proto.
(grub_diskfilter_vg_register): Likewise.
(grub_diskfilter_read_node): Likewise.
(grub_diskfilter_get_pv_from_disk) [GRUB_UTIL]: Likewise.
* include/grub/emu/hostdisk.h (grub_util_get_ldm): New proto.
(grub_util_is_ldm): Likewise.
(grub_util_ldm_embed) [GRUB_UTIL]: Likewise.
(grub_hostdisk_find_partition_start): Likewise.
(grub_hostdisk_os_dev_to_grub_drive): Likewise.
* include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_LDM):
New definition.
(grub_gpt_partition_map_iterate): New proto.
* include/grub/lvm.h (grub_lvm_vg): Removed.
(grub_lvm_pv): Likewise.
(grub_lvm_lv): Likewise.
(grub_lvm_segment): Likewise.
(grub_lvm_node): Likewise.
* util/getroot.c [...]
* util/grub-probe.c (probe_raid_level): Handle diskfilter.
(probe_abstraction): Likewise.
* util/grub-setup.c (setup): Remove must_embed. Support LDM.
(main): Remove dead logic.
+2012-01-29 Vladimir Serbinenko <phcoder@gmail.com>
+
+ Merge common RAID and LVM logic to an abstract diskfilter.
+ Add LDM support using the same framework.
+
+ * Makefile.util.def (libgrubkern): Add grub-core/disk/ldm.c,
+ grub-core/disk/diskfilter.c and grub-core/partmap/gpt.c.
+ (libgrubmods): Remove grub-core/disk/raid.c and
+ grub-core/partmap/gpt.c.
+ * grub-core/Makefile.core.def (ldm): New module.
+ (raid): Renamed to diskfilter. All users updated.
+ * grub-core/disk/raid.c: Moved to ...
+ * grub-core/disk/diskfilter.c: ... here.
+ * grub-core/disk/diskfilter.c: Rename grub_raid_ to grub_diskfilter_.
+ (lv_num): New var.
+ (find_array): Renamed to ...
+ (find_lv): ... this. Support multi-LV. Skip nameless LVs
+ (grub_is_array_readable): Renamed to ...
+ (grub_is_lv_readable): ... this. Support multinode hierarchy.
+ (insert_array): New argument id.
+ (is_node_readable): New function.
+ (scan_device): Rename to ...
+ (scan_disk): .. this. Restrict to one disk.
+ (scan_devices): New function.
+ (grub_diskfilter_iterate): Support multi-LV.
+ Skip invisible and nameless LVs.
+ (grub_diskfilter_memberlist): Support multi-LV.
+ (grub_diskfilter_read_node): New function.
+ (grub_raid_read): Most of logic moved to ...
+ (read_segment): ... here
+ (read_lv): New function.
+ (grub_diskfilter_get_vg_by_uuid): New function.
+ (grub_diskfilter_make_raid): Likewise.
+ * grub-core/disk/ldm.c: New file.
+ * grub-core/disk/lvm.c (vg_list): Removed.
+ (lv_count): Likewise.
+ (scan_depth): Likewise.
+ (is_lv_readable): Likewise.
+ (grub_lvm_getvalue): Advance pointer past the number.
+ (find_lv): Removed.
+ (do_lvm_scan): Refactored into ...
+ (grub_lvm_detect): ... this. Support raid.
+ (grub_lvm_iterate): Removed.
+ (grub_lvm_memberlist): Likewise.
+ (grub_lvm_open): Likewise.
+ (grub_lvm_close): Likewise.
+ (read_lv): Likewise.
+ (read_node): Likewise.
+ (is_node_readable): Likewise.
+ (is_lv_readable): Likewise.
+ (grub_lvm_read): Likewise.
+ (grub_lvm_write): Likewise.
+ (grub_lvm_dev): Use diskfilter
+ (GRUB_MOD_INIT): Likewise.
+ (GRUB_MOD_FINI): Likewise.
+ * grub-core/disk/dmraid_nvidia.c (grub_dmraid_nv_detect): Use
+ new interface.
+ * grub-core/disk/mdraid1x_linux.c (grub_mdraid_detect): Likewise.
+ * grub-core/disk/mdraid_linux.c (grub_mdraid_detect): Likewise.
+ * grub-core/disk/raid5_recover.c (grub_raid5_recover): Use
+ grub_diskfilter_read_node.
+ Fix a bug with xor.
+ * grub-core/disk/raid6_recover.c (grub_raid6_recover): Use
+ grub_diskfilter_read_node.
+ Support GRUB_RAID_LAYOUT_MUL_FROM_POS.
+ * grub-core/kern/disk.c (grub_disk_dev_list): Make global.
+ (grub_disk_dev_iterate): Move from here...
+ * include/grub/disk.h (grub_disk_dev_iterate): ... to here. Inlined.
+ * grub-core/kern/emu/hostdisk.c (grub_hostdisk_find_partition_start):
+ Make global.
+ (grub_hostdisk_find_partition_start): Likewise.
+ (grub_hostdisk_os_dev_to_grub_drive): New function.
+ (grub_util_biosdisk_get_osdev): Check that disk is biosdisk.
+ * grub-core/kern/emu/hostdisk.c (make_device_name): Move to ...
+ * util/getroot.c (make_device_name): ... here.
+ * grub-core/kern/emu/hostdisk.c (grub_util_get_dm_node_linear_info):
+ Move to ...
+ * util/getroot.c (grub_util_get_dm_node_linear_info): ...here.
+ * grub-core/kern/emu/hostdisk.c
+ (convert_system_partition_to_system_disk): Move to ...
+ * util/getroot.c (convert_system_partition_to_system_disk): ...here.
+ * grub-core/kern/emu/hostdisk.c (device_is_wholedisk): Move to ...
+ * util/getroot.c (device_is_wholedisk): ... here.
+ * grub-core/kern/emu/hostdisk.c (find_system_device): Move to ...
+ * util/getroot.c (find_system_device): ... here.
+ * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_present):
+ Move to ...
+ * util/getroot.c (grub_util_biosdisk_is_present): ...here.
+ * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_get_grub_dev):
+ Move to ...
+ * util/getroot.c (grub_util_biosdisk_get_grub_dev): ... here.
+ Handle LDM.
+ * grub-core/kern/emu/hostdisk.c (grub_util_biosdisk_is_floppy):
+ Move to ...
+ * util/getroot.c (grub_util_biosdisk_is_floppy): ... here.
+ * grub-core/partmap/gpt.c (grub_gpt_partition_map_iterate): Made global.
+ * include/grub/disk.h (grub_disk_dev_id): Replaced RAID and LVM with
+ DISKFILTER.
+ * include/grub/raid.h: Renamed to ...
+ * include/grub/diskfilter.h: ... this.
+ * include/grub/diskfilter.h: Rename grub_raid_* to grub_diskfilter_*
+ (GRUB_RAID_LAYOUT_*): Make into array.
+ (GRUB_RAID_LAYOUT_MUL_FROM_POS): New value.
+ (grub_diskfilter_vg): New struct.
+ (grub_diskfilter_pv_id): Likewise.
+ (grub_raid_member): Removed.
+ (grub_raid_array): Likewise.
+ (grub_diskfilter_pv): New struct.
+ (grub_diskfilter_lv): Likewise.
+ (grub_diskfilter_segment): Likewise.
+ (grub_diskfilter_node): Likewise.
+ (grub_diskfilter_get_vg_by_uuid): New proto.
+ (grub_raid_register): Inline.
+ (grub_diskfilter_unregister): Likewise.
+ (grub_diskfilter_make_raid): New proto.
+ (grub_diskfilter_vg_register): Likewise.
+ (grub_diskfilter_read_node): Likewise.
+ (grub_diskfilter_get_pv_from_disk) [GRUB_UTIL]: Likewise.
+ * include/grub/emu/hostdisk.h (grub_util_get_ldm): New proto.
+ (grub_util_is_ldm): Likewise.
+ (grub_util_ldm_embed) [GRUB_UTIL]: Likewise.
+ (grub_hostdisk_find_partition_start): Likewise.
+ (grub_hostdisk_os_dev_to_grub_drive): Likewise.
+ * include/grub/gpt_partition.h (GRUB_GPT_PARTITION_TYPE_LDM):
+ New definition.
+ (grub_gpt_partition_map_iterate): New proto.
+ * include/grub/lvm.h (grub_lvm_vg): Removed.
+ (grub_lvm_pv): Likewise.
+ (grub_lvm_lv): Likewise.
+ (grub_lvm_segment): Likewise.
+ (grub_lvm_node): Likewise.
+ * util/getroot.c [...]
+ * util/grub-probe.c (probe_raid_level): Handle diskfilter.
+ (probe_abstraction): Likewise.
+ * util/grub-setup.c (setup): Remove must_embed. Support LDM.
+ (main): Remove dead logic.
+
2012-01-28 Vladimir Serbinenko <phcoder@gmail.com>
Simplify root device discover and don't fail when trying to open
common = grub-core/lib/pbkdf2.c;
common = grub-core/commands/extcmd.c;
common = grub-core/lib/arg.c;
+ common = grub-core/disk/ldm.c;
+ common = grub-core/disk/diskfilter.c;
+ common = grub-core/partmap/gpt.c;
};
library = {
common = grub-core/disk/mdraid1x_linux.c;
common = grub-core/disk/raid5_recover.c;
common = grub-core/disk/raid6_recover.c;
- common = grub-core/disk/raid.c;
common = grub-core/fs/affs.c;
common = grub-core/fs/afs.c;
common = grub-core/fs/bfs.c;
common = grub-core/partmap/acorn.c;
common = grub-core/partmap/amiga.c;
common = grub-core/partmap/apple.c;
- common = grub-core/partmap/gpt.c;
common = grub-core/partmap/msdos.c;
common = grub-core/partmap/sun.c;
common = grub-core/partmap/plan.c;
common = disk/lvm.c;
};
+module = {
+ name = ldm;
+ common = disk/ldm.c;
+};
+
module = {
name = mdraid09;
common = disk/mdraid_linux.c;
};
module = {
- name = raid;
- common = disk/raid.c;
+ name = diskfilter;
+ common = disk/diskfilter.c;
};
module = {
--- /dev/null
+/* diskfilter.c - module to read RAID arrays. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008,2009,2010 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/partition.h>
+#ifdef GRUB_UTIL
+#include <grub/i18n.h>
+#include <grub/util/misc.h>
+#endif
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Linked list of DISKFILTER arrays. */
+static struct grub_diskfilter_vg *array_list;
+grub_raid5_recover_func_t grub_raid5_recover_func;
+grub_raid6_recover_func_t grub_raid6_recover_func;
+grub_diskfilter_t grub_diskfilter_list;
+static int inscnt = 0;
+static int lv_num = 0;
+
+static struct grub_diskfilter_lv *
+find_lv (const char *name);
+static int is_lv_readable (struct grub_diskfilter_lv *lv);
+
+\f
+
+static grub_err_t
+is_node_readable (const struct grub_diskfilter_node *node)
+{
+ /* Check whether we actually know the physical volume we want to
+ read from. */
+ if (node->pv)
+ return !!(node->pv->disk);
+ if (node->lv)
+ return is_lv_readable (node->lv);
+ return 0;
+}
+
+static int
+is_lv_readable (struct grub_diskfilter_lv *lv)
+{
+ unsigned i, j;
+ if (!lv)
+ return 0;
+ for (i = 0; i < lv->segment_count; i++)
+ {
+ int need = lv->segments[i].node_count, have = 0;
+ switch (lv->segments[i].type)
+ {
+ case GRUB_DISKFILTER_RAID6:
+ need--;
+ case GRUB_DISKFILTER_RAID4:
+ case GRUB_DISKFILTER_RAID5:
+ need--;
+ case GRUB_DISKFILTER_STRIPED:
+ break;
+
+ case GRUB_DISKFILTER_MIRROR:
+ need = 1;
+ break;
+
+ case GRUB_DISKFILTER_RAID10:
+ {
+ unsigned int n;
+ n = lv->segments[i].layout & 0xFF;
+ if (n == 1)
+ n = (lv->segments[i].layout >> 8) & 0xFF;
+ need = lv->segments[i].node_count - n + 1;
+ }
+ break;
+ }
+ for (j = 0; j < lv->segments[i].node_count; j++)
+ {
+ if (is_node_readable (lv->segments[i].nodes + j))
+ have++;
+ if (have >= need)
+ break;
+ }
+ if (have < need)
+ return 0;
+ }
+
+ return 1;
+}
+
+static grub_err_t
+insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id,
+ struct grub_diskfilter_vg *array,
+ grub_disk_addr_t start_sector, const char *scanner_name,
+ grub_diskfilter_t diskfilter __attribute__ ((unused)));
+
+static int
+scan_disk (const char *name)
+{
+ auto int hook (grub_disk_t disk, grub_partition_t p);
+ int hook (grub_disk_t disk, grub_partition_t p)
+ {
+ struct grub_diskfilter_vg *arr;
+ grub_disk_addr_t start_sector;
+ struct grub_diskfilter_pv_id id;
+ grub_diskfilter_t diskfilter;
+
+ grub_dprintf ("diskfilter", "Scanning for DISKFILTER devices on disk %s\n",
+ name);
+#ifdef GRUB_UTIL
+ grub_util_info ("Scanning for DISKFILTER devices on disk %s", name);
+#endif
+
+ disk->partition = p;
+
+ for (arr = array_list; arr != NULL; arr = arr->next)
+ {
+ struct grub_diskfilter_pv *m;
+ for (m = arr->pvs; m; m = m->next)
+ if (m->disk && m->disk->id == disk->id
+ && m->disk->dev->id == disk->dev->id
+ && m->part_start == grub_partition_get_start (disk->partition)
+ && m->part_size == grub_disk_get_size (disk))
+ return 0;
+ }
+
+ for (diskfilter = grub_diskfilter_list; diskfilter; diskfilter = diskfilter->next)
+ {
+ id.uuid = 0;
+ id.uuidlen = 0;
+ arr = diskfilter->detect (disk, &id, &start_sector);
+ if (arr &&
+ (! insert_array (disk, &id, arr, start_sector, diskfilter->name,
+ diskfilter)))
+ {
+ if (id.uuidlen)
+ grub_free (id.uuid);
+ return 0;
+ }
+ if (arr && id.uuidlen)
+ grub_free (id.uuid);
+
+ /* This error usually means it's not diskfilter, no need to display
+ it. */
+ if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
+ grub_print_error ();
+
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ return 0;
+ }
+ grub_disk_t disk;
+ static int scan_depth = 0;
+
+ if (scan_depth > 100)
+ return 0;
+
+ disk = grub_disk_open (name);
+ if (!disk)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ scan_depth++;
+ if (hook (disk, 0))
+ return 1;
+ if (grub_partition_iterate (disk, hook))
+ return 1;
+ scan_depth--;
+ grub_disk_close (disk);
+ return 0;
+}
+
+static void
+scan_devices (const char *arname)
+{
+ grub_disk_dev_t p;
+ grub_disk_pull_t pull;
+
+ for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID
+ && p->iterate)
+ {
+ if ((p->iterate) (scan_disk, pull))
+ return;
+ if (arname && is_lv_readable (find_lv (arname)))
+ return;
+ }
+}
+
+static int
+grub_diskfilter_iterate (int (*hook) (const char *name),
+ grub_disk_pull_t pull)
+{
+ struct grub_diskfilter_vg *array;
+ int islcnt = 0;
+
+ if (pull == GRUB_DISK_PULL_RESCAN)
+ {
+ islcnt = inscnt;
+ scan_devices (NULL);
+ }
+
+ if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN)
+ return 0;
+
+ for (array = array_list; array; array = array->next)
+ {
+ struct grub_diskfilter_lv *lv;
+ if (array->lvs)
+ for (lv = array->lvs; lv; lv = lv->next)
+ if (lv->visible && lv->fullname && lv->became_readable_at >= islcnt)
+ {
+ if (hook (lv->fullname))
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef GRUB_UTIL
+static grub_disk_memberlist_t
+grub_diskfilter_memberlist (grub_disk_t disk)
+{
+ struct grub_diskfilter_lv *lv = disk->data;
+ grub_disk_memberlist_t list = NULL, tmp;
+ struct grub_diskfilter_pv *pv;
+
+ if (lv->vg->pvs)
+ for (pv = lv->vg->pvs; pv; pv = pv->next)
+ {
+ if (!pv->disk)
+ grub_util_error (_("Couldn't find PV %s. Check your device.map"),
+ pv->name);
+ tmp = grub_malloc (sizeof (*tmp));
+ tmp->disk = pv->disk;
+ tmp->next = list;
+ list = tmp;
+ }
+
+ return list;
+}
+
+static const char *
+grub_diskfilter_getname (struct grub_disk *disk)
+{
+ struct grub_diskfilter_lv *array = disk->data;
+
+ return array->vg->driver->name;
+}
+#endif
+
+static inline int
+ascii2hex (char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return 0;
+}
+
+static struct grub_diskfilter_lv *
+find_lv (const char *name)
+{
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_lv *lv = NULL;
+
+ if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
+ {
+ const char *uuidstr = name + sizeof ("mduuid/") - 1;
+ grub_size_t uuid_len = grub_strlen (uuidstr) / 2;
+ grub_uint8_t uuidbin[uuid_len];
+ unsigned i;
+ for (i = 0; i < uuid_len; i++)
+ uuidbin[i] = ascii2hex (uuidstr[2 * i + 1])
+ | (ascii2hex (uuidstr[2 * i]) << 4);
+
+ for (vg = array_list; vg; vg = vg->next)
+ {
+ if (uuid_len == vg->uuid_len
+ && grub_memcmp (uuidbin, vg->uuid, uuid_len) == 0)
+ if (is_lv_readable (vg->lvs))
+ return vg->lvs;
+ }
+ }
+
+ for (vg = array_list; vg; vg = vg->next)
+ {
+ if (vg->lvs)
+ for (lv = vg->lvs; lv; lv = lv->next)
+ if (lv->fullname && grub_strcmp (lv->fullname, name) == 0
+ && is_lv_readable (lv))
+ return lv;
+ }
+ return NULL;
+}
+
+static grub_err_t
+grub_diskfilter_open (const char *name, grub_disk_t disk)
+{
+ struct grub_diskfilter_lv *lv;
+
+ if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0
+ && grub_memcmp (name, "lvm/", sizeof ("lvm/") - 1) != 0
+ && grub_memcmp (name, "ldm/", sizeof ("ldm/") - 1) != 0)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown DISKFILTER device %s",
+ name);
+
+ lv = find_lv (name);
+
+ if (! lv)
+ {
+ scan_devices (name);
+ if (grub_errno)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ }
+ lv = find_lv (name);
+ }
+
+ if (!lv)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown DISKFILTER device %s",
+ name);
+
+ disk->id = lv->number;
+ disk->data = lv;
+
+ grub_dprintf ("diskfilter", "%s: total_devs=%d, total_size=%lld\n", name,
+ lv->segments ? lv->segments->node_count : 0,
+ (unsigned long long) lv->size);
+ disk->total_sectors = lv->size;
+ grub_dprintf ("diskfilter", "%s: level=%d, total_sectors=%lld\n", name,
+ lv->segments ? lv->segments->type : 0,
+ (unsigned long long) disk->total_sectors);
+
+ return 0;
+}
+
+static void
+grub_diskfilter_close (grub_disk_t disk __attribute ((unused)))
+{
+ return;
+}
+
+static grub_err_t
+read_lv (struct grub_diskfilter_lv *lv, grub_disk_addr_t sector,
+ grub_size_t size, char *buf);
+
+grub_err_t
+grub_diskfilter_read_node (const struct grub_diskfilter_node *node,
+ grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ /* Check whether we actually know the physical volume we want to
+ read from. */
+ if (node->pv)
+ {
+ if (node->pv->disk)
+ return grub_disk_read (node->pv->disk, sector + node->start
+ + node->pv->start_sector,
+ 0, size << GRUB_DISK_SECTOR_BITS, buf);
+ else
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "physical volume %s not found", node->pv->name);
+
+ }
+ if (node->lv)
+ return read_lv (node->lv, sector + node->start, size, buf);
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown node '%s'", node->name);
+}
+
+static grub_err_t
+read_segment (struct grub_diskfilter_segment *seg, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ grub_err_t err;
+ switch (seg->type)
+ {
+ case GRUB_DISKFILTER_STRIPED:
+ if (seg->node_count == 1)
+ return grub_diskfilter_read_node (&seg->nodes[0],
+ sector, size, buf);
+ case GRUB_DISKFILTER_MIRROR:
+ case GRUB_DISKFILTER_RAID10:
+ {
+ grub_disk_addr_t read_sector, far_ofs;
+ grub_uint64_t disknr, b, near, far, ofs;
+ unsigned int i, j;
+
+ read_sector = grub_divmod64 (sector, seg->stripe_size, &b);
+ far = ofs = near = 1;
+ far_ofs = 0;
+
+ if (seg->type == 1)
+ near = seg->node_count;
+ else if (seg->type == 10)
+ {
+ near = seg->layout & 0xFF;
+ far = (seg->layout >> 8) & 0xFF;
+ if (seg->layout >> 16)
+ {
+ ofs = far;
+ far_ofs = 1;
+ }
+ else
+ far_ofs = grub_divmod64 (seg->raid_member_size,
+ far * seg->stripe_size, 0);
+
+ far_ofs *= seg->stripe_size;
+ }
+
+ read_sector = grub_divmod64 (read_sector * near,
+ seg->node_count,
+ &disknr);
+
+ ofs *= seg->stripe_size;
+ read_sector *= ofs;
+
+ while (1)
+ {
+ grub_size_t read_size;
+
+ read_size = seg->stripe_size - b;
+ if (read_size > size)
+ read_size = size;
+
+ for (i = 0; i < near; i++)
+ {
+ unsigned int k;
+
+ k = disknr;
+ for (j = 0; j < far; j++)
+ {
+ if (grub_errno == GRUB_ERR_READ_ERROR
+ || grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+ grub_errno = GRUB_ERR_NONE;
+
+ err = grub_diskfilter_read_node (&seg->nodes[k],
+ read_sector
+ + j * far_ofs + b,
+ read_size,
+ buf);
+ if (! err)
+ break;
+ else if (err != GRUB_ERR_READ_ERROR
+ && err != GRUB_ERR_UNKNOWN_DEVICE)
+ return err;
+ k++;
+ if (k == seg->node_count)
+ k = 0;
+ }
+
+ if (! err)
+ break;
+
+ disknr++;
+ if (disknr == seg->node_count)
+ {
+ disknr = 0;
+ read_sector += ofs;
+ }
+ }
+
+ if (err)
+ return err;
+
+ buf += read_size << GRUB_DISK_SECTOR_BITS;
+ size -= read_size;
+ if (! size)
+ return GRUB_ERR_NONE;
+
+ b = 0;
+ disknr += (near - i);
+ while (disknr >= seg->node_count)
+ {
+ disknr -= seg->node_count;
+ read_sector += ofs;
+ }
+ }
+ }
+ return GRUB_ERR_NONE;
+
+ case GRUB_DISKFILTER_RAID4:
+ case GRUB_DISKFILTER_RAID5:
+ case GRUB_DISKFILTER_RAID6:
+ {
+ grub_disk_addr_t read_sector;
+ grub_uint64_t b, p, n, disknr, e;
+
+ /* n = 1 for level 4 and 5, 2 for level 6. */
+ n = seg->type / 3;
+
+ /* Find the first sector to read. */
+ read_sector = grub_divmod64 (sector, seg->stripe_size, &b);
+ read_sector = grub_divmod64 (read_sector, seg->node_count - n,
+ &disknr);
+ if (seg->type >= 5)
+ {
+ grub_divmod64 (read_sector, seg->node_count, &p);
+
+ if (! (seg->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
+ p = seg->node_count - 1 - p;
+
+ if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
+ {
+ disknr += p + n;
+ }
+ else
+ {
+ grub_uint32_t q;
+
+ q = p + (n - 1);
+ if (q >= seg->node_count)
+ q -= seg->node_count;
+
+ if (disknr >= p)
+ disknr += n;
+ else if (disknr >= q)
+ disknr += q + 1;
+ }
+
+ if (disknr >= seg->node_count)
+ disknr -= seg->node_count;
+ }
+ else
+ p = seg->node_count - n;
+ read_sector *= seg->stripe_size;
+
+ while (1)
+ {
+ grub_size_t read_size;
+ int next_level;
+
+ read_size = seg->stripe_size - b;
+ if (read_size > size)
+ read_size = size;
+
+ e = 0;
+ /* Reset read error. */
+ if (grub_errno == GRUB_ERR_READ_ERROR
+ || grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+ grub_errno = GRUB_ERR_NONE;
+
+ err = grub_diskfilter_read_node (&seg->nodes[disknr],
+ read_sector + b,
+ read_size,
+ buf);
+
+ if ((err) && (err != GRUB_ERR_READ_ERROR
+ && err != GRUB_ERR_UNKNOWN_DEVICE))
+ return err;
+ e++;
+
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ if (seg->type == GRUB_DISKFILTER_RAID6)
+ {
+ err = ((grub_raid6_recover_func) ?
+ (*grub_raid6_recover_func) (seg, disknr, p,
+ buf, read_sector + b,
+ read_size) :
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "raid6rec is not loaded"));
+ }
+ else
+ {
+ err = ((grub_raid5_recover_func) ?
+ (*grub_raid5_recover_func) (seg, disknr,
+ buf, read_sector + b,
+ read_size) :
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "raid5rec is not loaded"));
+ }
+
+ if (err)
+ return err;
+ }
+
+ buf += read_size << GRUB_DISK_SECTOR_BITS;
+ size -= read_size;
+ sector += read_size;
+ if (! size)
+ break;
+
+ b = 0;
+ disknr++;
+
+ if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
+ {
+ if (disknr == seg->node_count)
+ disknr = 0;
+
+ next_level = (disknr == p);
+ }
+ else
+ {
+ if (disknr == p)
+ disknr += n;
+
+ next_level = (disknr >= seg->node_count);
+ }
+
+ if (next_level)
+ {
+ read_sector += seg->stripe_size;
+
+ if (seg->type >= 5)
+ {
+ if (seg->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
+ p = (p == seg->node_count - 1) ? 0 : p + 1;
+ else
+ p = (p == 0) ? seg->node_count - 1 : p - 1;
+
+ if (seg->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
+ {
+ disknr = p + n;
+ if (disknr >= seg->node_count)
+ disknr -= seg->node_count;
+ }
+ else
+ {
+ disknr -= seg->node_count;
+ if (disknr == p)
+ disknr += n;
+ }
+ }
+ else
+ disknr = 0;
+ }
+ }
+ }
+ return GRUB_ERR_NONE;
+ default:
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported RAID level %d", seg->type);
+ }
+}
+
+static grub_err_t
+read_lv (struct grub_diskfilter_lv *lv, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ if (!lv)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume");
+
+ while (size)
+ {
+ grub_err_t err = 0;
+ struct grub_diskfilter_vg *vg = lv->vg;
+ struct grub_diskfilter_segment *seg = lv->segments;
+ grub_uint64_t extent;
+ grub_size_t to_read;
+
+ extent = grub_divmod64 (sector, vg->extent_size, NULL);
+
+ /* Find the right segment. */
+ {
+ unsigned int i;
+ for (i = 0; i < lv->segment_count; i++)
+ {
+ if ((seg->start_extent <= extent)
+ && ((seg->start_extent + seg->extent_count) > extent))
+ break;
+ seg++;
+ }
+ if (i == lv->segment_count)
+ return grub_error (GRUB_ERR_READ_ERROR, "incorrect segment");
+ }
+ to_read = ((seg->start_extent + seg->extent_count)
+ * vg->extent_size) - sector;
+ if (to_read > size)
+ to_read = size;
+
+ err = read_segment (seg, sector - seg->start_extent * vg->extent_size,
+ to_read, buf);
+ if (err)
+ return err;
+
+ size -= to_read;
+ sector += to_read;
+ buf += to_read << GRUB_DISK_SECTOR_BITS;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_diskfilter_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
+ return read_lv (disk->data, sector, size, buf);
+}
+
+static grub_err_t
+grub_diskfilter_write (grub_disk_t disk __attribute ((unused)),
+ grub_disk_addr_t sector __attribute ((unused)),
+ grub_size_t size __attribute ((unused)),
+ const char *buf __attribute ((unused)))
+{
+ return GRUB_ERR_NOT_IMPLEMENTED_YET;
+}
+
+struct grub_diskfilter_vg *
+grub_diskfilter_get_vg_by_uuid (grub_size_t uuidlen, char *uuid)
+{
+ struct grub_diskfilter_vg *p;
+
+ for (p = array_list; p != NULL; p = p->next)
+ if ((p->uuid_len == uuidlen) &&
+ (! grub_memcmp (p->uuid, uuid, p->uuid_len)))
+ return p;
+ return NULL;
+}
+
+grub_err_t
+grub_diskfilter_vg_register (struct grub_diskfilter_vg *vg)
+{
+ struct grub_diskfilter_lv *lv, *p;
+ struct grub_diskfilter_vg *vgp;
+ unsigned i;
+
+ grub_dprintf ("diskfilter", "Found array %s\n", vg->name);
+#ifdef GRUB_UTIL
+ grub_util_info ("Found array %s", vg->name);
+#endif
+
+ for (lv = vg->lvs; lv; lv = lv->next)
+ {
+ lv->number = lv_num++;
+
+ if (lv->fullname)
+ {
+ grub_size_t len;
+ int max_used_number = 0, need_new_name = 0;
+ len = grub_strlen (lv->fullname);
+ for (vgp = array_list; vgp; vgp = vgp->next)
+ for (p = vgp->lvs; p; p = p->next)
+ {
+ int cur_num;
+ char *num, *end;
+ if (!p->fullname)
+ continue;
+ if (grub_strncmp (p->fullname, lv->fullname, len) != 0)
+ continue;
+ if (p->fullname[len] == 0)
+ {
+ need_new_name = 1;
+ continue;
+ }
+ num = p->fullname + len + 1;
+ if (!grub_isdigit (num[0]))
+ continue;
+ cur_num = grub_strtoul (num, &end, 10);
+ if (end[0])
+ continue;
+ if (cur_num > max_used_number)
+ max_used_number = cur_num;
+ }
+ if (need_new_name)
+ {
+ char *tmp;
+ tmp = grub_xasprintf ("%s_%d", lv->fullname, max_used_number + 1);
+ if (!tmp)
+ return grub_errno;
+ grub_free (lv->fullname);
+ lv->fullname = tmp;
+ }
+ }
+ /* RAID 1 doesn't use a chunksize but code assumes one so set
+ one. */
+ for (i = 0; i < lv->segment_count; i++)
+ if (lv->segments[i].type == 1)
+ lv->segments[i].stripe_size = 64;
+ lv->vg = vg;
+ }
+ /* Add our new array to the list. */
+ vg->next = array_list;
+ array_list = vg;
+ return GRUB_ERR_NONE;
+}
+
+struct grub_diskfilter_vg *
+grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb,
+ char *name, grub_uint64_t disk_size,
+ grub_uint64_t stripe_size,
+ int layout, int level)
+{
+ struct grub_diskfilter_vg *array;
+ int i;
+ grub_uint64_t totsize;
+ struct grub_diskfilter_pv *pv;
+ grub_err_t err;
+
+ switch (level)
+ {
+ case 1:
+ totsize = disk_size;
+ break;
+
+ case 10:
+ {
+ int n;
+ n = layout & 0xFF;
+ if (n == 1)
+ n = (layout >> 8) & 0xFF;
+
+ totsize = grub_divmod64 (nmemb * disk_size, n, 0);
+ }
+ break;
+
+ case 0:
+ case 4:
+ case 5:
+ case 6:
+ totsize = (nmemb - level / 3) * disk_size;
+ break;
+ }
+
+ array = grub_diskfilter_get_vg_by_uuid (uuidlen, uuid);
+ if (array)
+ {
+ if (array->lvs && array->lvs->size < totsize)
+ {
+ array->lvs->size = totsize;
+ if (array->lvs->segments)
+ array->lvs->segments->extent_count = totsize;
+ }
+
+ if (array->lvs->segments
+ && array->lvs->segments->raid_member_size > disk_size)
+ array->lvs->segments->raid_member_size = disk_size;
+
+ grub_free (uuid);
+ return array;
+ }
+ array = grub_zalloc (sizeof (*array));
+ if (!array)
+ return NULL;
+ array->uuid = uuid;
+ array->uuid_len = uuidlen;
+ if (name)
+ {
+ /* Strip off the homehost if present. */
+ char *colon = grub_strchr (name, ':');
+ char *new_name = grub_xasprintf ("md/%s",
+ colon ? colon + 1 : name);
+
+ if (! new_name)
+ goto fail;
+
+ array->name = new_name;
+ }
+ array->extent_size = 1;
+ array->lvs = grub_zalloc (sizeof (*array->lvs));
+ if (!array->lvs)
+ goto fail;
+ array->lvs->segment_count = 1;
+ array->lvs->visible = 1;
+ array->lvs->name = array->name;
+ array->lvs->fullname = array->name;
+
+ array->lvs->size = totsize;
+
+ array->lvs->segments = grub_zalloc (sizeof (*array->lvs->segments));
+ if (!array->lvs->segments)
+ goto fail;
+ array->lvs->segments->stripe_size = stripe_size;
+ array->lvs->segments->layout = layout;
+ array->lvs->segments->start_extent = 0;
+ array->lvs->segments->extent_count = totsize;
+ array->lvs->segments->type = level;
+ array->lvs->segments->node_count = nmemb;
+ array->lvs->segments->raid_member_size = disk_size;
+ array->lvs->segments->nodes
+ = grub_zalloc (nmemb * sizeof (array->lvs->segments->nodes[0]));
+ array->lvs->segments->stripe_size = stripe_size;
+ for (i = 0; i < nmemb; i++)
+ {
+ pv = grub_zalloc (sizeof (*pv));
+ if (!pv)
+ goto fail;
+ pv->id.uuidlen = 0;
+ pv->id.id = i;
+ pv->next = array->pvs;
+ array->pvs = pv;
+ array->lvs->segments->nodes[i].pv = pv;
+ }
+
+ err = grub_diskfilter_vg_register (array);
+ if (err)
+ goto fail;
+
+ return array;
+
+ fail:
+ grub_free (array->lvs);
+ while (array->pvs)
+ {
+ pv = array->pvs->next;
+ grub_free (array->pvs);
+ array->pvs = pv;
+ }
+ grub_free (array);
+ return NULL;
+}
+
+static grub_err_t
+insert_array (grub_disk_t disk, const struct grub_diskfilter_pv_id *id,
+ struct grub_diskfilter_vg *array,
+ grub_disk_addr_t start_sector, const char *scanner_name,
+ grub_diskfilter_t diskfilter __attribute__ ((unused)))
+{
+ struct grub_diskfilter_pv *pv;
+
+ grub_dprintf ("diskfilter", "Inserting %s into %s (%s)\n", disk->name,
+ array->name, scanner_name);
+#ifdef GRUB_UTIL
+ grub_util_info ("Inserting %s into %s (%s)\n", disk->name,
+ array->name, scanner_name);
+ array->driver = diskfilter;
+#endif
+
+ for (pv = array->pvs; pv; pv = pv->next)
+ if (id->uuidlen == pv->id.uuidlen
+ && id->uuidlen
+ ? (grub_memcmp (pv->id.uuid, id->uuid, id->uuidlen) == 0)
+ : (pv->id.id == id->id))
+ {
+ struct grub_diskfilter_lv *lv;
+ /* FIXME: Check whether the update time of the superblocks are
+ the same. */
+ /* This could happen to LVM on RAID, pv->disk points to the
+ raid device, we shouldn't change it. */
+ if (! pv->disk)
+ {
+ pv->disk = grub_disk_open (disk->name);
+ if (! pv->disk)
+ return grub_errno;
+ pv->part_start = grub_partition_get_start (disk->partition);
+ pv->part_size = grub_disk_get_size (disk);
+
+ if (start_sector != (grub_uint64_t)-1)
+ pv->start_sector = start_sector;
+ pv->start_sector += pv->part_start;
+ }
+ /* Add the device to the array. */
+ for (lv = array->lvs; lv; lv = lv->next)
+ if (!lv->became_readable_at && lv->fullname && is_lv_readable (lv))
+ {
+ lv->became_readable_at = ++inscnt;
+ scan_disk (lv->fullname);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static void
+free_array (void)
+{
+ while (array_list)
+ {
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_pv *pv;
+ struct grub_diskfilter_lv *lv;
+
+ vg = array_list;
+ array_list = array_list->next;
+
+ while ((pv = vg->pvs))
+ {
+ vg->pvs = pv->next;
+ grub_free (pv->name);
+ if (pv->disk)
+ grub_disk_close (pv->disk);
+ if (pv->id.uuidlen)
+ grub_free (pv->id.uuid);
+ grub_free (pv->internal_id);
+ grub_free (pv);
+ }
+
+ while ((lv = vg->lvs))
+ {
+ unsigned i;
+ vg->lvs = lv->next;
+ if (lv->name != lv->fullname)
+ grub_free (lv->fullname);
+ if (lv->name != vg->name)
+ grub_free (lv->name);
+ for (i = 0; i < lv->segment_count; i++)
+ grub_free (lv->segments[i].nodes);
+ grub_free (lv->segments);
+ grub_free (lv->internal_id);
+ grub_free (lv);
+ }
+
+ grub_free (vg->uuid);
+ grub_free (vg->name);
+ grub_free (vg);
+ }
+
+ array_list = 0;
+}
+
+#ifdef GRUB_UTIL
+struct grub_diskfilter_pv *
+grub_diskfilter_get_pv_from_disk (grub_disk_t disk,
+ struct grub_diskfilter_vg **vg_out)
+{
+ struct grub_diskfilter_pv *pv;
+ struct grub_diskfilter_vg *vg;
+
+ scan_disk (disk->name);
+ for (vg = array_list; vg; vg = vg->next)
+ for (pv = vg->pvs; pv; pv = pv->next)
+ {
+ if (pv->disk && pv->disk->id == disk->id
+ && pv->disk->dev->id == disk->dev->id
+ && pv->part_start == grub_partition_get_start (disk->partition)
+ && pv->part_size == grub_disk_get_size (disk))
+ {
+ if (vg_out)
+ *vg_out = vg;
+ return pv;
+ }
+ }
+ return NULL;
+}
+#endif
+
+static struct grub_disk_dev grub_diskfilter_dev =
+ {
+ .name = "diskfilter",
+ .id = GRUB_DISK_DEVICE_DISKFILTER_ID,
+ .iterate = grub_diskfilter_iterate,
+ .open = grub_diskfilter_open,
+ .close = grub_diskfilter_close,
+ .read = grub_diskfilter_read,
+ .write = grub_diskfilter_write,
+#ifdef GRUB_UTIL
+ .memberlist = grub_diskfilter_memberlist,
+ .raidname = grub_diskfilter_getname,
+#endif
+ .next = 0
+ };
+
+\f
+GRUB_MOD_INIT(diskfilter)
+{
+ grub_disk_dev_register (&grub_diskfilter_dev);
+}
+
+GRUB_MOD_FINI(diskfilter)
+{
+ grub_disk_dev_unregister (&grub_diskfilter_dev);
+ free_array ();
+}
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
GRUB_MOD_LICENSE ("GPLv3+");
struct grub_nv_array array; /* Array information */
} __attribute__ ((packed));
-static grub_err_t
-grub_dmraid_nv_detect (grub_disk_t disk, struct grub_raid_array *array,
- grub_disk_addr_t *start_sector)
+static struct grub_diskfilter_vg *
+grub_dmraid_nv_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
+ grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector;
struct grub_nv_super sb;
+ int level;
+ int layout;
+ grub_uint64_t disk_size;
+ char *uuid;
if (disk->partition)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "skip partition");
+ return NULL;
+ }
sector = grub_disk_get_size (disk);
if (sector == GRUB_DISK_SIZE_UNKNOWN)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
+ return NULL;
+ }
sector -= 2;
if (grub_disk_read (disk, sector, 0, sizeof (sb), &sb))
- return grub_errno;
+ return NULL;
if (grub_memcmp (sb.vendor, NV_ID_STRING, 6))
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not raid");
+ return NULL;
+ }
if (sb.version != NV_VERSION)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unknown version: %d.%d", sb.version);
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unknown version: %d.%d", sb.version);
+ return NULL;
+ }
switch (sb.array.raid_level)
{
case NV_LEVEL_0:
- array->level = 0;
- array->disk_size = sb.capacity / sb.array.total_volumes;
+ level = 0;
+ disk_size = sb.capacity / sb.array.total_volumes;
break;
case NV_LEVEL_1:
- array->level = 1;
- array->disk_size = sb.capacity;
+ level = 1;
+ disk_size = sb.capacity;
break;
case NV_LEVEL_5:
- array->level = 5;
- array->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
- array->disk_size = sb.capacity / (sb.array.total_volumes - 1);
+ level = 5;
+ layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
+ disk_size = sb.capacity / (sb.array.total_volumes - 1);
break;
default:
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unsupported RAID level: %d", sb.array.raid_level);
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported RAID level: %d", sb.array.raid_level);
+ return NULL;
}
- array->name = NULL;
- array->number = 0;
- array->total_devs = sb.array.total_volumes;
- array->chunk_size = sb.array.stripe_block_size;
- array->index = sb.unit_number;
- array->uuid_len = sizeof (sb.array.signature);
- array->uuid = grub_malloc (sizeof (sb.array.signature));
- if (! array->uuid)
- return grub_errno;
-
- grub_memcpy (array->uuid, (char *) &sb.array.signature,
+ uuid = grub_malloc (sizeof (sb.array.signature));
+ if (! uuid)
+ return NULL;
+
+ grub_memcpy (uuid, (char *) &sb.array.signature,
sizeof (sb.array.signature));
+ id->uuidlen = 0;
+ id->id = sb.unit_number;
+
*start_sector = 0;
- return 0;
+ return grub_diskfilter_make_raid (sizeof (sb.array.signature),
+ uuid, sb.array.total_volumes,
+ NULL, disk_size,
+ sb.array.stripe_block_size, layout,
+ level);
}
-static struct grub_raid grub_dmraid_nv_dev =
+static struct grub_diskfilter grub_dmraid_nv_dev =
{
.name = "dmraid_nv",
.detect = grub_dmraid_nv_detect,
GRUB_MOD_INIT(dm_nv)
{
- grub_raid_register (&grub_dmraid_nv_dev);
+ grub_diskfilter_register (&grub_dmraid_nv_dev);
}
GRUB_MOD_FINI(dm_nv)
{
- grub_raid_unregister (&grub_dmraid_nv_dev);
+ grub_diskfilter_unregister (&grub_dmraid_nv_dev);
}
--- /dev/null
+/*
+ * 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/gpt_partition.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];
+} __attribute__ ((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;
+} __attribute__ ((packed));
+
+
+#define LDM_MAGIC "PRIVHEAD"
+
+\f
+
+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 const grub_gpt_part_type_t ldm_type = GRUB_GPT_PARTITION_TYPE_LDM;
+
+static grub_disk_addr_t
+gpt_ldm_sector (grub_disk_t dsk)
+{
+ grub_disk_addr_t sector = 0;
+ grub_err_t err;
+ auto int hook (grub_disk_t disk, const grub_partition_t p);
+ int hook (grub_disk_t disk, const grub_partition_t p)
+ {
+ 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;
+ }
+ err = grub_gpt_partition_map_iterate (dsk, hook);
+ 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;
+ 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 index;
+ ptr += *ptr + 1;
+ if (ptr + *ptr + 1 >= vblk[i].dynamic
+ + sizeof (vblk[i].dynamic))
+ {
+ goto fail2;
+ }
+ index = read_int (ptr + 1, *ptr);
+ if (index < comp->segments->node_count)
+ comp->segments->nodes[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;
+ for (i = 0; i < 3; i++)
+ {
+ grub_disk_addr_t sector;
+ switch (i)
+ {
+ case 0:
+ sector = LDM_LABEL_SECTOR;
+ break;
+ case 1:
+ /* LDM is never inside a partition. */
+ if (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, *lv;
+ int i;
+
+ 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;
+ break;
+ }
+ 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 == lv)
+ {
+ res = lv;
+ break;
+ }
+ if (res->fullname)
+ return grub_strdup (lv->fullname);
+ return NULL;
+}
+
+int
+grub_util_is_ldm (grub_disk_t disk)
+{
+ int i;
+ for (i = 0; i < 3; i++)
+ {
+ grub_disk_addr_t sector;
+ grub_err_t err;
+ struct grub_ldm_label label;
+
+ switch (i)
+ {
+ case 0:
+ sector = LDM_LABEL_SECTOR;
+ break;
+ case 1:
+ /* LDM is never inside a partition. */
+ if (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,
+ 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,
+ "GPT curently supports only PC-BIOS embedding");
+ if (disk->partition)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM");
+ pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
+ if (!pv)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "disk isn't LDM");
+ for (lv = vg->lvs; lv; lv = lv->next)
+ {
+ struct grub_diskfilter_lv *comp;
+ struct grub_ldm_partition *part;
+
+ 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,
+ "Your LDM embed Partition is too small;"
+ " embedding won't be possible!");
+ *nsectors = lv->size;
+ *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,
+ "This LDM 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 (&grub_ldm_dev);
+}
+
+GRUB_MOD_FINI (ldm)
+{
+ grub_diskfilter_unregister (&grub_ldm_dev);
+}
GRUB_MOD_LICENSE ("GPLv3+");
-static struct grub_lvm_vg *vg_list;
-static int lv_count;
-static int scan_depth = 0;
-
-static int is_lv_readable (struct grub_lvm_lv *lv);
-
\f
/* Go the string STR and return the number after STR. *P will point
at the number. In case STR is not found, *P will be NULL and the
if (! *p)
return 0;
*p += grub_strlen (str);
- return grub_strtoul (*p, NULL, 10);
+ return grub_strtoul (*p, p, 10);
}
#if 0
}
}
-static struct grub_lvm_lv *
-find_lv (const char *name)
+static struct grub_diskfilter_vg *
+grub_lvm_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
+ grub_disk_addr_t *start_sector)
{
- struct grub_lvm_vg *vg;
- struct grub_lvm_lv *lv = NULL;
- for (vg = vg_list; vg; vg = vg->next)
+ grub_err_t err;
+ grub_uint64_t mda_offset, mda_size;
+ char buf[GRUB_LVM_LABEL_SIZE];
+ char vg_id[GRUB_LVM_ID_STRLEN+1];
+ char pv_id[GRUB_LVM_ID_STRLEN+1];
+ char *metadatabuf, *p, *q, *vgname;
+ struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
+ struct grub_lvm_pv_header *pvh;
+ struct grub_lvm_disk_locn *dlocn;
+ struct grub_lvm_mda_header *mdah;
+ struct grub_lvm_raw_locn *rlocn;
+ unsigned int i, j, vgname_len;
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_pv *pv;
+
+ /* Search for label. */
+ for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
{
- if (vg->lvs)
- for (lv = vg->lvs; lv; lv = lv->next)
- if ((grub_strcmp (lv->fullname, name) == 0
- || grub_strcmp (lv->compatname, name) == 0)
- && is_lv_readable (lv))
- return lv;
- }
- return NULL;
-}
+ err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
+ if (err)
+ goto fail;
-static void
-do_lvm_scan (const char *scan_for)
-{
- auto int grub_lvm_scan_device (const char *name);
- int grub_lvm_scan_device (const char *name)
- {
- grub_err_t err;
- grub_disk_t disk;
- grub_uint64_t mda_offset, mda_size;
- char buf[GRUB_LVM_LABEL_SIZE];
- char vg_id[GRUB_LVM_ID_STRLEN+1];
- char pv_id[GRUB_LVM_ID_STRLEN+1];
- char *metadatabuf, *p, *q, *vgname;
- struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
- struct grub_lvm_pv_header *pvh;
- struct grub_lvm_disk_locn *dlocn;
- struct grub_lvm_mda_header *mdah;
- struct grub_lvm_raw_locn *rlocn;
- unsigned int i, j, vgname_len;
- struct grub_lvm_vg *vg;
- struct grub_lvm_pv *pv;
+ if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
+ sizeof (lh->id)))
+ && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
+ sizeof (lh->type))))
+ break;
+ }
+ /* Return if we didn't find a label. */
+ if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("scanning %s for LVM", name);
+ grub_util_info ("no LVM signature found");
#endif
+ goto fail;
+ }
- disk = grub_disk_open (name);
- if (!disk)
- {
- if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
- grub_errno = GRUB_ERR_NONE;
- return 0;
- }
+ pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
- for (vg = vg_list; vg; vg = vg->next)
- for (pv = vg->pvs; pv; pv = pv->next)
- if (pv->disk && pv->disk->id == disk->id
- && pv->disk->dev->id == disk->dev->id
- && grub_partition_get_start (pv->disk->partition)
- == grub_partition_get_start (disk->partition)
- && grub_disk_get_size (pv->disk)
- == grub_disk_get_size (disk))
- {
- grub_disk_close (disk);
- return 0;
- }
+ for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
+ {
+ pv_id[j++] = pvh->pv_uuid[i];
+ if ((i != 1) && (i != 29) && (i % 4 == 1))
+ pv_id[j++] = '-';
+ }
+ pv_id[j] = '\0';
- /* Search for label. */
- for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
- {
- err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
- if (err)
- goto fail;
-
- if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
- sizeof (lh->id)))
- && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
- sizeof (lh->type))))
- break;
- }
+ dlocn = pvh->disk_areas_xl;
+
+ dlocn++;
+ /* Is it possible to have multiple data/metadata areas? I haven't
+ seen devices that have it. */
+ if (dlocn->offset)
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "we don't support multiple LVM data areas");
- /* Return if we didn't find a label. */
- if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
- {
#ifdef GRUB_UTIL
- grub_util_info ("no LVM signature found");
+ grub_util_info ("we don't support multiple LVM data areas\n");
#endif
- goto fail;
- }
+ goto fail;
+ }
- pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
+ dlocn++;
+ mda_offset = grub_le_to_cpu64 (dlocn->offset);
+ mda_size = grub_le_to_cpu64 (dlocn->size);
- for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
- {
- pv_id[j++] = pvh->pv_uuid[i];
- if ((i != 1) && (i != 29) && (i % 4 == 1))
- pv_id[j++] = '-';
- }
- pv_id[j] = '\0';
+ /* It's possible to have multiple copies of metadata areas, we just use the
+ first one. */
- dlocn = pvh->disk_areas_xl;
+ /* Allocate buffer space for the circular worst-case scenario. */
+ metadatabuf = grub_malloc (2 * mda_size);
+ if (! metadatabuf)
+ goto fail;
- dlocn++;
- /* Is it possible to have multiple data/metadata areas? I haven't
- seen devices that have it. */
- if (dlocn->offset)
- {
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "we don't support multiple LVM data areas");
+ err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf);
+ if (err)
+ goto fail2;
+ mdah = (struct grub_lvm_mda_header *) metadatabuf;
+ if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC,
+ sizeof (mdah->magic)))
+ || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION))
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unknown LVM metadata header");
#ifdef GRUB_UTIL
- grub_util_info ("we don't support multiple LVM data areas\n");
+ grub_util_info ("unknown LVM metadata header\n");
#endif
- goto fail;
- }
-
- dlocn++;
- mda_offset = grub_le_to_cpu64 (dlocn->offset);
- mda_size = grub_le_to_cpu64 (dlocn->size);
-
- /* It's possible to have multiple copies of metadata areas, we just use the
- first one. */
+ goto fail2;
+ }
- /* Allocate buffer space for the circular worst-case scenario. */
- metadatabuf = grub_malloc (2 * mda_size);
- if (! metadatabuf)
- goto fail;
+ rlocn = mdah->raw_locns;
+ if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) >
+ grub_le_to_cpu64 (mdah->size))
+ {
+ /* Metadata is circular. Copy the wrap in place. */
+ grub_memcpy (metadatabuf + mda_size,
+ metadatabuf + GRUB_LVM_MDA_HEADER_SIZE,
+ grub_le_to_cpu64 (rlocn->offset) +
+ grub_le_to_cpu64 (rlocn->size) -
+ grub_le_to_cpu64 (mdah->size));
+ }
+ p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset);
- err = grub_disk_read (disk, 0, mda_offset, mda_size, metadatabuf);
- if (err)
- goto fail2;
+ while (*q != ' ' && q < metadatabuf + mda_size)
+ q++;
- mdah = (struct grub_lvm_mda_header *) metadatabuf;
- if ((grub_strncmp ((char *)mdah->magic, GRUB_LVM_FMTT_MAGIC,
- sizeof (mdah->magic)))
- || (grub_le_to_cpu32 (mdah->version) != GRUB_LVM_FMTT_VERSION))
- {
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unknown LVM metadata header");
+ if (q == metadatabuf + mda_size)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown LVM metadata header\n");
+ grub_util_info ("error parsing metadata\n");
#endif
- goto fail2;
- }
+ goto fail2;
+ }
- rlocn = mdah->raw_locns;
- if (grub_le_to_cpu64 (rlocn->offset) + grub_le_to_cpu64 (rlocn->size) >
- grub_le_to_cpu64 (mdah->size))
- {
- /* Metadata is circular. Copy the wrap in place. */
- grub_memcpy (metadatabuf + mda_size,
- metadatabuf + GRUB_LVM_MDA_HEADER_SIZE,
- grub_le_to_cpu64 (rlocn->offset) +
- grub_le_to_cpu64 (rlocn->size) -
- grub_le_to_cpu64 (mdah->size));
- }
- p = q = metadatabuf + grub_le_to_cpu64 (rlocn->offset);
+ vgname_len = q - p;
+ vgname = grub_malloc (vgname_len + 1);
+ if (!vgname)
+ goto fail2;
- while (*q != ' ' && q < metadatabuf + mda_size)
- q++;
+ grub_memcpy (vgname, p, vgname_len);
+ vgname[vgname_len] = '\0';
- if (q == metadatabuf + mda_size)
- {
+ p = grub_strstr (q, "id = \"");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("error parsing metadata\n");
+ grub_util_info ("couldn't find ID\n");
#endif
- goto fail2;
- }
-
- vgname_len = q - p;
- vgname = grub_malloc (vgname_len + 1);
- if (!vgname)
- goto fail2;
+ goto fail3;
+ }
+ p += sizeof ("id = \"") - 1;
+ grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
+ vg_id[GRUB_LVM_ID_STRLEN] = '\0';
- grub_memcpy (vgname, p, vgname_len);
- vgname[vgname_len] = '\0';
+ vg = grub_diskfilter_get_vg_by_uuid (GRUB_LVM_ID_STRLEN, vg_id);
- p = grub_strstr (q, "id = \"");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("couldn't find ID\n");
-#endif
+ if (! vg)
+ {
+ /* First time we see this volume group. We've to create the
+ whole volume group structure. */
+ vg = grub_malloc (sizeof (*vg));
+ if (! vg)
goto fail3;
- }
- p += sizeof ("id = \"") - 1;
- grub_memcpy (vg_id, p, GRUB_LVM_ID_STRLEN);
- vg_id[GRUB_LVM_ID_STRLEN] = '\0';
-
- for (vg = vg_list; vg; vg = vg->next)
- {
- if (! grub_memcmp(vg_id, vg->id, GRUB_LVM_ID_STRLEN))
- break;
- }
+ vg->name = vgname;
+ vg->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
+ if (! vg->uuid)
+ goto fail3;
+ grub_memcpy (vg->uuid, vg_id, GRUB_LVM_ID_STRLEN);
+ vg->uuid_len = GRUB_LVM_ID_STRLEN;
- if (! vg)
- {
- /* First time we see this volume group. We've to create the
- whole volume group structure. */
- vg = grub_malloc (sizeof (*vg));
- if (! vg)
- goto fail3;
- vg->name = vgname;
- grub_memcpy (vg->id, vg_id, GRUB_LVM_ID_STRLEN+1);
-
- vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
- if (p == NULL)
- {
+ vg->extent_size = grub_lvm_getvalue (&p, "extent_size = ");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown extent size\n");
+ grub_util_info ("unknown extent size\n");
#endif
- goto fail4;
- }
+ goto fail4;
+ }
- vg->lvs = NULL;
- vg->pvs = NULL;
+ vg->lvs = NULL;
+ vg->pvs = NULL;
- p = grub_strstr (p, "physical_volumes {");
- if (p)
- {
- p += 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)
- {
- int s;
- while (grub_isspace (*p))
- p++;
+ /* Add all the pvs to the volume group. */
+ while (1)
+ {
+ int s;
+ while (grub_isspace (*p))
+ p++;
- if (*p == '}')
- break;
+ if (*p == '}')
+ break;
- pv = grub_malloc (sizeof (*pv));
- q = p;
- while (*q != ' ')
- q++;
+ pv = grub_zalloc (sizeof (*pv));
+ q = p;
+ while (*q != ' ')
+ q++;
- s = q - p;
- pv->name = grub_malloc (s + 1);
- grub_memcpy (pv->name, p, s);
- pv->name[s] = '\0';
+ s = q - p;
+ pv->name = grub_malloc (s + 1);
+ grub_memcpy (pv->name, p, s);
+ pv->name[s] = '\0';
- p = grub_strstr (p, "id = \"");
- if (p == NULL)
- goto pvs_fail;
- p += sizeof("id = \"") - 1;
+ p = grub_strstr (p, "id = \"");
+ if (p == NULL)
+ goto pvs_fail;
+ p += sizeof("id = \"") - 1;
- grub_memcpy (pv->id, p, GRUB_LVM_ID_STRLEN);
- pv->id[GRUB_LVM_ID_STRLEN] = '\0';
+ pv->id.uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
+ if (!pv->id.uuid)
+ goto pvs_fail;
+ grub_memcpy (pv->id.uuid, p, GRUB_LVM_ID_STRLEN);
+ pv->id.uuidlen = GRUB_LVM_ID_STRLEN;
- pv->start = grub_lvm_getvalue (&p, "pe_start = ");
- if (p == NULL)
- {
+ pv->start_sector = grub_lvm_getvalue (&p, "pe_start = ");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown pe_start\n");
+ grub_util_info ("unknown pe_start\n");
#endif
- goto pvs_fail;
- }
+ goto pvs_fail;
+ }
- p = grub_strchr (p, '}');
- if (p == NULL)
- {
+ p = grub_strchr (p, '}');
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("error parsing pe_start\n");
+ grub_util_info ("error parsing pe_start\n");
#endif
- goto pvs_fail;
- }
- p++;
+ goto pvs_fail;
+ }
+ p++;
- pv->disk = NULL;
- pv->next = vg->pvs;
- vg->pvs = pv;
+ pv->disk = NULL;
+ pv->next = vg->pvs;
+ vg->pvs = pv;
- continue;
- pvs_fail:
- grub_free (pv->name);
- grub_free (pv);
- goto fail4;
- }
- }
+ continue;
+ pvs_fail:
+ grub_free (pv->name);
+ grub_free (pv);
+ goto fail4;
+ }
+ }
- p = grub_strstr (p, "logical_volumes");
- if (p)
- {
- p += 18;
+ p = grub_strstr (p, "logical_volumes");
+ if (p)
+ {
+ p += sizeof ("logical_volumes = ") - 1;
- /* And add all the lvs to the volume group. */
- while (1)
- {
- int s;
- int skip_lv = 0;
- struct grub_lvm_lv *lv;
- struct grub_lvm_segment *seg;
- int is_pvmove;
+ /* And add all the lvs to the volume group. */
+ while (1)
+ {
+ int s;
+ int skip_lv = 0;
+ struct grub_diskfilter_lv *lv;
+ struct grub_diskfilter_segment *seg;
+ int is_pvmove;
- while (grub_isspace (*p))
- p++;
+ while (grub_isspace (*p))
+ p++;
- if (*p == '}')
- break;
+ if (*p == '}')
+ break;
- lv = grub_malloc (sizeof (*lv));
+ lv = grub_zalloc (sizeof (*lv));
- q = p;
- while (*q != ' ')
- q++;
+ q = p;
+ while (*q != ' ')
+ q++;
- s = q - p;
- lv->name = grub_strndup (p, s);
- if (!lv->name)
- goto lvs_fail;
- lv->compatname = grub_malloc (vgname_len + 1 + s + 1);
- if (!lv->compatname)
+ s = q - p;
+ lv->name = grub_strndup (p, s);
+ if (!lv->name)
+ goto lvs_fail;
+
+ {
+ const char *iptr;
+ char *optr;
+ lv->fullname = grub_malloc (sizeof ("lvm/") - 1 + 2 * vgname_len
+ + 1 + 2 * s + 1);
+ if (!lv->fullname)
goto lvs_fail;
- grub_memcpy (lv->compatname, vgname, vgname_len);
- lv->compatname[vgname_len] = '-';
- grub_memcpy (lv->compatname + vgname_len + 1, p, s);
- lv->compatname[vgname_len + 1 + s] = '\0';
- {
- const char *iptr;
- char *optr;
- lv->fullname = grub_malloc (sizeof("lvm/") + 2 * vgname_len
- + 1 + 2 * s + 1);
- if (!lv->fullname)
- goto lvs_fail;
-
- optr = lv->fullname;
- grub_memcpy (optr, "lvm/", sizeof ("lvm/") - 1);
- optr += sizeof ("lvm/") - 1;
- for (iptr = vgname; iptr < vgname + vgname_len; iptr++)
- {
- *optr++ = *iptr;
- if (*iptr == '-')
- *optr++ = '-';
- }
- *optr++ = '-';
- for (iptr = p; iptr < p + s; iptr++)
- {
- *optr++ = *iptr;
- if (*iptr == '-')
- *optr++ = '-';
- }
- *optr++ = 0;
- }
+ grub_memcpy (lv->fullname, "lvm/", sizeof ("lvm/") - 1);
+ optr = lv->fullname + sizeof ("lvm/") - 1;
+ for (iptr = vgname; iptr < vgname + vgname_len; iptr++)
+ {
+ *optr++ = *iptr;
+ if (*iptr == '-')
+ *optr++ = '-';
+ }
+ *optr++ = '-';
+ for (iptr = p; iptr < p + s; iptr++)
+ {
+ *optr++ = *iptr;
+ if (*iptr == '-')
+ *optr++ = '-';
+ }
+ *optr++ = 0;
+ }
- lv->size = 0;
+ lv->size = 0;
- lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
- is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE");
+ lv->visible = grub_lvm_check_flag (p, "status", "VISIBLE");
+ is_pvmove = grub_lvm_check_flag (p, "status", "PVMOVE");
- lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
- if (p == NULL)
- {
+ lv->segment_count = grub_lvm_getvalue (&p, "segment_count = ");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown segment_count\n");
+ grub_util_info ("unknown segment_count\n");
#endif
- goto lvs_fail;
- }
- lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
- seg = lv->segments;
+ goto lvs_fail;
+ }
+ lv->segments = grub_malloc (sizeof (*seg) * lv->segment_count);
+ seg = lv->segments;
- for (i = 0; i < lv->segment_count; i++)
- {
+ for (i = 0; i < lv->segment_count; i++)
+ {
- p = grub_strstr (p, "segment");
- if (p == NULL)
- {
+ p = grub_strstr (p, "segment");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown segment\n");
+ grub_util_info ("unknown segment\n");
#endif
- goto lvs_segment_fail;
- }
+ goto lvs_segment_fail;
+ }
- seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
- if (p == NULL)
- {
+ seg->start_extent = grub_lvm_getvalue (&p, "start_extent = ");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown start_extent\n");
+ grub_util_info ("unknown start_extent\n");
#endif
- goto lvs_segment_fail;
- }
- seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
- if (p == NULL)
- {
+ goto lvs_segment_fail;
+ }
+ seg->extent_count = grub_lvm_getvalue (&p, "extent_count = ");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown extent_count\n");
+ grub_util_info ("unknown extent_count\n");
#endif
- goto lvs_segment_fail;
- }
-
- p = grub_strstr (p, "type = \"");
- if (p == NULL)
goto lvs_segment_fail;
- p += sizeof("type = \"") - 1;
+ }
- lv->size += seg->extent_count * vg->extent_size;
+ p = grub_strstr (p, "type = \"");
+ if (p == NULL)
+ goto lvs_segment_fail;
+ p += sizeof("type = \"") - 1;
- if (grub_memcmp (p, "striped\"",
- sizeof ("striped\"") - 1) == 0)
- {
- struct grub_lvm_node *stripe;
+ lv->size += seg->extent_count * vg->extent_size;
+
+ if (grub_memcmp (p, "striped\"",
+ sizeof ("striped\"") - 1) == 0)
+ {
+ struct grub_diskfilter_node *stripe;
- seg->type = GRUB_LVM_STRIPED;
- seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
- if (p == NULL)
- {
+ seg->type = GRUB_DISKFILTER_STRIPED;
+ seg->node_count = grub_lvm_getvalue (&p, "stripe_count = ");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown stripe_count\n");
+ grub_util_info ("unknown stripe_count\n");
#endif
- goto lvs_segment_fail;
- }
+ goto lvs_segment_fail;
+ }
- if (seg->node_count != 1)
- seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
+ if (seg->node_count != 1)
+ seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
- seg->nodes = grub_zalloc (sizeof (*stripe)
- * seg->node_count);
- stripe = seg->nodes;
+ seg->nodes = grub_zalloc (sizeof (*stripe)
+ * seg->node_count);
+ stripe = seg->nodes;
- p = grub_strstr (p, "stripes = [");
- if (p == NULL)
- {
+ p = grub_strstr (p, "stripes = [");
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
- grub_util_info ("unknown stripes\n");
+ grub_util_info ("unknown stripes\n");
#endif
+ goto lvs_segment_fail2;
+ }
+ p += sizeof("stripes = [") - 1;
+
+ for (j = 0; j < seg->node_count; j++)
+ {
+ p = grub_strchr (p, '"');
+ if (p == NULL)
+ continue;
+ q = ++p;
+ while (*q != '"')
+ q++;
+
+ s = q - p;
+
+ stripe->name = grub_malloc (s + 1);
+ if (stripe->name == NULL)
goto lvs_segment_fail2;
- }
- p += sizeof("stripes = [") - 1;
-
- for (j = 0; j < seg->node_count; j++)
- {
- p = grub_strchr (p, '"');
- if (p == NULL)
- continue;
- q = ++p;
- while (*q != '"')
- q++;
-
- s = q - p;
-
- stripe->name = grub_malloc (s + 1);
- if (stripe->name == NULL)
- goto lvs_segment_fail2;
-
- grub_memcpy (stripe->name, p, s);
- stripe->name[s] = '\0';
-
- stripe->start = grub_lvm_getvalue (&p, ",");
- if (p == NULL)
- continue;
-
- stripe++;
- }
- }
- else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
- == 0)
- {
- seg->type = GRUB_LVM_MIRROR;
- seg->node_count = grub_lvm_getvalue (&p, "mirror_count = ");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown mirror_count\n");
-#endif
- goto lvs_segment_fail;
- }
- seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
- * seg->node_count);
+ grub_memcpy (stripe->name, p, s);
+ stripe->name[s] = '\0';
- p = grub_strstr (p, "mirrors = [");
- if (p == NULL)
- {
-#ifdef GRUB_UTIL
- grub_util_info ("unknown mirrors\n");
-#endif
- goto lvs_segment_fail2;
- }
- p += sizeof("mirrors = [") - 1;
-
- for (j = 0; j < seg->node_count; j++)
- {
- char *lvname;
-
- p = grub_strchr (p, '"');
- if (p == NULL)
- continue;
- q = ++p;
- while (*q != '"')
- q++;
-
- s = q - p;
-
- lvname = grub_malloc (s + 1);
- if (lvname == NULL)
- goto lvs_segment_fail2;
-
- grub_memcpy (lvname, p, s);
- lvname[s] = '\0';
- seg->nodes[j].name = lvname;
- p = q + 1;
- }
- /* Only first (original) is ok with in progress pvmove. */
- if (is_pvmove)
- seg->node_count = 1;
- }
- else
- {
-#ifdef GRUB_UTIL
- char *p2;
- p2 = grub_strchr (p, '"');
- if (p2)
- *p2 = 0;
- grub_util_info ("unknown LVM type %s\n", p);
- if (p2)
- *p2 ='"';
-#endif
- /* Found a non-supported type, give up and move on. */
- skip_lv = 1;
- break;
- }
-
- seg++;
-
- continue;
- lvs_segment_fail2:
- grub_free (seg->nodes);
- lvs_segment_fail:
- goto fail4;
- }
+ p = q + 1;
- if (p != NULL)
- p = grub_strchr (p, '}');
- if (p == NULL)
- goto lvs_fail;
- p += 3;
-
- if (skip_lv)
- {
- grub_free (lv->name);
- grub_free (lv);
- continue;
- }
-
- lv->number = lv_count++;
- lv->vg = vg;
- lv->next = vg->lvs;
- vg->lvs = lv;
-
- continue;
- lvs_fail:
- grub_free (lv->name);
- grub_free (lv);
- goto fail4;
- }
- }
-
- /* Match lvs. */
- {
- struct grub_lvm_lv *lv1;
- struct grub_lvm_lv *lv2;
- for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
- for (i = 0; i < lv1->segment_count; i++)
- for (j = 0; j < lv1->segments[i].node_count; j++)
- {
- if (vg->pvs)
- for (pv = vg->pvs; pv; pv = pv->next)
- {
- if (! grub_strcmp (pv->name,
- lv1->segments[i].nodes[j].name))
- {
- lv1->segments[i].nodes[j].pv = pv;
- break;
- }
- }
- if (lv1->segments[i].nodes[j].pv == NULL)
- for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
- if (grub_strcmp (lv2->name + grub_strlen (vg->name) + 1,
- lv1->segments[i].nodes[j].name) == 0)
- lv1->segments[i].nodes[j].lv = lv2;
- }
-
- }
-
- vg->next = vg_list;
- vg_list = vg;
- }
- else
- {
- grub_free (vgname);
- }
+ stripe->start = grub_lvm_getvalue (&p, ",")
+ * vg->extent_size;
+ if (p == NULL)
+ continue;
- /* 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))
- {
- /* This could happen to LVM on RAID, pv->disk points to the
- raid device, we shouldn't change it. */
- if (! pv->disk)
- pv->disk = grub_disk_open (name);
- break;
- }
- }
+ stripe++;
+ }
+ }
+ else if (grub_memcmp (p, "mirror\"", sizeof ("mirror\"") - 1)
+ == 0)
+ {
+ seg->type = GRUB_DISKFILTER_MIRROR;
+ seg->node_count = grub_lvm_getvalue (&p, "mirror_count = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown mirror_count\n");
+#endif
+ goto lvs_segment_fail;
+ }
- goto fail2;
+ seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
+ * seg->node_count);
- /* Failure path. */
- fail4:
- grub_free (vg);
- fail3:
- grub_free (vgname);
-
- /* Normal exit path. */
- fail2:
- grub_free (metadatabuf);
- fail:
- grub_disk_close (disk);
- if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
- grub_errno = GRUB_ERR_NONE;
- grub_print_error ();
- if (scan_for && find_lv (scan_for))
- return 1;
- return 0;
- }
+ p = grub_strstr (p, "mirrors = [");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown mirrors\n");
+#endif
+ goto lvs_segment_fail2;
+ }
+ p += sizeof("mirrors = [") - 1;
- scan_depth++;
- grub_device_iterate (&grub_lvm_scan_device);
- scan_depth--;
-}
+ for (j = 0; j < seg->node_count; j++)
+ {
+ char *lvname;
-static int
-grub_lvm_iterate (int (*hook) (const char *name),
- grub_disk_pull_t pull)
-{
- struct grub_lvm_vg *vg;
- unsigned old_count = 0;
- if (pull == GRUB_DISK_PULL_RESCAN && scan_depth)
- return 0;
+ p = grub_strchr (p, '"');
+ if (p == NULL)
+ continue;
+ q = ++p;
+ while (*q != '"')
+ q++;
- if (pull == GRUB_DISK_PULL_RESCAN)
- {
- old_count = lv_count;
- if (!scan_depth)
- do_lvm_scan (NULL);
- }
- if (pull != GRUB_DISK_PULL_RESCAN && pull != GRUB_DISK_PULL_NONE)
- return GRUB_ERR_NONE;
- 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 (lv->visible && lv->number >= old_count)
- {
- if (hook (lv->fullname))
- return 1;
- }
- }
+ s = q - p;
- return 0;
-}
+ lvname = grub_malloc (s + 1);
+ if (lvname == NULL)
+ goto lvs_segment_fail2;
+ grub_memcpy (lvname, p, s);
+ lvname[s] = '\0';
+ seg->nodes[j].name = lvname;
+ p = q + 1;
+ }
+ /* Only first (original) is ok with in progress pvmove. */
+ if (is_pvmove)
+ seg->node_count = 1;
+ }
+ else if (grub_memcmp (p, "raid", sizeof ("raid") - 1)
+ == 0 && (p[sizeof ("raid") - 1] >= '4'
+ && p[sizeof ("raid") - 1] <= '6')
+ && p[sizeof ("raidX") - 1] == '"')
+ {
+ switch (p[sizeof ("raid") - 1])
+ {
+ case '4':
+ seg->type = GRUB_DISKFILTER_RAID4;
+ seg->layout = GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC;
+ break;
+ case '5':
+ seg->type = GRUB_DISKFILTER_RAID5;
+ seg->layout = GRUB_RAID_LAYOUT_LEFT_SYMMETRIC;
+ break;
+ case '6':
+ seg->type = GRUB_DISKFILTER_RAID6;
+ seg->layout = (GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC
+ | GRUB_RAID_LAYOUT_MUL_FROM_POS);
+ break;
+ }
+ seg->node_count = grub_lvm_getvalue (&p, "device_count = ");
+
+ if (p == NULL)
+ {
#ifdef GRUB_UTIL
-static grub_disk_memberlist_t
-grub_lvm_memberlist (grub_disk_t disk)
-{
- struct grub_lvm_lv *lv = disk->data;
- 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)
- {
- if (!pv->disk)
- grub_util_error (_("Couldn't find PV %s. Check your device.map"),
- pv->name);
- tmp = grub_malloc (sizeof (*tmp));
- tmp->disk = pv->disk;
- tmp->next = list;
- list = tmp;
- }
-
- return list;
-}
+ grub_util_info ("unknown device_count\n");
#endif
+ goto lvs_segment_fail;
+ }
-static grub_err_t
-grub_lvm_open (const char *name, grub_disk_t disk)
-{
- struct grub_lvm_lv *lv = NULL;
- int explicit = 0;
-
- if (grub_memcmp (name, "lvm/", sizeof ("lvm/") - 1) == 0)
- explicit = 1;
-
- lv = find_lv (name);
-
- if (! lv && !scan_depth && explicit)
- {
- do_lvm_scan (name);
- if (grub_errno)
- {
- grub_print_error ();
- grub_errno = GRUB_ERR_NONE;
- }
- lv = find_lv (name);
- }
-
- if (! lv)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown LVM device %s", name);
+ seg->stripe_size = grub_lvm_getvalue (&p, "stripe_size = ");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown stripe_size\n");
+#endif
+ goto lvs_segment_fail;
+ }
- disk->id = lv->number;
- disk->data = lv;
- disk->total_sectors = lv->size;
- return 0;
-}
+ seg->nodes = grub_zalloc (sizeof (seg->nodes[0])
+ * seg->node_count);
-static void
-grub_lvm_close (grub_disk_t disk __attribute ((unused)))
-{
- return;
-}
+ p = grub_strstr (p, "raids = [");
+ if (p == NULL)
+ {
+#ifdef GRUB_UTIL
+ grub_util_info ("unknown mirrors\n");
+#endif
+ goto lvs_segment_fail2;
+ }
+ p += sizeof("raids = [") - 1;
+
+ for (j = 0; j < seg->node_count; j++)
+ {
+ char *lvname;
+
+ p = grub_strchr (p, '"');
+ p = p ? grub_strchr (p + 1, '"') : 0;
+ p = p ? grub_strchr (p + 1, '"') : 0;
+ if (p == NULL)
+ continue;
+ q = ++p;
+ while (*q != '"')
+ q++;
+
+ s = q - p;
+
+ lvname = grub_malloc (s + 1);
+ if (lvname == NULL)
+ goto lvs_segment_fail2;
-static grub_err_t
-read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
- grub_size_t size, char *buf);
+ grub_memcpy (lvname, p, s);
+ lvname[s] = '\0';
+ seg->nodes[j].name = lvname;
+ p = q + 1;
+ }
+ if (seg->type == GRUB_DISKFILTER_RAID4)
+ {
+ char *tmp;
+ tmp = seg->nodes[0].name;
+ grub_memmove (seg->nodes, seg->nodes + 1,
+ sizeof (seg->nodes[0])
+ * (seg->node_count - 1));
+ seg->nodes[seg->node_count - 1].name = tmp;
+ }
+ }
+ else
+ {
+#ifdef GRUB_UTIL
+ char *p2;
+ p2 = grub_strchr (p, '"');
+ if (p2)
+ *p2 = 0;
+ grub_util_info ("unknown LVM type %s\n", p);
+ if (p2)
+ *p2 ='"';
+#endif
+ /* Found a non-supported type, give up and move on. */
+ skip_lv = 1;
+ break;
+ }
-static grub_err_t
-read_node (const struct grub_lvm_node *node, grub_disk_addr_t sector,
- grub_size_t size, char *buf)
-{
- /* Check whether we actually know the physical volume we want to
- read from. */
- if (node->pv)
- {
- if (node->pv->disk)
- return grub_disk_read (node->pv->disk, sector + node->pv->start, 0,
- size << GRUB_DISK_SECTOR_BITS, buf);
- else
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE,
- "physical volume %s not found", node->pv->name);
+ seg++;
- }
- if (node->lv)
- return read_lv (node->lv, sector, size, buf);
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown node '%s'", node->name);
-}
+ continue;
+ lvs_segment_fail2:
+ grub_free (seg->nodes);
+ lvs_segment_fail:
+ goto fail4;
+ }
-static grub_err_t
-read_lv (struct grub_lvm_lv *lv, grub_disk_addr_t sector,
- grub_size_t size, char *buf)
-{
- grub_err_t err = 0;
- struct grub_lvm_vg *vg = lv->vg;
- struct grub_lvm_segment *seg = lv->segments;
- struct grub_lvm_node *node;
- grub_uint64_t offset;
- grub_uint64_t extent;
- unsigned int i;
+ if (p != NULL)
+ p = grub_strchr (p, '}');
+ if (p == NULL)
+ goto lvs_fail;
+ p += 3;
- if (!lv)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown volume");
+ if (skip_lv)
+ {
+ grub_free (lv->name);
+ grub_free (lv);
+ continue;
+ }
- extent = grub_divmod64 (sector, vg->extent_size, NULL);
+ lv->vg = vg;
+ lv->next = vg->lvs;
+ vg->lvs = lv;
- /* Find the right segment. */
- for (i = 0; i < lv->segment_count; i++)
- {
- if ((seg->start_extent <= extent)
- && ((seg->start_extent + seg->extent_count) > extent))
- {
- break;
+ continue;
+ lvs_fail:
+ grub_free (lv->name);
+ grub_free (lv);
+ goto fail4;
+ }
}
- seg++;
+ /* Match lvs. */
+ {
+ struct grub_diskfilter_lv *lv1;
+ struct grub_diskfilter_lv *lv2;
+ for (lv1 = vg->lvs; lv1; lv1 = lv1->next)
+ for (i = 0; i < lv1->segment_count; i++)
+ for (j = 0; j < lv1->segments[i].node_count; j++)
+ {
+ if (vg->pvs)
+ for (pv = vg->pvs; pv; pv = pv->next)
+ {
+ if (! grub_strcmp (pv->name,
+ lv1->segments[i].nodes[j].name))
+ {
+ lv1->segments[i].nodes[j].pv = pv;
+ break;
+ }
+ }
+ if (lv1->segments[i].nodes[j].pv == NULL)
+ for (lv2 = vg->lvs; lv2; lv2 = lv2->next)
+ if (grub_strcmp (lv2->name,
+ lv1->segments[i].nodes[j].name) == 0)
+ lv1->segments[i].nodes[j].lv = lv2;
+ }
+
+ }
+ if (grub_diskfilter_vg_register (vg))
+ goto fail4;
}
-
- if (i == lv->segment_count)
- return grub_error (GRUB_ERR_READ_ERROR, "incorrect segment");
-
- switch (seg->type)
+ else
{
- case GRUB_LVM_STRIPED:
- if (seg->node_count == 1)
- {
- /* This segment is linear, so that's easy. We just need to find
- out the offset in the physical volume and read SIZE bytes
- from that. */
- struct grub_lvm_node *stripe = seg->nodes;
- grub_uint64_t seg_offset; /* Offset of the segment in PV device. */
-
- node = stripe;
- seg_offset = ((grub_uint64_t) stripe->start
- * (grub_uint64_t) vg->extent_size);
-
- offset = sector - ((grub_uint64_t) seg->start_extent
- * (grub_uint64_t) vg->extent_size) + seg_offset;
- }
- else
- {
- /* This is a striped segment. We have to find the right PV
- similar to RAID0. */
- struct grub_lvm_node *stripe = seg->nodes;
- grub_uint64_t a, b;
- grub_uint64_t seg_offset; /* Offset of the segment in PV device. */
- grub_uint64_t stripenr;
-
- offset = sector - ((grub_uint64_t) seg->start_extent
- * (grub_uint64_t) vg->extent_size);
-
- a = grub_divmod64 (offset, seg->stripe_size, NULL);
- grub_divmod64 (a, seg->node_count, &stripenr);
-
- a = grub_divmod64 (offset, seg->stripe_size * seg->node_count, NULL);
- grub_divmod64 (offset, seg->stripe_size, &b);
- offset = a * seg->stripe_size + b;
-
- stripe += stripenr;
- node = stripe;
-
- seg_offset = ((grub_uint64_t) stripe->start
- * (grub_uint64_t) vg->extent_size);
-
- offset += seg_offset;
- }
- return read_node (node, offset, size, buf);
- case GRUB_LVM_MIRROR:
- i = 0;
- while (1)
- {
- err = read_node (&seg->nodes[i], sector, size, buf);
- if (!err)
- return err;
- if (++i >= seg->node_count)
- return err;
- grub_errno = GRUB_ERR_NONE;
- }
+ grub_free (vgname);
}
- return grub_error (GRUB_ERR_IO, "unknown LVM segment");
-}
-
-static grub_err_t
-is_node_readable (const struct grub_lvm_node *node)
-{
- /* Check whether we actually know the physical volume we want to
- read from. */
- if (node->pv)
- return !!(node->pv->disk);
- if (node->lv)
- return is_lv_readable (node->lv);
- return 0;
-}
-
-static int
-is_lv_readable (struct grub_lvm_lv *lv)
-{
- unsigned int i, j;
-
- if (!lv)
- return 0;
-
- /* Find the right segment. */
- for (i = 0; i < lv->segment_count; i++)
- switch (lv->segments[i].type)
- {
- case GRUB_LVM_STRIPED:
- for (j = 0; j < lv->segments[i].node_count; j++)
- if (!is_node_readable (lv->segments[i].nodes + j))
- return 0;
- break;
- case GRUB_LVM_MIRROR:
- for (j = 0; j < lv->segments[i].node_count; j++)
- if (is_node_readable (lv->segments[i].nodes + j))
- break;
- if (j == lv->segments[i].node_count)
- return 0;
- default:
- return 0;
- }
-
- return 1;
-}
-
-static grub_err_t
-grub_lvm_read (grub_disk_t disk, grub_disk_addr_t sector,
- grub_size_t size, char *buf)
-{
- return read_lv (disk->data, sector, size, buf);
+ id->uuid = grub_malloc (GRUB_LVM_ID_STRLEN);
+ if (!id->uuid)
+ goto fail4;
+ grub_memcpy (id->uuid, pv_id, GRUB_LVM_ID_STRLEN);
+ id->uuidlen = GRUB_LVM_ID_STRLEN;
+ grub_free (metadatabuf);
+ *start_sector = -1;
+ return vg;
+
+ /* Failure path. */
+ fail4:
+ grub_free (vg);
+ fail3:
+ grub_free (vgname);
+
+ fail2:
+ grub_free (metadatabuf);
+ fail:
+ return NULL;
}
-static grub_err_t
-grub_lvm_write (grub_disk_t disk __attribute ((unused)),
- grub_disk_addr_t sector __attribute ((unused)),
- grub_size_t size __attribute ((unused)),
- const char *buf __attribute ((unused)))
-{
- return GRUB_ERR_NOT_IMPLEMENTED_YET;
-}
+\f
-static struct grub_disk_dev grub_lvm_dev =
- {
- .name = "lvm",
- .id = GRUB_DISK_DEVICE_LVM_ID,
- .iterate = grub_lvm_iterate,
- .open = grub_lvm_open,
- .close = grub_lvm_close,
- .read = grub_lvm_read,
- .write = grub_lvm_write,
-#ifdef GRUB_UTIL
- .memberlist = grub_lvm_memberlist,
-#endif
- .next = 0
- };
+static struct grub_diskfilter grub_lvm_dev = {
+ .name = "lvm",
+ .detect = grub_lvm_detect,
+ .next = 0
+};
-\f
-GRUB_MOD_INIT(lvm)
+GRUB_MOD_INIT (lvm)
{
- grub_disk_dev_register (&grub_lvm_dev);
+ grub_diskfilter_register (&grub_lvm_dev);
}
-GRUB_MOD_FINI(lvm)
+GRUB_MOD_FINI (lvm)
{
- grub_disk_dev_unregister (&grub_lvm_dev);
- vg_list = NULL;
- /* FIXME: free the lvm list. */
+ grub_diskfilter_unregister (&grub_lvm_dev);
}
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
GRUB_MOD_LICENSE ("GPLv3+");
#define WriteMostly1 1 /* Mask for writemostly flag in above devflags. */
-static grub_err_t
-grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
+static struct grub_diskfilter_vg *
+grub_mdraid_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector = 0;
if (grub_disk_read (disk, sector, 0, sizeof (struct grub_raid_super_1x),
&sb))
- return grub_errno;
+ return NULL;
if (grub_le_to_cpu32 (sb.magic) != SB_MAGIC
|| grub_le_to_cpu64 (sb.super_offset) != sector)
grub_uint32_t level;
if (grub_le_to_cpu32 (sb.major_version) != 1)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Unsupported RAID version: %d",
- grub_le_to_cpu32 (sb.major_version));
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "Unsupported RAID version: %d",
+ grub_le_to_cpu32 (sb.major_version));
+ return NULL;
+ }
level = grub_le_to_cpu32 (sb.level);
if (level != 0 && level != 1 && level != 4 &&
level != 5 && level != 6 && level != 10)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Unsupported RAID level: %d", sb.level);
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "Unsupported RAID level: %d", sb.level);
+ return NULL;
+ }
/* 1.x superblocks don't have a fixed size on disk. So we have to
read it again now that we now the max device count. */
+ 2 * grub_le_to_cpu32 (sb.max_dev);
real_sb = grub_malloc (sb_size);
if (! real_sb)
- return grub_errno;
+ return NULL;
if (grub_disk_read (disk, sector, 0, sb_size, real_sb))
{
grub_free (real_sb);
- return grub_errno;
+ return NULL;
}
- array->name = grub_strdup (real_sb->set_name);
- if (! array->name)
- {
- grub_free (real_sb);
- return grub_errno;
- }
-
- array->number = 0;
- array->level = grub_le_to_cpu32 (real_sb->level);
- array->layout = grub_le_to_cpu32 (real_sb->layout);
- array->total_devs = grub_le_to_cpu32 (real_sb->raid_disks);
- if (real_sb->size)
- array->disk_size = grub_le_to_cpu64 (real_sb->size);
- else
- array->disk_size = grub_le_to_cpu64 (real_sb->data_size);
- array->chunk_size = grub_le_to_cpu32 (real_sb->chunksize);
+ struct grub_diskfilter_vg *array;
+ char *uuid;
if (grub_le_to_cpu32 (real_sb->dev_number) >=
grub_le_to_cpu32 (real_sb->max_dev))
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- "spares aren't implemented");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "spares aren't implemented");
+ return NULL;
+ }
- array->index = grub_le_to_cpu16
+ id->uuidlen = 0;
+ id->id = grub_le_to_cpu16
(real_sb->dev_roles[grub_le_to_cpu32 (real_sb->dev_number)]);
- if (array->index >= array->total_devs)
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- "spares aren't implemented");
- array->uuid_len = 16;
- array->uuid = grub_malloc (16);
- if (!array->uuid)
+
+ uuid = grub_malloc (16);
+ if (!uuid)
{
grub_free (real_sb);
- return grub_errno;
+ return NULL;
}
- grub_memcpy (array->uuid, real_sb->set_uuid, 16);
-
+ grub_memcpy (uuid, real_sb->set_uuid, 16);
+
*start_sector = grub_le_to_cpu64 (real_sb->data_offset);
+ if (grub_le_to_cpu32 (real_sb->dev_number)
+ >= grub_le_to_cpu32 (real_sb->raid_disks))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "spares aren't implemented");
+ return NULL;
+ }
+
+ array = grub_diskfilter_make_raid (16, uuid,
+ grub_le_to_cpu32 (real_sb->raid_disks),
+ real_sb->set_name,
+ (real_sb->size)
+ ? grub_le_to_cpu64 (real_sb->size)
+ : grub_le_to_cpu64 (real_sb->data_size),
+ grub_le_to_cpu32 (real_sb->chunksize),
+ grub_le_to_cpu32 (real_sb->layout),
+ grub_le_to_cpu32 (real_sb->level));
+
grub_free (real_sb);
- return 0;
+ return array;
}
}
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid");
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not 1.x raid");
+ return NULL;
}
-static struct grub_raid grub_mdraid_dev = {
+static struct grub_diskfilter grub_mdraid_dev = {
.name = "mdraid1x",
.detect = grub_mdraid_detect,
.next = 0
GRUB_MOD_INIT (mdraid1x)
{
- grub_raid_register (&grub_mdraid_dev);
+ grub_diskfilter_register (&grub_mdraid_dev);
}
GRUB_MOD_FINI (mdraid1x)
{
- grub_raid_unregister (&grub_mdraid_dev);
+ grub_diskfilter_unregister (&grub_mdraid_dev);
}
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
/* Linux RAID on disk structures and constants,
copied from include/linux/raid/md_p.h. */
struct grub_raid_disk_09 this_disk;
} __attribute__ ((packed));
-static grub_err_t
-grub_mdraid_detect (grub_disk_t disk, struct grub_raid_array *array,
+static struct grub_diskfilter_vg *
+grub_mdraid_detect (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
grub_disk_addr_t *start_sector)
{
grub_disk_addr_t sector;
/* The sector where the mdraid 0.90 superblock is stored, if available. */
size = grub_disk_get_size (disk);
if (size == GRUB_DISK_SIZE_UNKNOWN)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
+ return NULL;
+ }
sector = NEW_SIZE_SECTORS (size);
if (grub_disk_read (disk, sector, 0, SB_BYTES, &sb))
- return grub_errno;
+ return NULL;
/* Look whether there is a mdraid 0.90 superblock. */
if (grub_le_to_cpu32 (sb.md_magic) != SB_MAGIC)
- return grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "not 0.9x raid");
+ return NULL;
+ }
if (grub_le_to_cpu32 (sb.major_version) != 0
|| grub_le_to_cpu32 (sb.minor_version) != 90)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unsupported RAID version: %d.%d",
- grub_le_to_cpu32 (sb.major_version),
- grub_le_to_cpu32 (sb.minor_version));
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported RAID version: %d.%d",
+ grub_le_to_cpu32 (sb.major_version),
+ grub_le_to_cpu32 (sb.minor_version));
+ return NULL;
+ }
/* FIXME: Check the checksum. */
if (level != 0 && level != 1 && level != 4 &&
level != 5 && level != 6 && level != 10)
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "unsupported RAID level: %d", level);
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "unsupported RAID level: %d", level);
+ return NULL;
+ }
if (grub_le_to_cpu32 (sb.this_disk.number) == 0xffff
|| grub_le_to_cpu32 (sb.this_disk.number) == 0xfffe)
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- "spares aren't implemented");
-
- array->name = NULL;
- array->number = grub_le_to_cpu32 (sb.md_minor);
- array->level = level;
- array->layout = grub_le_to_cpu32 (sb.layout);
- array->total_devs = grub_le_to_cpu32 (sb.raid_disks);
- array->disk_size = (sb.size) ? grub_le_to_cpu32 (sb.size) * 2 : sector;
- array->chunk_size = grub_le_to_cpu32 (sb.chunk_size) >> 9;
- array->index = grub_le_to_cpu32 (sb.this_disk.number);
- array->uuid_len = 16;
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE,
+ "spares aren't implemented");
+ return NULL;
+ }
+
uuid = grub_malloc (16);
- array->uuid = (char *) uuid;
- if (!array->uuid)
- return grub_errno;
+ if (!uuid)
+ return NULL;
uuid[0] = grub_swap_bytes32 (sb.set_uuid0);
uuid[1] = grub_swap_bytes32 (sb.set_uuid1);
*start_sector = 0;
- return 0;
+ id->uuidlen = 0;
+ id->id = grub_le_to_cpu32 (sb.this_disk.number);
+
+ char buf[32];
+ grub_snprintf (buf, sizeof (buf), "md%d", grub_le_to_cpu32 (sb.md_minor));
+ return grub_diskfilter_make_raid (16, (char *) uuid,
+ grub_le_to_cpu32 (sb.raid_disks), buf,
+ (sb.size) ? grub_le_to_cpu32 (sb.size) * 2
+ : sector,
+ grub_le_to_cpu32 (sb.chunk_size) >> 9,
+ grub_le_to_cpu32 (sb.layout),
+ level);
}
-static struct grub_raid grub_mdraid_dev = {
+static struct grub_diskfilter grub_mdraid_dev = {
.name = "mdraid09",
.detect = grub_mdraid_detect,
.next = 0
GRUB_MOD_INIT (mdraid09)
{
- grub_raid_register (&grub_mdraid_dev);
+ grub_diskfilter_register (&grub_mdraid_dev);
}
GRUB_MOD_FINI (mdraid09)
{
- grub_raid_unregister (&grub_mdraid_dev);
+ grub_diskfilter_unregister (&grub_mdraid_dev);
}
+++ /dev/null
-/* raid.c - module to read RAID arrays. */
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007,2008,2009,2010 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/raid.h>
-#include <grub/partition.h>
-#ifdef GRUB_UTIL
-#include <grub/util/misc.h>
-#endif
-
-GRUB_MOD_LICENSE ("GPLv3+");
-
-/* Linked list of RAID arrays. */
-static struct grub_raid_array *array_list;
-grub_raid5_recover_func_t grub_raid5_recover_func;
-grub_raid6_recover_func_t grub_raid6_recover_func;
-static grub_raid_t grub_raid_list;
-static int inscnt = 0;
-
-static struct grub_raid_array *
-find_array (const char *name);
-
-\f
-static char
-grub_is_array_readable (struct grub_raid_array *array)
-{
- switch (array->level)
- {
- case 0:
- if (array->nr_devs == array->total_devs)
- return 1;
- break;
-
- case 1:
- if (array->nr_devs >= 1)
- return 1;
- break;
-
- case 4:
- case 5:
- case 6:
- case 10:
- {
- unsigned int n;
-
- if (array->level == 10)
- {
- n = array->layout & 0xFF;
- if (n == 1)
- n = (array->layout >> 8) & 0xFF;
-
- n--;
- }
- else
- n = array->level / 3;
-
- if (array->nr_devs >= array->total_devs - n)
- return 1;
-
- break;
- }
- }
-
- return 0;
-}
-
-static grub_err_t
-insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
- grub_disk_addr_t start_sector, const char *scanner_name,
- grub_raid_t raid __attribute__ ((unused)));
-
-static int scan_depth = 0;
-
-static void
-scan_devices (const char *arname)
-{
- grub_raid_t raid;
-
- auto int hook (const char *name);
- int hook (const char *name)
- {
- grub_disk_t disk;
- struct grub_raid_array array;
- struct grub_raid_array *arr;
- grub_disk_addr_t start_sector;
-
- grub_dprintf ("raid", "Scanning for %s RAID devices on disk %s\n",
- raid->name, name);
-#ifdef GRUB_UTIL
- grub_util_info ("Scanning for %s RAID devices on disk %s",
- raid->name, name);
-#endif
-
- disk = grub_disk_open (name);
- if (!disk)
- return 0;
-
- for (arr = array_list; arr != NULL; arr = arr->next)
- {
- struct grub_raid_member *m;
- for (m = arr->members; m < arr->members + arr->nr_devs; m++)
- if (m->device && m->device->id == disk->id
- && m->device->dev->id == disk->dev->id
- && grub_partition_get_start (m->device->partition)
- == grub_partition_get_start (disk->partition)
- && grub_disk_get_size (m->device)
- == grub_disk_get_size (disk))
- {
- grub_disk_close (disk);
- return 0;
- }
- }
-
- if ((! raid->detect (disk, &array, &start_sector)) &&
- (! insert_array (disk, &array, start_sector, raid->name,
- raid)))
- return 0;
-
- /* This error usually means it's not raid, no need to display
- it. */
- if (grub_errno != GRUB_ERR_OUT_OF_RANGE)
- grub_print_error ();
-
- grub_errno = GRUB_ERR_NONE;
-
- grub_disk_close (disk);
-
- if (arname && find_array (arname))
- return 1;
-
- return 0;
- }
-
- if (scan_depth)
- return;
-
- scan_depth++;
- for (raid = grub_raid_list; raid; raid = raid->next)
- grub_device_iterate (&hook);
- scan_depth--;
-}
-
-static int
-grub_raid_iterate (int (*hook) (const char *name),
- grub_disk_pull_t pull)
-{
- struct grub_raid_array *array;
- int islcnt = 0;
-
- if (pull == GRUB_DISK_PULL_RESCAN)
- {
- islcnt = inscnt;
- scan_devices (NULL);
- }
-
- if (pull != GRUB_DISK_PULL_NONE && pull != GRUB_DISK_PULL_RESCAN)
- return 0;
-
- for (array = array_list; array != NULL; array = array->next)
- {
- if (grub_is_array_readable (array) && array->became_readable_at >= islcnt)
- if (hook (array->name))
- return 1;
- }
-
- return 0;
-}
-
-#ifdef GRUB_UTIL
-static grub_disk_memberlist_t
-grub_raid_memberlist (grub_disk_t disk)
-{
- struct grub_raid_array *array = disk->data;
- grub_disk_memberlist_t list = NULL, tmp;
- unsigned int i;
-
- for (i = 0; i < array->total_devs; i++)
- if (array->members[i].device)
- {
- tmp = grub_malloc (sizeof (*tmp));
- tmp->disk = array->members[i].device;
- tmp->next = list;
- list = tmp;
- }
-
- return list;
-}
-
-static const char *
-grub_raid_getname (struct grub_disk *disk)
-{
- struct grub_raid_array *array = disk->data;
-
- return array->driver->name;
-}
-#endif
-
-static inline int
-ascii2hex (char c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- return 0;
-}
-
-static struct grub_raid_array *
-find_array (const char *name)
-{
- struct grub_raid_array *array;
-
- if (grub_memcmp (name, "mduuid/", sizeof ("mduuid/") - 1) == 0)
- {
- const char *uuidstr = name + sizeof ("mduuid/") - 1;
- grub_size_t uuid_len = grub_strlen (uuidstr) / 2;
- grub_uint8_t uuidbin[uuid_len];
- unsigned i;
- for (i = 0; i < uuid_len; i++)
- uuidbin[i] = ascii2hex (uuidstr[2 * i + 1])
- | (ascii2hex (uuidstr[2 * i]) << 4);
-
- for (array = array_list; array != NULL; array = array->next)
- {
- if (uuid_len == (unsigned) array->uuid_len
- && grub_memcmp (uuidbin, array->uuid, uuid_len) == 0)
- if (grub_is_array_readable (array))
- return array;
- }
- }
- else
- for (array = array_list; array != NULL; array = array->next)
- {
- if (!grub_strcmp (array->name, name))
- if (grub_is_array_readable (array))
- return array;
- }
- return NULL;
-}
-
-static grub_err_t
-grub_raid_open (const char *name, grub_disk_t disk)
-{
- struct grub_raid_array *array;
- unsigned n;
-
- if (grub_memcmp (name, "md", sizeof ("md") - 1) != 0)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
- name);
-
- array = find_array (name);
-
- if (! array)
- {
- scan_devices (name);
- if (grub_errno)
- {
- grub_print_error ();
- grub_errno = GRUB_ERR_NONE;
- }
- array = find_array (name);
- }
-
- if (!array)
- return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "unknown RAID device %s",
- name);
-
- disk->id = array->number;
- disk->data = array;
-
- grub_dprintf ("raid", "%s: total_devs=%d, disk_size=%lld\n", name,
- array->total_devs, (unsigned long long) array->disk_size);
-
- switch (array->level)
- {
- case 1:
- disk->total_sectors = array->disk_size;
- break;
-
- case 10:
- n = array->layout & 0xFF;
- if (n == 1)
- n = (array->layout >> 8) & 0xFF;
-
- disk->total_sectors = grub_divmod64 (array->total_devs *
- array->disk_size,
- n, 0);
- break;
-
- case 0:
- case 4:
- case 5:
- case 6:
- n = array->level / 3;
-
- disk->total_sectors = (array->total_devs - n) * array->disk_size;
- break;
- }
-
- grub_dprintf ("raid", "%s: level=%d, total_sectors=%lld\n", name,
- array->level, (unsigned long long) disk->total_sectors);
-
- return 0;
-}
-
-static void
-grub_raid_close (grub_disk_t disk __attribute ((unused)))
-{
- return;
-}
-
-static grub_err_t
-grub_raid_read (grub_disk_t disk, grub_disk_addr_t sector,
- grub_size_t size, char *buf)
-{
- struct grub_raid_array *array = disk->data;
- grub_err_t err = 0;
-
- switch (array->level)
- {
- case 0:
- case 1:
- case 10:
- {
- grub_disk_addr_t read_sector, far_ofs;
- grub_uint64_t disknr, b, near, far, ofs;
-
- read_sector = grub_divmod64 (sector, array->chunk_size, &b);
- far = ofs = near = 1;
- far_ofs = 0;
-
- if (array->level == 1)
- near = array->total_devs;
- else if (array->level == 10)
- {
- near = array->layout & 0xFF;
- far = (array->layout >> 8) & 0xFF;
- if (array->layout >> 16)
- {
- ofs = far;
- far_ofs = 1;
- }
- else
- far_ofs = grub_divmod64 (array->disk_size,
- far * array->chunk_size, 0);
-
- far_ofs *= array->chunk_size;
- }
-
- read_sector = grub_divmod64 (read_sector * near, array->total_devs,
- &disknr);
-
- ofs *= array->chunk_size;
- read_sector *= ofs;
-
- while (1)
- {
- grub_size_t read_size;
- unsigned int i, j;
-
- read_size = array->chunk_size - b;
- if (read_size > size)
- read_size = size;
-
- for (i = 0; i < near; i++)
- {
- unsigned int k;
-
- k = disknr;
- for (j = 0; j < far; j++)
- {
- if (array->members[k].device)
- {
- if (grub_errno == GRUB_ERR_READ_ERROR)
- grub_errno = GRUB_ERR_NONE;
-
- err = grub_disk_read (array->members[k].device,
- array->members[k].start_sector +
- read_sector + j * far_ofs + b,
- 0,
- read_size << GRUB_DISK_SECTOR_BITS,
- buf);
- if (! err)
- break;
- else if (err != GRUB_ERR_READ_ERROR)
- return err;
- }
- else
- err = grub_error (GRUB_ERR_READ_ERROR,
- "disk missing");
-
- k++;
- if (k == array->total_devs)
- k = 0;
- }
-
- if (! err)
- break;
-
- disknr++;
- if (disknr == array->total_devs)
- {
- disknr = 0;
- read_sector += ofs;
- }
- }
-
- if (err)
- return err;
-
- buf += read_size << GRUB_DISK_SECTOR_BITS;
- size -= read_size;
- if (! size)
- break;
-
- b = 0;
- disknr += (near - i);
- while (disknr >= array->total_devs)
- {
- disknr -= array->total_devs;
- read_sector += ofs;
- }
- }
- break;
- }
-
- case 4:
- case 5:
- case 6:
- {
- grub_disk_addr_t read_sector;
- grub_uint64_t b, p, n, disknr, e;
-
- /* n = 1 for level 4 and 5, 2 for level 6. */
- n = array->level / 3;
-
- /* Find the first sector to read. */
- read_sector = grub_divmod64 (sector, array->chunk_size, &b);
- read_sector = grub_divmod64 (read_sector, array->total_devs - n,
- &disknr);
- if (array->level >= 5)
- {
- grub_divmod64 (read_sector, array->total_devs, &p);
-
- if (! (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK))
- p = array->total_devs - 1 - p;
-
- if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
- {
- disknr += p + n;
- }
- else
- {
- grub_uint32_t q;
-
- q = p + (n - 1);
- if (q >= array->total_devs)
- q -= array->total_devs;
-
- if (disknr >= p)
- disknr += n;
- else if (disknr >= q)
- disknr += q + 1;
- }
-
- if (disknr >= array->total_devs)
- disknr -= array->total_devs;
- }
- else
- p = array->total_devs - n;
-
- read_sector *= array->chunk_size;
-
- while (1)
- {
- grub_size_t read_size;
- int next_level;
-
- read_size = array->chunk_size - b;
- if (read_size > size)
- read_size = size;
-
- e = 0;
- if (array->members[disknr].device)
- {
- /* Reset read error. */
- if (grub_errno == GRUB_ERR_READ_ERROR)
- grub_errno = GRUB_ERR_NONE;
-
- err = grub_disk_read (array->members[disknr].device,
- array->members[disknr].start_sector +
- read_sector + b, 0,
- read_size << GRUB_DISK_SECTOR_BITS,
- buf);
-
- if ((err) && (err != GRUB_ERR_READ_ERROR))
- break;
- e++;
- }
- else
- err = GRUB_ERR_READ_ERROR;
-
- if (err)
- {
- if (array->nr_devs < array->total_devs - n + e)
- break;
-
- grub_errno = GRUB_ERR_NONE;
- if (array->level == 6)
- {
- err = ((grub_raid6_recover_func) ?
- (*grub_raid6_recover_func) (array, disknr, p,
- buf, read_sector + b,
- read_size) :
- grub_error (GRUB_ERR_BAD_DEVICE,
- "raid6rec is not loaded"));
- }
- else
- {
- err = ((grub_raid5_recover_func) ?
- (*grub_raid5_recover_func) (array, disknr,
- buf, read_sector + b,
- read_size) :
- grub_error (GRUB_ERR_BAD_DEVICE,
- "raid5rec is not loaded"));
- }
-
- if (err)
- break;
- }
-
- buf += read_size << GRUB_DISK_SECTOR_BITS;
- size -= read_size;
- if (! size)
- break;
-
- b = 0;
- disknr++;
-
- if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
- {
- if (disknr == array->total_devs)
- disknr = 0;
-
- next_level = (disknr == p);
- }
- else
- {
- if (disknr == p)
- disknr += n;
-
- next_level = (disknr >= array->total_devs);
- }
-
- if (next_level)
- {
- read_sector += array->chunk_size;
-
- if (array->level >= 5)
- {
- if (array->layout & GRUB_RAID_LAYOUT_RIGHT_MASK)
- p = (p == array->total_devs - 1) ? 0 : p + 1;
- else
- p = (p == 0) ? array->total_devs - 1 : p - 1;
-
- if (array->layout & GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
- {
- disknr = p + n;
- if (disknr >= array->total_devs)
- disknr -= array->total_devs;
- }
- else
- {
- disknr -= array->total_devs;
- if (disknr == p)
- disknr += n;
- }
- }
- else
- disknr = 0;
- }
- }
- }
- break;
- }
-
- return err;
-}
-
-static grub_err_t
-grub_raid_write (grub_disk_t disk __attribute ((unused)),
- grub_disk_addr_t sector __attribute ((unused)),
- grub_size_t size __attribute ((unused)),
- const char *buf __attribute ((unused)))
-{
- return GRUB_ERR_NOT_IMPLEMENTED_YET;
-}
-
-static grub_err_t
-insert_array (grub_disk_t disk, struct grub_raid_array *new_array,
- grub_disk_addr_t start_sector, const char *scanner_name,
- grub_raid_t raid __attribute__ ((unused)))
-{
- struct grub_raid_array *array = 0, *p;
- int was_readable = 0;
-
- /* See whether the device is part of an array we have already seen a
- device from. */
- for (p = array_list; p != NULL; p = p->next)
- if ((p->uuid_len == new_array->uuid_len) &&
- (! grub_memcmp (p->uuid, new_array->uuid, p->uuid_len)))
- {
- grub_free (new_array->uuid);
- array = p;
-
- was_readable = grub_is_array_readable (array);
-
- /* Do some checks before adding the device to the array. */
-
- if (new_array->index >= array->allocated_devs)
- {
- void *tmp;
- unsigned int newnum = 2 * (new_array->index + 1);
- tmp = grub_realloc (array->members, newnum
- * sizeof (array->members[0]));
- if (!tmp)
- return grub_errno;
- array->members = tmp;
- grub_memset (array->members + array->allocated_devs,
- 0, (newnum - array->allocated_devs)
- * sizeof (array->members[0]));
- array->allocated_devs = newnum;
- }
-
- /* FIXME: Check whether the update time of the superblocks are
- the same. */
-
- if (array->total_devs == array->nr_devs)
- /* We found more members of the array than the array
- actually has according to its superblock. This shouldn't
- happen normally. */
- return grub_error (GRUB_ERR_BAD_DEVICE,
- "superfluous RAID member (%d found)",
- array->total_devs);
-
- if (array->members[new_array->index].device != NULL)
- /* We found multiple devices with the same number. Again,
- this shouldn't happen. */
- return grub_error (GRUB_ERR_BAD_DEVICE,
- "found two disks with the index %d for RAID %s",
- new_array->index, array->name);
-
- if (new_array->disk_size < array->disk_size)
- array->disk_size = new_array->disk_size;
- break;
- }
-
- /* Add an array to the list if we didn't find any. */
- if (!array)
- {
- array = grub_malloc (sizeof (*array));
- if (!array)
- {
- grub_free (new_array->uuid);
- return grub_errno;
- }
-
- *array = *new_array;
- array->nr_devs = 0;
-#ifdef GRUB_UTIL
- array->driver = raid;
-#endif
- array->allocated_devs = 32;
- if (new_array->index >= array->allocated_devs)
- array->allocated_devs = 2 * (new_array->index + 1);
-
- array->members = grub_zalloc (array->allocated_devs
- * sizeof (array->members[0]));
-
- if (!array->members)
- {
- grub_free (new_array->uuid);
- return grub_errno;
- }
-
- if (! array->name)
- {
- for (p = array_list; p != NULL; p = p->next)
- {
- if (p->number == array->number)
- break;
- }
- }
-
- if (array->name || p)
- {
- /* The number is already in use, so we need to find a new one.
- (Or, in the case of named arrays, the array doesn't have its
- own number, but we need one that doesn't clash for use as a key
- in the disk cache. */
- int i = array->name ? 0x40000000 : 0;
-
- while (1)
- {
- for (p = array_list; p != NULL; p = p->next)
- {
- if (p->number == i)
- break;
- }
-
- if (! p)
- {
- /* We found an unused number. */
- array->number = i;
- break;
- }
-
- i++;
- }
- }
-
- /* mdraid 1.x superblocks have only a name stored not a number.
- Use it directly as GRUB device. */
- if (! array->name)
- {
- array->name = grub_xasprintf ("md%d", array->number);
- if (! array->name)
- {
- grub_free (array->members);
- grub_free (array->uuid);
- grub_free (array);
-
- return grub_errno;
- }
- }
- else
- {
- /* Strip off the homehost if present. */
- char *colon = grub_strchr (array->name, ':');
- char *new_name = grub_xasprintf ("md/%s",
- colon ? colon + 1 : array->name);
-
- if (! new_name)
- {
- grub_free (array->members);
- grub_free (array->uuid);
- grub_free (array);
-
- return grub_errno;
- }
-
- grub_free (array->name);
- array->name = new_name;
- }
-
- grub_dprintf ("raid", "Found array %s (%s)\n", array->name,
- scanner_name);
-#ifdef GRUB_UTIL
- grub_util_info ("Found array %s (%s)", array->name,
- scanner_name);
-#endif
-
- {
- int max_used_number = 0, len, need_new_name = 0;
- int add_us = 0;
- len = grub_strlen (array->name);
- if (len && grub_isdigit (array->name[len-1]))
- add_us = 1;
- for (p = array_list; p != NULL; p = p->next)
- {
- int cur_num;
- char *num, *end;
- if (grub_strncmp (p->name, array->name, len) != 0)
- continue;
- if (p->name[len] == 0)
- {
- need_new_name = 1;
- continue;
- }
- if (add_us && p->name[len] != '_')
- continue;
- if (add_us)
- num = p->name + len + 1;
- else
- num = p->name + len;
- if (!grub_isdigit (num[0]))
- continue;
- cur_num = grub_strtoull (num, &end, 10);
- if (end[0])
- continue;
- if (cur_num > max_used_number)
- max_used_number = cur_num;
- }
- if (need_new_name)
- {
- char *tmp;
- tmp = grub_xasprintf ("%s%s%d", array->name, add_us ? "_" : "",
- max_used_number + 1);
- if (!tmp)
- return grub_errno;
- grub_free (array->name);
- array->name = tmp;
- }
- }
-
- /* Add our new array to the list. */
- array->next = array_list;
- array_list = array;
-
- /* RAID 1 doesn't use a chunksize but code assumes one so set
- one. */
- if (array->level == 1)
- array->chunk_size = 64;
- }
-
- /* Add the device to the array. */
- array->members[new_array->index].device = disk;
- array->members[new_array->index].start_sector = start_sector;
- array->nr_devs++;
- if (!was_readable && grub_is_array_readable (array))
- array->became_readable_at = inscnt++;
-
- return 0;
-}
-
-static void
-free_array (void)
-{
- struct grub_raid_array *array;
-
- array = array_list;
- while (array)
- {
- struct grub_raid_array *p;
- unsigned int i;
-
- p = array;
- array = array->next;
-
- for (i = 0; i < p->allocated_devs; i++)
- if (p->members[i].device)
- grub_disk_close (p->members[i].device);
- grub_free (p->members);
-
- grub_free (p->uuid);
- grub_free (p->name);
- grub_free (p);
- }
-
- array_list = 0;
-}
-
-void
-grub_raid_register (grub_raid_t raid)
-{
- raid->next = grub_raid_list;
- grub_raid_list = raid;
-}
-
-void
-grub_raid_unregister (grub_raid_t raid)
-{
- grub_raid_t *p, q;
-
- for (p = &grub_raid_list, q = *p; q; p = &(q->next), q = q->next)
- if (q == raid)
- {
- *p = q->next;
- break;
- }
-}
-
-static struct grub_disk_dev grub_raid_dev =
- {
- .name = "raid",
- .id = GRUB_DISK_DEVICE_RAID_ID,
- .iterate = grub_raid_iterate,
- .open = grub_raid_open,
- .close = grub_raid_close,
- .read = grub_raid_read,
- .write = grub_raid_write,
-#ifdef GRUB_UTIL
- .memberlist = grub_raid_memberlist,
- .raidname = grub_raid_getname,
-#endif
- .next = 0
- };
-
-\f
-GRUB_MOD_INIT(raid)
-{
- grub_disk_dev_register (&grub_raid_dev);
-}
-
-GRUB_MOD_FINI(raid)
-{
- grub_disk_dev_unregister (&grub_raid_dev);
- free_array ();
-}
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
#include <grub/crypto.h>
GRUB_MOD_LICENSE ("GPLv3+");
static grub_err_t
-grub_raid5_recover (struct grub_raid_array *array, int disknr,
+grub_raid5_recover (struct grub_diskfilter_segment *array, int disknr,
char *buf, grub_disk_addr_t sector, int size)
{
char *buf2;
grub_memset (buf, 0, size);
- for (i = 0; i < (int) array->total_devs; i++)
+ for (i = 0; i < (int) array->node_count; i++)
{
grub_err_t err;
if (i == disknr)
continue;
- err = grub_disk_read (array->members[i].device,
- array->members[i].start_sector + sector,
- 0, size, buf2);
+ err = grub_diskfilter_read_node (&array->nodes[i], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf2);
if (err)
{
return err;
}
- grub_crypto_xor (buf, buf2, buf2, size);
+ grub_crypto_xor (buf, buf, buf2, size);
}
grub_free (buf2);
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/misc.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
#include <grub/crypto.h>
GRUB_MOD_LICENSE ("GPLv3+");
}
static grub_err_t
-grub_raid6_recover (struct grub_raid_array *array, int disknr, int p,
+grub_raid6_recover (struct grub_diskfilter_segment *array, int disknr, int p,
char *buf, grub_disk_addr_t sector, int size)
{
int i, q, pos;
goto quit;
q = p + 1;
- if (q == (int) array->total_devs)
+ if (q == (int) array->node_count)
q = 0;
pos = q + 1;
- if (pos == (int) array->total_devs)
+ if (pos == (int) array->node_count)
pos = 0;
- for (i = 0; i < (int) array->total_devs - 2; i++)
+ for (i = 0; i < (int) array->node_count - 2; i++)
{
+ int c;
+ if (array->layout & GRUB_RAID_LAYOUT_MUL_FROM_POS)
+ c = pos;
+ else
+ c = i;
if (pos == disknr)
- bad1 = i;
+ bad1 = c;
else
{
- if ((array->members[pos].device) &&
- (! grub_disk_read (array->members[pos].device,
- array->members[pos].start_sector + sector,
- 0, size, buf)))
+ if (! grub_diskfilter_read_node (&array->nodes[pos], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf))
{
grub_crypto_xor (pbuf, pbuf, buf, size);
- grub_raid_block_mulx (i, buf, size);
+ grub_raid_block_mulx (c, buf, size);
grub_crypto_xor (qbuf, qbuf, buf, size);
}
else
if (bad2 >= 0)
goto quit;
- bad2 = i;
+ bad2 = c;
grub_errno = GRUB_ERR_NONE;
}
}
pos++;
- if (pos == (int) array->total_devs)
+ if (pos == (int) array->node_count)
pos = 0;
}
if (bad2 < 0)
{
/* One bad device */
- if ((array->members[p].device) &&
- (! grub_disk_read (array->members[p].device,
- array->members[p].start_sector + sector,
- 0, size, buf)))
+ if ((! grub_diskfilter_read_node (&array->nodes[p], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf)))
{
grub_crypto_xor (buf, buf, pbuf, size);
goto quit;
}
- if (! array->members[q].device)
- {
- grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore");
- goto quit;
- }
-
grub_errno = GRUB_ERR_NONE;
- if (grub_disk_read (array->members[q].device,
- array->members[q].start_sector + sector, 0, size, buf))
+ if (grub_diskfilter_read_node (&array->nodes[q], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (buf, buf, qbuf, size);
/* Two bad devices */
int c;
- if ((! array->members[p].device) || (! array->members[q].device))
- {
- grub_error (GRUB_ERR_READ_ERROR, "not enough disk to restore");
- goto quit;
- }
-
- if (grub_disk_read (array->members[p].device,
- array->members[p].start_sector + sector,
- 0, size, buf))
+ if (grub_diskfilter_read_node (&array->nodes[p], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (pbuf, pbuf, buf, size);
- if (grub_disk_read (array->members[q].device,
- array->members[q].start_sector + sector,
- 0, size, buf))
+ if (grub_diskfilter_read_node (&array->nodes[q], sector,
+ size >> GRUB_DISK_SECTOR_BITS, buf))
goto quit;
grub_crypto_xor (qbuf, qbuf, buf, size);
\f
-static grub_disk_dev_t grub_disk_dev_list;
+grub_disk_dev_t grub_disk_dev_list;
void
grub_disk_dev_register (grub_disk_dev_t dev)
}
}
-int
-grub_disk_dev_iterate (int (*hook) (const char *name))
-{
- grub_disk_dev_t p;
- grub_disk_pull_t pull;
-
- for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
- for (p = grub_disk_dev_list; p; p = p->next)
- if (p->iterate && (p->iterate) (hook, pull))
- return 1;
-
- return 0;
-}
-
/* Return the location of the first ',', if any, which is not
escaped by a '\'. */
static const char *
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
# ifndef BLKGETSIZE64
# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
# endif /* ! BLKGETSIZE64 */
-# ifndef MAJOR
-# ifndef MINORBITS
-# define MINORBITS 8
-# endif /* ! MINORBITS */
-# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
-# endif /* ! MAJOR */
-# ifndef FLOPPY_MAJOR
-# define FLOPPY_MAJOR 2
-# endif /* ! FLOPPY_MAJOR */
-# ifndef LOOP_MAJOR
-# define LOOP_MAJOR 7
-# endif /* ! LOOP_MAJOR */
#endif /* __linux__ */
#ifdef __CYGWIN__
# include <sys/ioctl.h>
# include <cygwin/fs.h> /* BLKGETSIZE64 */
# include <cygwin/hdreg.h> /* HDIO_GETGEO */
-# define MAJOR(dev) ((unsigned) ((dev) >> 16))
-# define FLOPPY_MAJOR 2
#endif
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
# include <sys/sysctl.h>
# include <sys/mount.h>
#include <libgeom.h>
-# define MAJOR(dev) major(dev)
-# define FLOPPY_MAJOR 2
#endif
#if defined (__sun__)
# include <util.h> /* getrawpartition */
# endif /* HAVE_GETRAWPARTITION */
# include <sys/fdio.h>
-# ifndef FLOPPY_MAJOR
-# define FLOPPY_MAJOR 2
-# endif /* ! FLOPPY_MAJOR */
# ifndef RAW_FLOPPY_MAJOR
# define RAW_FLOPPY_MAJOR 9
# endif /* ! RAW_FLOPPY_MAJOR */
*off_out = 0;
}
-static grub_disk_addr_t
-find_partition_start (const char *dev)
+grub_disk_addr_t
+grub_hostdisk_find_partition_start (const char *dev)
{
grub_disk_addr_t out;
if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
}
#elif defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined (__sun__)
-static grub_disk_addr_t
-find_partition_start (const char *dev)
+grub_disk_addr_t
+grub_hostdisk_find_partition_start (const char *dev)
{
int fd;
#ifdef __sun__
missing = 0;
close (fd);
- start = find_partition_start (real_dev);
+ start = grub_hostdisk_find_partition_start (real_dev);
/* We don't care about errors here. */
grub_errno = GRUB_ERR_NONE;
}
#endif
+const char *
+grub_hostdisk_os_dev_to_grub_drive (const char *os_disk, int add)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE (map); i++)
+ if (! map[i].device)
+ break;
+ else if (strcmp (map[i].device, os_disk) == 0)
+ return map[i].drive;
+
+ if (!add)
+ return NULL;
+
+ if (i == ARRAY_SIZE (map))
+ grub_util_error (_("device count exceeds limit"));
+
+ map[i].device = xstrdup (os_disk);
+ map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk));
+ strcpy (map[i].drive, "hostdisk/");
+ strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
+ map[i].device_map = 0;
+
+ return map[i].drive;
+}
+
static int
open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
{
grub_disk_dev_unregister (&grub_util_biosdisk_dev);
}
-/*
- * Note: we do not use the new partition naming scheme as dos_part does not
- * necessarily correspond to an msdos partition.
- */
-static char *
-make_device_name (int drive, int dos_part, int bsd_part)
-{
- char *ret, *ptr, *end;
- const char *iptr;
-
- ret = xmalloc (strlen (map[drive].drive) * 2
- + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
- ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
- end = (ret + strlen (map[drive].drive) * 2
- + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
- ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
- ptr = ret;
- for (iptr = map[drive].drive; *iptr; iptr++)
- {
- if (*iptr == ',')
- *ptr++ = '\\';
- *ptr++ = *iptr;
- }
- *ptr = 0;
- if (dos_part >= 0)
- snprintf (ptr, end - ptr, ",%d", dos_part + 1);
- ptr += strlen (ptr);
- if (bsd_part >= 0)
- snprintf (ptr, end - ptr, ",%d", bsd_part + 1);
-
- return ret;
-}
-
-#ifdef HAVE_DEVICE_MAPPER
-static int
-grub_util_get_dm_node_linear_info (const char *dev,
- int *maj, int *min)
-{
- struct dm_task *dmt;
- void *next = NULL;
- uint64_t length, start;
- char *target, *params;
- char *ptr;
- int major, minor;
-
- dmt = dm_task_create(DM_DEVICE_TABLE);
- if (!dmt)
- return 0;
-
- if (!dm_task_set_name(dmt, dev))
- return 0;
- dm_task_no_open_count(dmt);
- if (!dm_task_run(dmt))
- return 0;
- next = dm_get_next_target(dmt, next, &start, &length,
- &target, ¶ms);
- if (grub_strcmp (target, "linear") != 0)
- return 0;
- major = grub_strtoul (params, &ptr, 10);
- if (grub_errno)
- {
- grub_errno = GRUB_ERR_NONE;
- return 0;
- }
- if (*ptr != ':')
- return 0;
- ptr++;
- minor = grub_strtoul (ptr, 0, 10);
- if (grub_errno)
- {
- grub_errno = GRUB_ERR_NONE;
- return 0;
- }
- if (maj)
- *maj = major;
- if (min)
- *min = minor;
- return 1;
-}
-#endif
-
-static char *
-convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
-{
-#if defined(__linux__)
- char *path = xmalloc (PATH_MAX);
- if (! realpath (os_dev, path))
- return NULL;
-
- if (strncmp ("/dev/", path, 5) == 0)
- {
- char *p = path + 5;
-
- /* If this is an IDE disk. */
- if (strncmp ("ide/", p, 4) == 0)
- {
- p = strstr (p, "part");
- if (p)
- strcpy (p, "disc");
-
- return path;
- }
-
- /* If this is a SCSI disk. */
- if (strncmp ("scsi/", p, 5) == 0)
- {
- p = strstr (p, "part");
- if (p)
- strcpy (p, "disc");
-
- return path;
- }
-
- /* If this is a DAC960 disk. */
- if (strncmp ("rd/c", p, 4) == 0)
- {
- /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
-
- /* If this is a Mylex AcceleRAID Array. */
- if (strncmp ("rs/c", p, 4) == 0)
- {
- /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
- /* If this is a CCISS disk. */
- if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
- {
- /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
-
- /* If this is a Compaq Intelligent Drive Array. */
- if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
- {
- /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
-
- /* If this is an I2O disk. */
- if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
- {
- /* /dev/i2o/hd[a-z]([0-9]+)? */
- p[sizeof ("i2o/hda") - 1] = '\0';
- return path;
- }
-
- /* If this is a MultiMediaCard (MMC). */
- if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
- {
- /* /dev/mmcblk[0-9]+(p[0-9]+)? */
- p = strchr (p, 'p');
- if (p)
- *p = '\0';
-
- return path;
- }
-
- if (strncmp ("md", p, 2) == 0
- && p[2] >= '0' && p[2] <= '9')
- {
- char *ptr = p + 2;
- while (*ptr >= '0' && *ptr <= '9')
- ptr++;
- *ptr = 0;
- return path;
- }
-
- /* If this is an IDE, SCSI or Virtio disk. */
- if (strncmp ("vdisk", p, 5) == 0
- && p[5] >= 'a' && p[5] <= 'z')
- {
- /* /dev/vdisk[a-z][0-9]* */
- p[6] = '\0';
- return path;
- }
- if ((strncmp ("hd", p, 2) == 0
- || strncmp ("vd", p, 2) == 0
- || strncmp ("sd", p, 2) == 0)
- && p[2] >= 'a' && p[2] <= 'z')
- {
- char *pp = p + 2;
- while (*pp >= 'a' && *pp <= 'z')
- pp++;
- /* /dev/[hsv]d[a-z]+[0-9]* */
- *pp = '\0';
- return path;
- }
-
- /* If this is a Xen virtual block device. */
- if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
- {
- char *pp = p + 3;
- while (*pp >= 'a' && *pp <= 'z')
- pp++;
- /* /dev/xvd[a-z]+[0-9]* */
- *pp = '\0';
- return path;
- }
-
-#ifdef HAVE_DEVICE_MAPPER
- /* If this is a DM-RAID device.
- Compare os_dev rather than path here, since nodes under
- /dev/mapper/ are often symlinks. */
- if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
- {
- struct dm_tree *tree;
- uint32_t maj, min;
- struct dm_tree_node *node = NULL, *child;
- void *handle;
- const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
-
- tree = dm_tree_create ();
- if (! tree)
- {
- grub_dprintf ("hostdisk", "dm_tree_create failed\n");
- goto devmapper_out;
- }
-
- maj = major (st->st_rdev);
- min = minor (st->st_rdev);
- if (! dm_tree_add_dev (tree, maj, min))
- {
- grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
- goto devmapper_out;
- }
-
- node = dm_tree_find_node (tree, maj, min);
- if (! node)
- {
- grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
- goto devmapper_out;
- }
- node_uuid = dm_tree_node_get_uuid (node);
- if (! node_uuid)
- {
- grub_dprintf ("hostdisk", "%s has no DM uuid\n", path);
- node = NULL;
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "LVM-", 4) == 0)
- {
- grub_dprintf ("hostdisk", "%s is an LVM\n", path);
- node = NULL;
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "mpath-", 6) == 0)
- {
- /* Multipath partitions have partN-mpath-* UUIDs, and are
- linear mappings so are handled by
- grub_util_get_dm_node_linear_info. Multipath disks are not
- linear mappings and must be handled specially. */
- grub_dprintf ("hostdisk", "%s is a multipath disk\n", path);
- mapper_name = dm_tree_node_get_name (node);
- goto devmapper_out;
- }
- if (strncmp (node_uuid, "DMRAID-", 7) != 0)
- {
- int major, minor;
- const char *node_name;
- grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
-
- if ((node_name = dm_tree_node_get_name (node))
- && grub_util_get_dm_node_linear_info (node_name,
- &major, &minor))
- {
- if (tree)
- dm_tree_free (tree);
- free (path);
- char *ret = grub_find_device ("/dev",
- (major << 8) | minor);
- return ret;
- }
-
- node = NULL;
- goto devmapper_out;
- }
-
- handle = NULL;
- /* Counter-intuitively, device-mapper refers to the disk-like
- device containing a DM-RAID partition device as a "child" of
- the partition device. */
- child = dm_tree_next_child (&handle, node, 0);
- if (! child)
- {
- grub_dprintf ("hostdisk", "%s has no DM children\n", path);
- goto devmapper_out;
- }
- child_uuid = dm_tree_node_get_uuid (child);
- if (! child_uuid)
- {
- grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path);
- goto devmapper_out;
- }
- else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
- {
- grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path);
- goto devmapper_out;
- }
- child_name = dm_tree_node_get_name (child);
- if (! child_name)
- {
- grub_dprintf ("hostdisk", "%s child has no DM name\n", path);
- goto devmapper_out;
- }
- mapper_name = child_name;
-
-devmapper_out:
- if (! mapper_name && node)
- {
- /* This is a DM-RAID disk, not a partition. */
- mapper_name = dm_tree_node_get_name (node);
- if (! mapper_name)
- grub_dprintf ("hostdisk", "%s has no DM name\n", path);
- }
- if (tree)
- dm_tree_free (tree);
- free (path);
- if (mapper_name)
- return xasprintf ("/dev/mapper/%s", mapper_name);
- else
- return NULL;
- }
-#endif /* HAVE_DEVICE_MAPPER */
- }
-
- return path;
-
-#elif defined(__GNU__)
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
- {
- char *p = strchr (path + 7, 's');
- if (p)
- *p = '\0';
- }
- return path;
-
-#elif defined(__CYGWIN__)
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
- path[8] = 0;
- return path;
-
-#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- char *out, *out2;
- if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return xstrdup (os_dev);
- grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
-
- out2 = xasprintf ("/dev/%s", out);
- free (out);
-
- return out2;
-#elif defined(__APPLE__)
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/", path, 5) == 0)
- {
- char *p;
- for (p = path + 5; *p; ++p)
- if (grub_isdigit(*p))
- {
- p = strpbrk (p, "sp");
- if (p)
- *p = '\0';
- break;
- }
- }
- return path;
-
-#elif defined(__NetBSD__)
- /* NetBSD uses "/dev/r[a-z]+[0-9][a-z]". */
- char *path = xstrdup (os_dev);
- if (strncmp ("/dev/r", path, sizeof("/dev/r") - 1) == 0 &&
- (path[sizeof("/dev/r") - 1] >= 'a' && path[sizeof("/dev/r") - 1] <= 'z') &&
- strncmp ("fd", path + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
- {
- char *p;
- for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
- if (grub_isdigit(*p))
- {
- p++;
- if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
- {
- /* path matches the required regular expression and
- p points to its last character. */
- int rawpart = -1;
-# ifdef HAVE_GETRAWPARTITION
- rawpart = getrawpartition();
-# endif /* HAVE_GETRAWPARTITION */
- if (rawpart >= 0)
- *p = 'a' + rawpart;
- }
- }
- }
- return path;
-
-#elif defined (__sun__)
- char *colon = grub_strrchr (os_dev, ':');
- if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
- && colon)
- {
- char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
- grub_memcpy (ret, os_dev, colon - os_dev);
- grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
- return ret;
- }
- else
- return xstrdup (os_dev);
-#else
-# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
- return xstrdup (os_dev);
-#endif
-}
-
-#if defined(__sun__)
-static int
-device_is_wholedisk (const char *os_dev)
-{
- if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0)
- return 1;
- if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1),
- ":q,raw", (sizeof (":q,raw") - 1)) == 0)
- return 1;
- return 0;
-}
-#endif
-
-#if defined(__linux__) || defined(__CYGWIN__)
-static int
-device_is_wholedisk (const char *os_dev)
-{
- int len = strlen (os_dev);
-
- if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9')
- return 1;
- return 0;
-}
-#endif
-
-#if defined(__NetBSD__)
-/* Try to determine whether a given device name corresponds to a whole disk.
- This function should give in most cases a definite answer, but it may
- actually give an approximate one in the following sense: if the return
- value is 0 then the device name does not correspond to a whole disk. */
-static int
-device_is_wholedisk (const char *os_dev)
-{
- int len = strlen (os_dev);
- int rawpart = -1;
-
-# ifdef HAVE_GETRAWPARTITION
- rawpart = getrawpartition();
-# endif /* HAVE_GETRAWPARTITION */
- if (rawpart < 0)
- return 1;
- return (os_dev[len - 1] == ('a' + rawpart));
-}
-#endif /* defined(__NetBSD__) */
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-static int
-device_is_wholedisk (const char *os_dev)
-{
- const char *p;
-
- if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
- return 0;
-
- for (p = os_dev + sizeof ("/dev/") - 1; *p; ++p)
- if (grub_isdigit (*p))
- {
- if (strchr (p, 's'))
- return 0;
- break;
- }
-
- return 1;
-}
-#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
-
-static int
-find_system_device (const char *os_dev, struct stat *st, int convert, int add)
-{
- unsigned int i;
- char *os_disk;
-
- if (convert)
- os_disk = convert_system_partition_to_system_disk (os_dev, st);
- else
- os_disk = xstrdup (os_dev);
- if (! os_disk)
- return -1;
-
- for (i = 0; i < ARRAY_SIZE (map); i++)
- if (! map[i].device)
- break;
- else if (strcmp (map[i].device, os_disk) == 0)
- {
- free (os_disk);
- return i;
- }
-
- if (!add)
- {
- free (os_disk);
- return -1;
- }
-
- if (i == ARRAY_SIZE (map))
- grub_util_error (_("device count exceeds limit"));
-
- map[i].device = os_disk;
- map[i].drive = xmalloc (sizeof ("hostdisk/") + strlen (os_disk));
- strcpy (map[i].drive, "hostdisk/");
- strcpy (map[i].drive + sizeof ("hostdisk/") - 1, os_disk);
- map[i].device_map = 0;
-
- return i;
-}
-
-int
-grub_util_biosdisk_is_present (const char *os_dev)
-{
- struct stat st;
-
- if (stat (os_dev, &st) < 0)
- return 0;
-
- return find_system_device (os_dev, &st, 1, 0) != -1;
-}
-
-char *
-grub_util_biosdisk_get_grub_dev (const char *os_dev)
-{
- struct stat st;
- int drive;
- char *sys_disk;
-
- grub_util_info ("Looking for %s", os_dev);
-
- if (stat (os_dev, &st) < 0)
- {
- grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
- grub_util_info ("cannot stat `%s'", os_dev);
- return 0;
- }
-
- drive = find_system_device (os_dev, &st, 1, 1);
- if (drive < 0)
- {
- grub_error (GRUB_ERR_UNKNOWN_DEVICE,
- "no mapping exists for `%s'", os_dev);
- grub_util_info ("no mapping exists for `%s'", os_dev);
- return 0;
- }
-
- sys_disk = convert_system_partition_to_system_disk (os_dev, &st);
- if (grub_strcmp (os_dev, sys_disk) == 0)
- {
- free (sys_disk);
- return make_device_name (drive, -1, -1);
- }
- free (sys_disk);
-
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
- if (! S_ISCHR (st.st_mode))
-#else
- if (! S_ISBLK (st.st_mode))
-#endif
- return make_device_name (drive, -1, -1);
-
-#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
-
- /* Linux counts partitions uniformly, whether a BSD partition or a DOS
- partition, so mapping them to GRUB devices is not trivial.
- Here, get the start sector of a partition by HDIO_GETGEO, and
- compare it with each partition GRUB recognizes.
-
- Cygwin /dev/sdXN emulation uses Windows partition mapping. It
- does not count the extended partition and missing primary
- partitions. Use same method as on Linux here.
-
- For NetBSD and FreeBSD, proceed as for Linux, except that the start
- sector is obtained from the disk label. */
- {
- char *name, *partname;
- grub_disk_t disk;
- grub_disk_addr_t start;
- auto int find_partition (grub_disk_t dsk,
- const grub_partition_t partition);
-
- int find_partition (grub_disk_t dsk __attribute__ ((unused)),
- const grub_partition_t partition)
- {
- grub_disk_addr_t part_start = 0;
- grub_util_info ("Partition %d starts from %lu",
- partition->number, partition->start);
-
- part_start = grub_partition_get_start (partition);
-
- if (start == part_start)
- {
- partname = grub_partition_get_name (partition);
- return 1;
- }
-
- return 0;
- }
-
- name = make_device_name (drive, -1, -1);
-
-# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
- if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
- return name;
-# else /* defined(HAVE_DIOCGDINFO) */
- /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
- * different, we know that os_dev cannot be a floppy device. */
-# endif /* !defined(HAVE_DIOCGDINFO) */
-
- start = find_partition_start (os_dev);
- if (grub_errno != GRUB_ERR_NONE)
- {
- free (name);
- return 0;
- }
-
- grub_util_info ("%s starts from %lu", os_dev, start);
-
- if (start == 0 && device_is_wholedisk (os_dev))
- return name;
-
- grub_util_info ("opening the device %s", name);
- disk = grub_disk_open (name);
- free (name);
-
- if (! disk)
- {
- /* We already know that the partition exists. Given that we already
- checked the device map above, we can only get
- GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist.
- This can happen on Xen, where disk images in the host can be
- assigned to devices that have partition-like names in the guest
- but are really more like disks. */
- if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
- {
- grub_util_warn
- ("disk does not exist, so falling back to partition device %s",
- os_dev);
-
- drive = find_system_device (os_dev, &st, 0, 1);
- if (drive < 0)
- {
- grub_error (GRUB_ERR_UNKNOWN_DEVICE,
- "no mapping exists for `%s'", os_dev);
- return 0;
- }
-
- return make_device_name (drive, -1, -1);
- }
- else
- return 0;
- }
-
- partname = NULL;
- grub_partition_iterate (disk, find_partition);
- if (grub_errno != GRUB_ERR_NONE)
- {
- grub_disk_close (disk);
- return 0;
- }
-
- if (partname == NULL)
- {
- grub_disk_close (disk);
- grub_util_info ("cannot find the partition of `%s'", os_dev);
- grub_error (GRUB_ERR_BAD_DEVICE,
- "cannot find the partition of `%s'", os_dev);
- return 0;
- }
-
- name = grub_xasprintf ("%s,%s", disk->name, partname);
- free (partname);
- grub_disk_close (disk);
- return name;
- }
-
-#elif defined(__GNU__)
- /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
- {
- char *p;
- int dos_part = -1;
- int bsd_part = -1;
-
- p = strrchr (os_dev, 's');
- if (p)
- {
- long int n;
- char *q;
-
- p++;
- n = strtol (p, &q, 10);
- if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX)
- {
- dos_part = (int) n - 1;
-
- if (*q >= 'a' && *q <= 'g')
- bsd_part = *q - 'a';
- }
- }
-
- return make_device_name (drive, dos_part, bsd_part);
- }
-
-#else
-# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
- return make_device_name (drive, -1, -1);
-#endif
-}
-
const char *
grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk)
{
const char *
grub_util_biosdisk_get_osdev (grub_disk_t disk)
{
- return map[disk->id].device;
-}
-
-int
-grub_util_biosdisk_is_floppy (grub_disk_t disk)
-{
- struct stat st;
- int fd;
-
if (disk->dev != &grub_util_biosdisk_dev)
return 0;
- fd = open (map[disk->id].device, O_RDONLY);
- /* Shouldn't happen. */
- if (fd == -1)
- return 0;
-
- /* Shouldn't happen either. */
- if (fstat (fd, &st) < 0)
- {
- close (fd);
- return 0;
- }
-
- close (fd);
-
-#if defined(__NetBSD__)
- if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
- return 1;
-#endif
-
-#if defined(FLOPPY_MAJOR)
- if (major(st.st_rdev) == FLOPPY_MAJOR)
-#else
- /* Some kernels (e.g. kFreeBSD) don't have a static major number
- for floppies, but they still use a "fd[0-9]" pathname. */
- if (map[disk->id].device[5] == 'f'
- && map[disk->id].device[6] == 'd'
- && map[disk->id].device[7] >= '0'
- && map[disk->id].device[7] <= '9')
-#endif
- return 1;
-
- return 0;
+ return map[disk->id].device;
}
\f
-static grub_err_t
-gpt_partition_map_iterate (grub_disk_t disk,
- int (*hook) (grub_disk_t disk,
- const grub_partition_t partition))
+grub_err_t
+grub_gpt_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition))
{
struct grub_partition part;
struct grub_gpt_header gpt;
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"GPT currently supports only PC-BIOS embedding");
- err = gpt_partition_map_iterate (disk, find_usable_region);
+ err = grub_gpt_partition_map_iterate (disk, find_usable_region);
if (err)
return err;
static struct grub_partition_map grub_gpt_partition_map =
{
.name = "gpt",
- .iterate = gpt_partition_map_iterate,
+ .iterate = grub_gpt_partition_map_iterate,
#ifdef GRUB_UTIL
.embed = gpt_partition_map_embed
#endif
GRUB_DISK_DEVICE_OFDISK_ID,
GRUB_DISK_DEVICE_LOOPBACK_ID,
GRUB_DISK_DEVICE_EFIDISK_ID,
- GRUB_DISK_DEVICE_RAID_ID,
- GRUB_DISK_DEVICE_LVM_ID,
+ GRUB_DISK_DEVICE_DISKFILTER_ID,
GRUB_DISK_DEVICE_HOST_ID,
GRUB_DISK_DEVICE_ATA_ID,
GRUB_DISK_DEVICE_MEMDISK_ID,
};
typedef struct grub_disk_dev *grub_disk_dev_t;
+extern grub_disk_dev_t EXPORT_VAR (grub_disk_dev_list);
+
struct grub_partition;
/* Disk. */
void EXPORT_FUNC(grub_disk_dev_register) (grub_disk_dev_t dev);
void EXPORT_FUNC(grub_disk_dev_unregister) (grub_disk_dev_t dev);
-int EXPORT_FUNC(grub_disk_dev_iterate) (int (*hook) (const char *name));
+static inline int
+grub_disk_dev_iterate (int (*hook) (const char *name))
+{
+ grub_disk_dev_t p;
+ grub_disk_pull_t pull;
+
+ for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->iterate && (p->iterate) (hook, pull))
+ return 1;
+
+ return 0;
+}
grub_disk_t EXPORT_FUNC(grub_disk_open) (const char *name);
void EXPORT_FUNC(grub_disk_close) (grub_disk_t disk);
#if defined (GRUB_UTIL) || defined (GRUB_MACHINE_EMU)
void grub_lvm_init (void);
+void grub_ldm_init (void);
void grub_mdraid09_init (void);
void grub_mdraid1x_init (void);
-void grub_raid_init (void);
+void grub_diskfilter_init (void);
void grub_lvm_fini (void);
+void grub_ldm_fini (void);
void grub_mdraid09_fini (void);
void grub_mdraid1x_fini (void);
-void grub_raid_fini (void);
+void grub_diskfilter_fini (void);
#endif
#endif /* ! GRUB_DISK_HEADER */
--- /dev/null
+/* diskfilter.h - On disk structures for RAID. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008,2010 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/>.
+ */
+
+#ifndef GRUB_DISKFILTER_H
+#define GRUB_DISKFILTER_H 1
+
+#include <grub/types.h>
+#include <grub/list.h>
+
+enum
+ {
+ GRUB_RAID_LAYOUT_RIGHT_MASK = 1,
+ GRUB_RAID_LAYOUT_SYMMETRIC_MASK = 2,
+ GRUB_RAID_LAYOUT_MUL_FROM_POS = 4,
+
+ GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC = 0,
+ GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC = GRUB_RAID_LAYOUT_RIGHT_MASK,
+ GRUB_RAID_LAYOUT_LEFT_SYMMETRIC = GRUB_RAID_LAYOUT_SYMMETRIC_MASK,
+ GRUB_RAID_LAYOUT_RIGHT_SYMMETRIC = (GRUB_RAID_LAYOUT_RIGHT_MASK
+ | GRUB_RAID_LAYOUT_SYMMETRIC_MASK)
+ };
+
+
+struct grub_diskfilter_vg {
+ char *uuid;
+ grub_size_t uuid_len;
+ /* Optional. */
+ char *name;
+ int extent_size;
+ struct grub_diskfilter_pv *pvs;
+ struct grub_diskfilter_lv *lvs;
+ struct grub_diskfilter_vg *next;
+
+#ifdef GRUB_UTIL
+ struct grub_diskfilter *driver;
+#endif
+};
+
+struct grub_diskfilter_pv_id {
+ union
+ {
+ char *uuid;
+ int id;
+ };
+ grub_size_t uuidlen;
+};
+
+struct grub_diskfilter_pv {
+ struct grub_diskfilter_pv_id id;
+ /* Optional. */
+ char *name;
+ grub_disk_t disk;
+ grub_disk_addr_t part_start;
+ grub_disk_addr_t part_size;
+ grub_disk_addr_t start_sector; /* Sector number where the data area starts. */
+ struct grub_diskfilter_pv *next;
+ /* Optional. */
+ grub_uint8_t *internal_id;
+};
+
+struct grub_diskfilter_lv {
+ /* Name used for disk. */
+ char *fullname;
+ /* Optional. */
+ char *name;
+ int number;
+ unsigned int segment_count;
+ grub_size_t segment_alloc;
+ grub_uint64_t size;
+ int became_readable_at;
+
+ int visible;
+
+ /* Pointer to segment_count segments. */
+ struct grub_diskfilter_segment *segments;
+ struct grub_diskfilter_vg *vg;
+ struct grub_diskfilter_lv *next;
+
+ /* Optional. */
+ char *internal_id;
+};
+
+struct grub_diskfilter_segment {
+ unsigned int start_extent;
+ unsigned int extent_count;
+ enum
+ {
+ GRUB_DISKFILTER_STRIPED = 0,
+ GRUB_DISKFILTER_MIRROR = 1,
+ GRUB_DISKFILTER_RAID4 = 4,
+ GRUB_DISKFILTER_RAID5 = 5,
+ GRUB_DISKFILTER_RAID6 = 6,
+ GRUB_DISKFILTER_RAID10 = 10,
+ } type;
+ int layout;
+ /* valid only for raid10. */
+ grub_uint64_t raid_member_size;
+
+ unsigned int node_count;
+ unsigned int node_alloc;
+ struct grub_diskfilter_node *nodes;
+
+ unsigned int stripe_size;
+};
+
+struct grub_diskfilter_node {
+ grub_disk_addr_t start;
+ /* Optional. */
+ char *name;
+ struct grub_diskfilter_pv *pv;
+ struct grub_diskfilter_lv *lv;
+};
+
+struct grub_diskfilter_vg *
+grub_diskfilter_get_vg_by_uuid (grub_size_t uuidlen, char *uuid);
+
+struct grub_diskfilter
+{
+ struct grub_diskfilter *next;
+ struct grub_diskfilter **prev;
+
+ const char *name;
+
+ struct grub_diskfilter_vg * (*detect) (grub_disk_t disk,
+ struct grub_diskfilter_pv_id *id,
+ grub_disk_addr_t *start_sector);
+};
+typedef struct grub_diskfilter *grub_diskfilter_t;
+
+extern grub_diskfilter_t grub_diskfilter_list;
+static inline void
+grub_diskfilter_register (grub_diskfilter_t diskfilter)
+{
+ grub_list_push (GRUB_AS_LIST_P (&grub_diskfilter_list),
+ GRUB_AS_LIST (diskfilter));
+}
+static inline void
+grub_diskfilter_unregister (grub_diskfilter_t diskfilter)
+{
+ grub_list_remove (GRUB_AS_LIST (diskfilter));
+}
+
+struct grub_diskfilter_vg *
+grub_diskfilter_make_raid (grub_size_t uuidlen, char *uuid, int nmemb,
+ char *name, grub_uint64_t disk_size,
+ grub_uint64_t stripe_size,
+ int layout, int level);
+
+typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_diskfilter_segment *array,
+ int disknr, char *buf,
+ grub_disk_addr_t sector,
+ int size);
+
+typedef grub_err_t (*grub_raid6_recover_func_t) (struct grub_diskfilter_segment *array,
+ int disknr, int p, char *buf,
+ grub_disk_addr_t sector,
+ int size);
+
+extern grub_raid5_recover_func_t grub_raid5_recover_func;
+extern grub_raid6_recover_func_t grub_raid6_recover_func;
+
+grub_err_t grub_diskfilter_vg_register (struct grub_diskfilter_vg *vg);
+
+grub_err_t
+grub_diskfilter_read_node (const struct grub_diskfilter_node *node,
+ grub_disk_addr_t sector,
+ grub_size_t size, char *buf);
+
+#ifdef GRUB_UTIL
+struct grub_diskfilter_pv *
+grub_diskfilter_get_pv_from_disk (grub_disk_t disk,
+ struct grub_diskfilter_vg **vg);
+#endif
+
+#endif /* ! GRUB_RAID_H */
#define GRUB_BIOSDISK_MACHINE_UTIL_HEADER 1
#include <grub/disk.h>
+#include <grub/partition.h>
#include <sys/types.h>
void grub_util_biosdisk_init (const char *dev_map);
grub_err_t
grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
void grub_util_cryptodisk_print_uuid (grub_disk_t disk);
+char *
+grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
+int
+grub_util_is_ldm (grub_disk_t disk);
+#ifdef GRUB_UTIL
+grub_err_t
+grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
+ grub_embed_type_t embed_type,
+ grub_disk_addr_t **sectors);
+#endif
+grub_disk_addr_t
+grub_hostdisk_find_partition_start (const char *dev);
+const char *
+grub_hostdisk_os_dev_to_grub_drive (const char *os_dev, int add);
+
#if !defined(__MINGW32__)
grub_uint64_t
grub_util_get_fd_sectors (int fd, unsigned *log_secsize);
#define GRUB_GPT_PARTITION_HEADER 1
#include <grub/types.h>
+#include <grub/partition.h>
struct grub_gpt_part_type
{
}
#define GRUB_GPT_PARTITION_TYPE_BIOS_BOOT \
- { grub_cpu_to_le32_compile_time (0x21686148), grub_cpu_to_le16_compile_time (0x6449), grub_cpu_to_le16_compile_time (0x6e6f), \
+ { grub_cpu_to_le32_compile_time (0x21686148), \
+ grub_cpu_to_le16_compile_time (0x6449), \
+ grub_cpu_to_le16_compile_time (0x6e6f), \
{ 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } \
}
+#define GRUB_GPT_PARTITION_TYPE_LDM \
+ { grub_cpu_to_le32_compile_time (0x5808C8AAU),\
+ grub_cpu_to_le16_compile_time (0x7E8F), \
+ grub_cpu_to_le16_compile_time (0x42E0), \
+ { 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3 } \
+ }
+
struct grub_gpt_header
{
grub_uint8_t magic[8];
char name[72];
} __attribute__ ((packed));
+grub_err_t
+grub_gpt_partition_map_iterate (grub_disk_t disk,
+ int (*hook) (grub_disk_t disk,
+ const grub_partition_t partition));
+
+
#endif /* ! GRUB_GPT_PARTITION_HEADER */
#define GRUB_LVM_H 1
#include <grub/types.h>
+#include <grub/diskfilter.h>
/* Length of ID string, excluding terminating zero. */
#define GRUB_LVM_ID_STRLEN 38
-struct grub_lvm_vg {
- char id[GRUB_LVM_ID_STRLEN+1];
- char *name;
- int extent_size;
- struct grub_lvm_pv *pvs;
- struct grub_lvm_lv *lvs;
- struct grub_lvm_vg *next;
-};
-
-struct grub_lvm_pv {
- char id[GRUB_LVM_ID_STRLEN+1];
- char *name;
- grub_disk_t disk;
- grub_disk_addr_t start; /* Sector number where the data area starts. */
- struct grub_lvm_pv *next;
-};
-
-struct grub_lvm_lv {
- char *name;
- char *fullname;
- char *compatname;
- unsigned int number;
- unsigned int segment_count;
- grub_uint64_t size;
-
- int visible;
-
- struct grub_lvm_segment *segments; /* Pointer to segment_count segments. */
- struct grub_lvm_vg *vg;
- struct grub_lvm_lv *next;
-};
-
-struct grub_lvm_segment {
- unsigned int start_extent;
- unsigned int extent_count;
- enum { GRUB_LVM_STRIPED, GRUB_LVM_MIRROR } type;
-
- unsigned int node_count;
- struct grub_lvm_node *nodes;
-
- unsigned int stripe_size;
-};
-
-struct grub_lvm_node {
- grub_disk_addr_t start;
- char *name;
- struct grub_lvm_pv *pv;
- struct grub_lvm_lv *lv;
-};
-
#define GRUB_LVM_LABEL_SIZE GRUB_DISK_SECTOR_SIZE
#define GRUB_LVM_LABEL_SCAN_SECTORS 4L
+++ /dev/null
-/* raid.h - On disk structures for RAID. */
-/*
- * GRUB -- GRand Unified Bootloader
- * Copyright (C) 2006,2007,2008,2010 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/>.
- */
-
-#ifndef GRUB_RAID_H
-#define GRUB_RAID_H 1
-
-#include <grub/types.h>
-
-#define GRUB_RAID_LAYOUT_LEFT_ASYMMETRIC 0
-#define GRUB_RAID_LAYOUT_RIGHT_ASYMMETRIC 1
-#define GRUB_RAID_LAYOUT_LEFT_SYMMETRIC 2
-#define GRUB_RAID_LAYOUT_RIGHT_SYMMETRIC 3
-
-#define GRUB_RAID_LAYOUT_RIGHT_MASK 1
-#define GRUB_RAID_LAYOUT_SYMMETRIC_MASK 2
-
-struct grub_raid_member
-{
- grub_disk_t device; /* Array of total_devs devices. */
- grub_disk_addr_t start_sector;
- /* Start of each device, in 512 byte sectors. */
-};
-
-struct grub_raid_array
-{
- int number; /* The device number, taken from md_minor so we
- are consistent with the device name in
- Linux. */
- int became_readable_at;
- int level; /* RAID levels, only 0, 1 or 5 at the moment. */
- int layout; /* Layout for RAID 5/6. */
- unsigned int total_devs; /* Total number of devices in the array. */
- grub_size_t chunk_size; /* The size of a chunk, in 512 byte sectors. */
- grub_uint64_t disk_size; /* Size of an individual disk, in 512 byte
- sectors. */
- unsigned int index; /* Index of current device. */
- int uuid_len; /* The length of uuid. */
- char *uuid; /* The UUID of the device. */
-
- /* The following field is setup by the caller. */
- char *name; /* That will be "md<number>". */
- unsigned int nr_devs; /* The number of devices we've found so far. */
- unsigned int allocated_devs;
- struct grub_raid_member *members;
- struct grub_raid_array *next;
-
-#ifdef GRUB_UTIL
- struct grub_raid *driver;
-#endif
-};
-
-struct grub_raid
-{
- const char *name;
-
- grub_err_t (*detect) (grub_disk_t disk, struct grub_raid_array *array,
- grub_disk_addr_t *start_sector);
-
- struct grub_raid *next;
-};
-typedef struct grub_raid *grub_raid_t;
-
-void grub_raid_register (grub_raid_t raid);
-void grub_raid_unregister (grub_raid_t raid);
-
-void grub_raid_block_xor (char *buf1, const char *buf2, int size);
-
-typedef grub_err_t (*grub_raid5_recover_func_t) (struct grub_raid_array *array,
- int disknr, char *buf,
- grub_disk_addr_t sector,
- int size);
-
-typedef grub_err_t (*grub_raid6_recover_func_t) (struct grub_raid_array *array,
- int disknr, int p, char *buf,
- grub_disk_addr_t sector,
- int size);
-
-extern grub_raid5_recover_func_t grub_raid5_recover_func;
-extern grub_raid6_recover_func_t grub_raid6_recover_func;
-
-#endif /* ! GRUB_RAID_H */
#include <grub/emu/hostdisk.h>
#include <grub/emu/getroot.h>
+#ifdef __linux__
+# include <sys/ioctl.h> /* ioctl */
+# include <sys/mount.h>
+# ifndef MAJOR
+# ifndef MINORBITS
+# define MINORBITS 8
+# endif /* ! MINORBITS */
+# define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
+# endif /* ! MAJOR */
+# ifndef FLOPPY_MAJOR
+# define FLOPPY_MAJOR 2
+# endif /* ! FLOPPY_MAJOR */
+#endif
+
+#ifdef __CYGWIN__
+# include <sys/ioctl.h>
+# include <cygwin/fs.h> /* BLKGETSIZE64 */
+# include <cygwin/hdreg.h> /* HDIO_GETGEO */
+# define MAJOR(dev) ((unsigned) ((dev) >> 16))
+# define FLOPPY_MAJOR 2
+#endif
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# include <sys/disk.h> /* DIOCGMEDIASIZE */
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/mount.h>
+#include <libgeom.h>
+# define MAJOR(dev) major(dev)
+# define FLOPPY_MAJOR 2
+#endif
+
+#if defined (__sun__)
+# include <sys/dkio.h>
+#endif
+
+#if defined(__APPLE__)
+# include <sys/disk.h>
+#endif
+
+#ifdef HAVE_DEVICE_MAPPER
+# include <libdevmapper.h>
+#endif
+
+#if defined(__NetBSD__)
+# define HAVE_DIOCGDINFO
+# include <sys/ioctl.h>
+# include <sys/disklabel.h> /* struct disklabel */
+#else /* !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__) */
+# undef HAVE_DIOCGDINFO
+#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
+
+#if defined(__NetBSD__)
+# ifdef HAVE_GETRAWPARTITION
+# include <util.h> /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+# include <sys/fdio.h>
+# ifndef FLOPPY_MAJOR
+# define FLOPPY_MAJOR 2
+# endif /* ! FLOPPY_MAJOR */
+# ifndef RAW_FLOPPY_MAJOR
+# define RAW_FLOPPY_MAJOR 9
+# endif /* ! RAW_FLOPPY_MAJOR */
+#endif /* defined(__NetBSD__) */
+
static void
strip_extra_slashes (char *dir)
{
}
}
+#ifdef HAVE_DEVICE_MAPPER
+static int
+grub_util_get_dm_node_linear_info (const char *dev,
+ int *maj, int *min)
+{
+ struct dm_task *dmt;
+ void *next = NULL;
+ uint64_t length, start;
+ char *target, *params;
+ char *ptr;
+ int major, minor;
+
+ dmt = dm_task_create(DM_DEVICE_TABLE);
+ if (!dmt)
+ return 0;
+
+ if (!dm_task_set_name(dmt, dev))
+ return 0;
+ dm_task_no_open_count(dmt);
+ if (!dm_task_run(dmt))
+ return 0;
+ next = dm_get_next_target(dmt, next, &start, &length,
+ &target, ¶ms);
+ if (grub_strcmp (target, "linear") != 0)
+ return 0;
+ major = grub_strtoul (params, &ptr, 10);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ if (*ptr != ':')
+ return 0;
+ ptr++;
+ minor = grub_strtoul (ptr, 0, 10);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ if (maj)
+ *maj = major;
+ if (min)
+ *min = minor;
+ return 1;
+}
+#endif
+
+int
+grub_util_biosdisk_is_floppy (grub_disk_t disk)
+{
+ struct stat st;
+ int fd;
+ const char *dname;
+
+ dname = grub_util_biosdisk_get_osdev (disk);
+
+ if (!dname)
+ return 0;
+
+ fd = open (dname, O_RDONLY);
+ /* Shouldn't happen. */
+ if (fd == -1)
+ return 0;
+
+ /* Shouldn't happen either. */
+ if (fstat (fd, &st) < 0)
+ {
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
+#if defined(__NetBSD__)
+ if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
+ return 1;
+#endif
+
+#if defined(FLOPPY_MAJOR)
+ if (major(st.st_rdev) == FLOPPY_MAJOR)
+#else
+ /* Some kernels (e.g. kFreeBSD) don't have a static major number
+ for floppies, but they still use a "fd[0-9]" pathname. */
+ if (map[disk->id].device[5] == 'f'
+ && map[disk->id].device[6] == 'd'
+ && map[disk->id].device[7] >= '0'
+ && map[disk->id].device[7] <= '9')
+#endif
+ return 1;
+
+ return 0;
+}
+
+static char *
+convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
+{
+#if defined(__linux__)
+ char *path = xmalloc (PATH_MAX);
+ if (! realpath (os_dev, path))
+ return NULL;
+
+ if (strncmp ("/dev/", path, 5) == 0)
+ {
+ char *p = path + 5;
+
+ /* If this is an IDE disk. */
+ if (strncmp ("ide/", p, 4) == 0)
+ {
+ p = strstr (p, "part");
+ if (p)
+ strcpy (p, "disc");
+
+ return path;
+ }
+
+ /* If this is a SCSI disk. */
+ if (strncmp ("scsi/", p, 5) == 0)
+ {
+ p = strstr (p, "part");
+ if (p)
+ strcpy (p, "disc");
+
+ return path;
+ }
+
+ /* If this is a DAC960 disk. */
+ if (strncmp ("rd/c", p, 4) == 0)
+ {
+ /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+
+ /* If this is a Mylex AcceleRAID Array. */
+ if (strncmp ("rs/c", p, 4) == 0)
+ {
+ /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+ /* If this is a CCISS disk. */
+ if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
+ {
+ /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+
+ /* If this is a Compaq Intelligent Drive Array. */
+ if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
+ {
+ /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+
+ /* If this is an I2O disk. */
+ if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
+ {
+ /* /dev/i2o/hd[a-z]([0-9]+)? */
+ p[sizeof ("i2o/hda") - 1] = '\0';
+ return path;
+ }
+
+ /* If this is a MultiMediaCard (MMC). */
+ if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
+ {
+ /* /dev/mmcblk[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ *p = '\0';
+
+ return path;
+ }
+
+ if (strncmp ("md", p, 2) == 0
+ && p[2] >= '0' && p[2] <= '9')
+ {
+ char *ptr = p + 2;
+ while (*ptr >= '0' && *ptr <= '9')
+ ptr++;
+ *ptr = 0;
+ return path;
+ }
+
+ /* If this is an IDE, SCSI or Virtio disk. */
+ if (strncmp ("vdisk", p, 5) == 0
+ && p[5] >= 'a' && p[5] <= 'z')
+ {
+ /* /dev/vdisk[a-z][0-9]* */
+ p[6] = '\0';
+ return path;
+ }
+ if ((strncmp ("hd", p, 2) == 0
+ || strncmp ("vd", p, 2) == 0
+ || strncmp ("sd", p, 2) == 0)
+ && p[2] >= 'a' && p[2] <= 'z')
+ {
+ char *pp = p + 2;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ /* /dev/[hsv]d[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+ /* If this is a Xen virtual block device. */
+ if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
+ {
+ char *pp = p + 3;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ /* /dev/xvd[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+#ifdef HAVE_DEVICE_MAPPER
+ /* If this is a DM-RAID device.
+ Compare os_dev rather than path here, since nodes under
+ /dev/mapper/ are often symlinks. */
+ if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
+ {
+ struct dm_tree *tree;
+ uint32_t maj, min;
+ struct dm_tree_node *node = NULL, *child;
+ void *handle;
+ const char *node_uuid, *mapper_name = NULL, *child_uuid, *child_name;
+
+ tree = dm_tree_create ();
+ if (! tree)
+ {
+ grub_dprintf ("hostdisk", "dm_tree_create failed\n");
+ goto devmapper_out;
+ }
+
+ maj = major (st->st_rdev);
+ min = minor (st->st_rdev);
+ if (! dm_tree_add_dev (tree, maj, min))
+ {
+ grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
+ goto devmapper_out;
+ }
+
+ node = dm_tree_find_node (tree, maj, min);
+ if (! node)
+ {
+ grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
+ goto devmapper_out;
+ }
+ node_uuid = dm_tree_node_get_uuid (node);
+ if (! node_uuid)
+ {
+ grub_dprintf ("hostdisk", "%s has no DM uuid\n", path);
+ node = NULL;
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "LVM-", 4) == 0)
+ {
+ grub_dprintf ("hostdisk", "%s is an LVM\n", path);
+ node = NULL;
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "mpath-", 6) == 0)
+ {
+ /* Multipath partitions have partN-mpath-* UUIDs, and are
+ linear mappings so are handled by
+ grub_util_get_dm_node_linear_info. Multipath disks are not
+ linear mappings and must be handled specially. */
+ grub_dprintf ("hostdisk", "%s is a multipath disk\n", path);
+ mapper_name = dm_tree_node_get_name (node);
+ goto devmapper_out;
+ }
+ if (strncmp (node_uuid, "DMRAID-", 7) != 0)
+ {
+ int major, minor;
+ const char *node_name;
+ grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
+
+ if ((node_name = dm_tree_node_get_name (node))
+ && grub_util_get_dm_node_linear_info (node_name,
+ &major, &minor))
+ {
+ if (tree)
+ dm_tree_free (tree);
+ free (path);
+ char *ret = grub_find_device ("/dev",
+ (major << 8) | minor);
+ return ret;
+ }
+
+ node = NULL;
+ goto devmapper_out;
+ }
+
+ handle = NULL;
+ /* Counter-intuitively, device-mapper refers to the disk-like
+ device containing a DM-RAID partition device as a "child" of
+ the partition device. */
+ child = dm_tree_next_child (&handle, node, 0);
+ if (! child)
+ {
+ grub_dprintf ("hostdisk", "%s has no DM children\n", path);
+ goto devmapper_out;
+ }
+ child_uuid = dm_tree_node_get_uuid (child);
+ if (! child_uuid)
+ {
+ grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path);
+ goto devmapper_out;
+ }
+ else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
+ {
+ grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path);
+ goto devmapper_out;
+ }
+ child_name = dm_tree_node_get_name (child);
+ if (! child_name)
+ {
+ grub_dprintf ("hostdisk", "%s child has no DM name\n", path);
+ goto devmapper_out;
+ }
+ mapper_name = child_name;
+
+devmapper_out:
+ if (! mapper_name && node)
+ {
+ /* This is a DM-RAID disk, not a partition. */
+ mapper_name = dm_tree_node_get_name (node);
+ if (! mapper_name)
+ grub_dprintf ("hostdisk", "%s has no DM name\n", path);
+ }
+ if (tree)
+ dm_tree_free (tree);
+ free (path);
+ if (mapper_name)
+ return xasprintf ("/dev/mapper/%s", mapper_name);
+ else
+ return NULL;
+ }
+#endif /* HAVE_DEVICE_MAPPER */
+ }
+
+ return path;
+
+#elif defined(__GNU__)
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
+ {
+ char *p = strchr (path + 7, 's');
+ if (p)
+ *p = '\0';
+ }
+ return path;
+
+#elif defined(__CYGWIN__)
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
+ path[8] = 0;
+ return path;
+
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ char *out, *out2;
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return xstrdup (os_dev);
+ grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
+
+ out2 = xasprintf ("/dev/%s", out);
+ free (out);
+
+ return out2;
+#elif defined(__APPLE__)
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/", path, 5) == 0)
+ {
+ char *p;
+ for (p = path + 5; *p; ++p)
+ if (grub_isdigit(*p))
+ {
+ p = strpbrk (p, "sp");
+ if (p)
+ *p = '\0';
+ break;
+ }
+ }
+ return path;
+
+#elif defined(__NetBSD__)
+ /* NetBSD uses "/dev/r[a-z]+[0-9][a-z]". */
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/r", path, sizeof("/dev/r") - 1) == 0 &&
+ (path[sizeof("/dev/r") - 1] >= 'a' && path[sizeof("/dev/r") - 1] <= 'z') &&
+ strncmp ("fd", path + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
+ {
+ char *p;
+ for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
+ if (grub_isdigit(*p))
+ {
+ p++;
+ if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
+ {
+ /* path matches the required regular expression and
+ p points to its last character. */
+ int rawpart = -1;
+# ifdef HAVE_GETRAWPARTITION
+ rawpart = getrawpartition();
+# endif /* HAVE_GETRAWPARTITION */
+ if (rawpart >= 0)
+ *p = 'a' + rawpart;
+ }
+ }
+ }
+ return path;
+
+#elif defined (__sun__)
+ char *colon = grub_strrchr (os_dev, ':');
+ if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
+ && colon)
+ {
+ char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
+ grub_memcpy (ret, os_dev, colon - os_dev);
+ grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
+ return ret;
+ }
+ else
+ return xstrdup (os_dev);
+#else
+# warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
+ return xstrdup (os_dev);
+#endif
+}
+
+static const char *
+find_system_device (const char *os_dev, struct stat *st, int convert, int add)
+{
+ unsigned int i;
+ char *os_disk;
+ const char *drive;
+
+ if (convert)
+ os_disk = convert_system_partition_to_system_disk (os_dev, st);
+ else
+ os_disk = xstrdup (os_dev);
+ if (! os_disk)
+ return NULL;
+
+ drive = grub_hostdisk_os_dev_to_grub_drive (os_disk, add);
+ free (os_disk);
+ return drive;
+}
+
+/*
+ * Note: we do not use the new partition naming scheme as dos_part does not
+ * necessarily correspond to an msdos partition.
+ */
+static char *
+make_device_name (const char *drive, int dos_part, int bsd_part)
+{
+ char *ret, *ptr, *end;
+ const char *iptr;
+
+ ret = xmalloc (strlen (drive) * 2
+ + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
+ ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
+ end = (ret + strlen (drive) * 2
+ + sizeof (",XXXXXXXXXXXXXXXXXXXXXXXXXX"
+ ",XXXXXXXXXXXXXXXXXXXXXXXXXX"));
+ ptr = ret;
+ for (iptr = drive; *iptr; iptr++)
+ {
+ if (*iptr == ',')
+ *ptr++ = '\\';
+ *ptr++ = *iptr;
+ }
+ *ptr = 0;
+ if (dos_part >= 0)
+ snprintf (ptr, end - ptr, ",%d", dos_part + 1);
+ ptr += strlen (ptr);
+ if (bsd_part >= 0)
+ snprintf (ptr, end - ptr, ",%d", bsd_part + 1);
+
+ return ret;
+}
+
+#if defined(__sun__)
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ if (grub_memcmp (os_dev, "/devices/", sizeof ("/devices/") - 1) != 0)
+ return 1;
+ if (grub_memcmp (os_dev + strlen (os_dev) - (sizeof (":q,raw") - 1),
+ ":q,raw", (sizeof (":q,raw") - 1)) == 0)
+ return 1;
+ return 0;
+}
+#endif
+
+#if defined(__linux__) || defined(__CYGWIN__)
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ int len = strlen (os_dev);
+
+ if (os_dev[len - 1] < '0' || os_dev[len - 1] > '9')
+ return 1;
+ return 0;
+}
+#endif
+
+#if defined(__NetBSD__)
+/* Try to determine whether a given device name corresponds to a whole disk.
+ This function should give in most cases a definite answer, but it may
+ actually give an approximate one in the following sense: if the return
+ value is 0 then the device name does not correspond to a whole disk. */
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ int len = strlen (os_dev);
+ int rawpart = -1;
+
+# ifdef HAVE_GETRAWPARTITION
+ rawpart = getrawpartition();
+# endif /* HAVE_GETRAWPARTITION */
+ if (rawpart < 0)
+ return 1;
+ return (os_dev[len - 1] == ('a' + rawpart));
+}
+#endif /* defined(__NetBSD__) */
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+static int
+device_is_wholedisk (const char *os_dev)
+{
+ const char *p;
+
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 0;
+
+ for (p = os_dev + sizeof ("/dev/") - 1; *p; ++p)
+ if (grub_isdigit (*p))
+ {
+ if (strchr (p, 's'))
+ return 0;
+ break;
+ }
+
+ return 1;
+}
+#endif /* defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
+
+char *
+grub_util_biosdisk_get_grub_dev (const char *os_dev)
+{
+ struct stat st;
+ const char *drive;
+ char *sys_disk;
+
+ grub_util_info ("Looking for %s", os_dev);
+
+ if (stat (os_dev, &st) < 0)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
+ grub_util_info ("cannot stat `%s'", os_dev);
+ return 0;
+ }
+
+ drive = find_system_device (os_dev, &st, 1, 1);
+ if (!drive)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "no mapping exists for `%s'", os_dev);
+ grub_util_info ("no mapping exists for `%s'", os_dev);
+ return 0;
+ }
+
+ sys_disk = convert_system_partition_to_system_disk (os_dev, &st);
+ if (grub_strcmp (os_dev, sys_disk) == 0)
+ {
+ free (sys_disk);
+ return make_device_name (drive, -1, -1);
+ }
+ free (sys_disk);
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__) || defined (__sun__)
+ if (! S_ISCHR (st.st_mode))
+#else
+ if (! S_ISBLK (st.st_mode))
+#endif
+ return make_device_name (drive, -1, -1);
+
+#if defined(__linux__) || defined(__CYGWIN__) || defined(HAVE_DIOCGDINFO) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__sun__)
+
+ /* Linux counts partitions uniformly, whether a BSD partition or a DOS
+ partition, so mapping them to GRUB devices is not trivial.
+ Here, get the start sector of a partition by HDIO_GETGEO, and
+ compare it with each partition GRUB recognizes.
+
+ Cygwin /dev/sdXN emulation uses Windows partition mapping. It
+ does not count the extended partition and missing primary
+ partitions. Use same method as on Linux here.
+
+ For NetBSD and FreeBSD, proceed as for Linux, except that the start
+ sector is obtained from the disk label. */
+ {
+ char *name, *partname;
+ grub_disk_t disk;
+ grub_disk_addr_t start;
+ auto int find_partition (grub_disk_t dsk,
+ const grub_partition_t partition);
+
+ int find_partition (grub_disk_t dsk __attribute__ ((unused)),
+ const grub_partition_t partition)
+ {
+ grub_disk_addr_t part_start = 0;
+ grub_util_info ("Partition %d starts from %lu",
+ partition->number, partition->start);
+
+ part_start = grub_partition_get_start (partition);
+
+ if (start == part_start)
+ {
+ partname = grub_partition_get_name (partition);
+ return 1;
+ }
+
+ return 0;
+ }
+
+ name = make_device_name (drive, -1, -1);
+
+# if !defined(HAVE_DIOCGDINFO) && !defined(__sun__)
+ if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
+ return name;
+# else /* defined(HAVE_DIOCGDINFO) */
+ /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
+ * different, we know that os_dev cannot be a floppy device. */
+# endif /* !defined(HAVE_DIOCGDINFO) */
+
+ start = grub_hostdisk_find_partition_start (os_dev);
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ free (name);
+ return 0;
+ }
+
+ grub_util_info ("%s starts from %lu", os_dev, start);
+
+ if (start == 0 && device_is_wholedisk (os_dev))
+ return name;
+
+ grub_util_info ("opening the device %s", name);
+ disk = grub_disk_open (name);
+ free (name);
+
+ if (! disk)
+ {
+ /* We already know that the partition exists. Given that we already
+ checked the device map above, we can only get
+ GRUB_ERR_UNKNOWN_DEVICE at this point if the disk does not exist.
+ This can happen on Xen, where disk images in the host can be
+ assigned to devices that have partition-like names in the guest
+ but are really more like disks. */
+ if (grub_errno == GRUB_ERR_UNKNOWN_DEVICE)
+ {
+ grub_util_warn
+ ("disk does not exist, so falling back to partition device %s",
+ os_dev);
+
+ drive = find_system_device (os_dev, &st, 0, 1);
+ if (!drive)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE,
+ "no mapping exists for `%s'", os_dev);
+ return 0;
+ }
+
+ return make_device_name (drive, -1, -1);
+ }
+ else
+ return 0;
+ }
+
+ name = grub_util_get_ldm (disk, start);
+ if (name)
+ return name;
+
+ partname = NULL;
+
+ grub_partition_iterate (disk, find_partition);
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_disk_close (disk);
+ return 0;
+ }
+
+ if (partname == NULL)
+ {
+ grub_disk_close (disk);
+ grub_util_info ("cannot find the partition of `%s'", os_dev);
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot find the partition of `%s'", os_dev);
+ return 0;
+ }
+
+ name = grub_xasprintf ("%s,%s", disk->name, partname);
+ free (partname);
+ grub_disk_close (disk);
+ return name;
+ }
+
+#elif defined(__GNU__)
+ /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
+ {
+ char *p;
+ int dos_part = -1;
+ int bsd_part = -1;
+
+ p = strrchr (os_dev, 's');
+ if (p)
+ {
+ long int n;
+ char *q;
+
+ p++;
+ n = strtol (p, &q, 10);
+ if (p != q && n != GRUB_LONG_MIN && n != GRUB_LONG_MAX)
+ {
+ dos_part = (int) n - 1;
+
+ if (*q >= 'a' && *q <= 'g')
+ bsd_part = *q - 'a';
+ }
+ }
+
+ return make_device_name (drive, dos_part, bsd_part);
+ }
+
+#else
+# warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
+ return make_device_name (drive, -1, -1);
+#endif
+}
+
+int
+grub_util_biosdisk_is_present (const char *os_dev)
+{
+ struct stat st;
+
+ if (stat (os_dev, &st) < 0)
+ return 0;
+
+ return find_system_device (os_dev, &st, 1, 0) != NULL;
+}
+
char *
grub_util_get_grub_dev (const char *os_dev)
{
}
}
+ grub_ldm_fini ();
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
+ grub_ldm_init ();
switch (cmd)
{
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
#include <grub/emu/getroot.h>
#include <grub/term.h>
#include <grub/env.h>
-#include <grub/raid.h>
+#include <grub/diskfilter.h>
#include <grub/i18n.h>
#include <grub/emu/misc.h>
#include <grub/util/ofpath.h>
if (!disk)
return -1;
- if (disk->dev->id != GRUB_DISK_DEVICE_RAID_ID)
+ if (disk->dev->id != GRUB_DISK_DEVICE_DISKFILTER_ID)
return -1;
- return ((struct grub_raid_array *) disk->data)->level;
+ if (disk->name[0] != 'm' || disk->name[1] != 'd')
+ return -1;
+
+ if (!((struct grub_diskfilter_lv *) disk->data)->segments)
+ return -1;
+ return ((struct grub_diskfilter_lv *) disk->data)->segments->type;
}
/* Since OF path names can have "," characters in them, and GRUB
list = tmp;
}
- if (disk->dev->id == GRUB_DISK_DEVICE_LVM_ID)
+ if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
+ && grub_memcmp (disk->name, "lvm/", sizeof ("lvm/") - 1) == 0)
printf ("lvm ");
+ if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID
+ && grub_memcmp (disk->name, "ldm/", sizeof ("ldm/") - 1) == 0)
+ printf ("ldm ");
+
if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
grub_util_cryptodisk_print_abstraction (disk);
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
static void
setup (const char *dir,
const char *boot_file, const char *core_file,
- const char *root, const char *dest, int must_embed, int force,
+ const char *root, const char *dest, int force,
int fs_probe, int allow_floppy)
{
char *boot_path, *core_path, *core_path_dev, *core_path_dev_full;
grub_partition_map_t dest_partmap = NULL;
grub_partition_t container = dest_dev->disk->partition;
int multiple_partmaps = 0;
+ int is_ldm;
grub_err_t err;
grub_disk_addr_t *sectors;
int i;
if (!fs)
grub_errno = GRUB_ERR_NONE;
+ is_ldm = grub_util_is_ldm (dest_dev->disk);
+
#ifdef GRUB_MACHINE_PCBIOS
if (fs_probe)
{
"result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
"by grub-setup (--skip-fs-probe disables this "
"check, use at your own risk)"), dest_dev->disk->name, dest_partmap->name);
+ if (is_ldm && dest_partmap && strcmp (dest_partmap->name, "msdos") != 0
+ && strcmp (dest_partmap->name, "gpt") != 0)
+ grub_util_error (_("%s appears to contain a %s partition map and "
+ "LDM which isn't known to be a safe combination."
+ " Installing GRUB there could "
+ "result in FILESYSTEM DESTRUCTION if valuable data"
+ " is overwritten "
+ "by grub-setup (--skip-fs-probe disables this "
+ "check, use at your own risk)"),
+ dest_dev->disk->name, dest_partmap->name);
+
}
#endif
free (tmp_img);
- if (! dest_partmap && ! fs)
+ if (! dest_partmap && ! fs && !is_ldm)
{
grub_util_warn (_("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea."));
goto unable_to_embed;
}
- if (multiple_partmaps || (dest_partmap && fs))
+ if (multiple_partmaps || (dest_partmap && fs) || (is_ldm && fs))
{
- grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels or both partition label and filesystem. This is not supported yet."));
+ grub_util_warn (_("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet."));
goto unable_to_embed;
}
}
nsec = core_sectors;
- if (dest_partmap)
+ if (is_ldm)
+ err = grub_util_ldm_embed (dest_dev->disk, &nsec,
+ GRUB_EMBED_PCBIOS, §ors);
+ else if (dest_partmap)
err = dest_partmap->embed (dest_dev->disk, &nsec,
GRUB_EMBED_PCBIOS, §ors);
else
unable_to_embed:
- if (must_embed)
- grub_util_error (_("embedding is not possible, but this is required when "
- "the root device is on a RAID array or LVM volume"));
-
#ifdef GRUB_MACHINE_PCBIOS
- if (dest_dev->disk->id != root_dev->disk->id)
+ if (dest_dev->disk->id != root_dev->disk->id
+ || dest_dev->disk->dev->id != root_dev->disk->dev->id)
grub_util_error (_("embedding is not possible, but this is required for "
- "cross-disk install"));
+ "cross-disk, RAID and LVM install"));
+#else
+ if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
+ grub_util_error (_("embedding is not possible, but this is required for "
+ "RAID and LVM install"));
+
#endif
grub_util_warn (_("Embedding is not possible. GRUB can only be installed in this "
{
char *root_dev = NULL;
char *dest_dev = NULL;
- int must_embed = 0;
struct arguments arguments;
set_program_name (argv[0]);
grub_lvm_fini ();
grub_mdraid09_fini ();
grub_mdraid1x_fini ();
- grub_raid_fini ();
- grub_raid_init ();
+ grub_diskfilter_fini ();
+ grub_diskfilter_init ();
grub_mdraid09_init ();
grub_mdraid1x_init ();
grub_lvm_init ();
arguments.dir ? : DEFAULT_DIRECTORY);
}
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- if (grub_util_lvm_isvolume (root_dev))
- must_embed = 1;
-#endif
-
-#ifdef __linux__
- if (root_dev[0] == 'm' && root_dev[1] == 'd'
- && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/'))
- {
- /* FIXME: we can avoid this on RAID1. */
- must_embed = 1;
- }
-
- if (dest_dev[0] == 'm' && dest_dev[1] == 'd'
- && ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/'))
- {
- char **devicelist;
- int i;
-
- if (arguments.device[0] == '/')
- devicelist = grub_util_raid_getmembers (arguments.device, 1);
- else
- {
- char *devname;
- devname = xasprintf ("/dev/%s", dest_dev);
- devicelist = grub_util_raid_getmembers (dest_dev, 1);
- free (devname);
- }
-
- for (i = 0; devicelist[i]; i++)
- {
- setup (arguments.dir ? : DEFAULT_DIRECTORY,
- arguments.boot_file ? : DEFAULT_BOOT_FILE,
- arguments.core_file ? : DEFAULT_CORE_FILE,
- root_dev, grub_util_get_grub_dev (devicelist[i]), 1,
- arguments.force, arguments.fs_probe,
- arguments.allow_floppy);
- }
- }
- else
-#endif
- /* Do the real work. */
- setup (arguments.dir ? : DEFAULT_DIRECTORY,
- arguments.boot_file ? : DEFAULT_BOOT_FILE,
- arguments.core_file ? : DEFAULT_CORE_FILE,
- root_dev, dest_dev, must_embed, arguments.force,
- arguments.fs_probe, arguments.allow_floppy);
+ /* Do the real work. */
+ setup (arguments.dir ? : DEFAULT_DIRECTORY,
+ arguments.boot_file ? : DEFAULT_BOOT_FILE,
+ arguments.core_file ? : DEFAULT_CORE_FILE,
+ root_dev, dest_dev, arguments.force,
+ arguments.fs_probe, arguments.allow_floppy);
/* Free resources. */
grub_fini_all ();