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.
This commit is contained in:
parent
8a7f9b9c50
commit
076e7c0fda
27 changed files with 4249 additions and 3052 deletions
832
util/getroot.c
832
util/getroot.c
|
@ -76,6 +76,71 @@
|
|||
#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)
|
||||
{
|
||||
|
@ -1164,6 +1229,773 @@ grub_util_pull_device (const char *os_dev)
|
|||
}
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue