# include <sys/disk.h>
#endif
+#ifdef HAVE_DEVICE_MAPPER
+# include <libdevmapper.h>
+#endif
+
+ #if defined(__NetBSD__)
+ # include <sys/ioctl.h>
+ # include <sys/disklabel.h> /* struct disklabel */
+ # ifdef HAVE_GETRAWPARTITION
+ # include <util.h> /* getrawpartition */
+ # endif /* HAVE_GETRAWPARTITION */
+ # include <sys/fdio.h>
+ # ifndef RAW_FLOPPY_MAJOR
+ # define RAW_FLOPPY_MAJOR 9
+ # endif /* ! RAW_FLOPPY_MAJOR */
+ #endif /* defined(__NetBSD__) */
+
struct
{
char *drive;
return GRUB_ERR_NONE;
}
- #if defined(__linux__) || defined(__CYGWIN__)
+#ifdef HAVE_DEVICE_MAPPER
+static int
+device_is_mapped (const char *dev)
+{
+ struct stat st;
+
+ if (stat (dev, &st) < 0)
+ return 0;
+
+ return dm_is_dm_major (major (st.st_rdev));
+}
+#endif /* HAVE_DEVICE_MAPPER */
+
- #ifdef HAVE_DEVICE_MAPPER
++#if defined(__linux__) || defined(__CYGWIN__) || defined(__NetBSD__)
+static grub_disk_addr_t
+find_partition_start (const char *dev)
+{
+ int fd;
++# if !defined(__NetBSD__)
+ struct hd_geometry hdg;
++# else /* defined(__NetBSD__) */
++ struct disklabel label;
++ int index;
++# endif /* !defined(__NetBSD__) */
+
- dev, partition_start);
++# ifdef HAVE_DEVICE_MAPPER
+ if (device_is_mapped (dev)) {
+ struct dm_task *task = NULL;
+ grub_uint64_t start, length;
+ char *target_type, *params, *space;
+ grub_disk_addr_t partition_start;
+
+ /* If any device-mapper operation fails, we fall back silently to
+ HDIO_GETGEO. */
+ task = dm_task_create (DM_DEVICE_TABLE);
+ if (! task)
+ {
+ grub_dprintf ("hostdisk", "dm_task_create failed\n");
+ goto devmapper_fail;
+ }
+
+ if (! dm_task_set_name (task, dev))
+ {
+ grub_dprintf ("hostdisk", "dm_task_set_name failed\n");
+ goto devmapper_fail;
+ }
+
+ if (! dm_task_run (task))
+ {
+ grub_dprintf ("hostdisk", "dm_task_run failed\n");
+ goto devmapper_fail;
+ }
+
+ dm_get_next_target (task, NULL, &start, &length, &target_type, ¶ms);
+ if (! target_type)
+ {
+ grub_dprintf ("hostdisk", "no dm target\n");
+ goto devmapper_fail;
+ }
+ if (strcmp (target_type, "linear") != 0)
+ {
+ grub_dprintf ("hostdisk", "ignoring dm target %s (not linear)\n",
+ target_type);
+ goto devmapper_fail;
+ }
+ if (! params)
+ {
+ grub_dprintf ("hostdisk", "no dm params\n");
+ goto devmapper_fail;
+ }
+
+ /* The params string for a linear target looks like this:
+ DEVICE-NAME START-SECTOR
+ Parse this out. */
+ space = strchr (params, ' ');
+ if (! space)
+ goto devmapper_fail;
+ errno = 0;
+ partition_start = strtoull (space + 1, NULL, 10);
+ if (errno == 0)
+ {
+ grub_dprintf ("hostdisk", "dm %s starts at %llu\n",
- #endif /* HAVE_DEVICE_MAPPER */
++ dev, (unsigned long long) partition_start);
+ dm_task_destroy (task);
+ return partition_start;
+ }
+
+devmapper_fail:
+ if (task)
+ dm_task_destroy (task);
+ }
- "cannot get geometry of `%s'", dev);
++# endif /* HAVE_DEVICE_MAPPER */
+
+ fd = open (dev, O_RDONLY);
+ if (fd == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", dev);
+ return 0;
+ }
+
++# if !defined(__NetBSD__)
+ if (ioctl (fd, HDIO_GETGEO, &hdg))
++# else /* defined(__NetBSD__) */
++ configure_device_driver (fd);
++ if (ioctl (fd, DIOCGDINFO, &label) == -1)
++# endif /* !defined(__NetBSD__) */
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
++ "cannot get disk geometry of `%s'", dev);
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
++# if !defined(__NetBSD__)
+ return hdg.start;
++# else /* defined(__NetBSD__) */
++ /* Since dev and convert_system_partition_to_system_disk (dev) are
++ * different, we know that dev is of the form /dev/r[wsc]d[0-9]+[a-z]
++ * and in particular it cannot be a floppy device. */
++ index = dev[strlen(dev) - 1] - 'a';
++
++ if (index >= label.d_npartitions)
++ {
++ grub_error (GRUB_ERR_BAD_DEVICE,
++ "no disk label entry for `%s'", dev);
++ return 0;
++ }
++ return (grub_disk_addr_t) label.d_partitions[index].p_offset;
++# endif /* !defined(__NetBSD__) */
+}
+#endif /* __linux__ || __CYGWIN__ */
+
#ifdef __linux__
+ /* Cache of partition start sectors for each disk. */
+ struct linux_partition_cache
+ {
+ struct linux_partition_cache *next;
+ char *dev;
+ unsigned long start;
+ int partno;
+ };
+
+ struct linux_partition_cache *linux_partition_cache_list;
+
static int
linux_find_partition (char *dev, unsigned long sector)
{
fd = open (real_dev, O_RDONLY);
if (fd == -1)
return 0;
-
- if (ioctl (fd, HDIO_GETGEO, &hdg))
- {
- close (fd);
- return 0;
- }
-
close (fd);
- if (hdg.start == sector)
+ start = find_partition_start (real_dev);
+ /* We don't care about errors here. */
+ grub_errno = GRUB_ERR_NONE;
+
+ if (start == sector)
{
- new_cache_item->start = hdg.start;
+ struct linux_partition_cache *new_cache_item;
+
+ new_cache_item = xmalloc (sizeof *new_cache_item);
+ new_cache_item->dev = xstrdup (dev);
++ new_cache_item->start = start;
+ new_cache_item->partno = i;
+ grub_list_push (GRUB_AS_LIST_P (&linux_partition_cache_list),
+ GRUB_AS_LIST (new_cache_item));
+
strcpy (dev, real_dev);
return 1;
}
}
#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__) */
+
static int
-find_system_device (const char *os_dev)
+find_system_device (const char *os_dev, struct stat *st)
{
unsigned int i;
char *os_disk;
return 0;
}
- drive = find_system_device (os_dev);
+ drive = find_system_device (os_dev, &st);
if (drive < 0)
{
- grub_error (GRUB_ERR_BAD_DEVICE,
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE,
"no mapping exists for `%s'", os_dev);
return 0;
}
- if (grub_strcmp (os_dev, convert_system_partition_to_system_disk (os_dev))
- == 0)
+ if (grub_strcmp (os_dev,
+ convert_system_partition_to_system_disk (os_dev, &st)) == 0)
return make_device_name (drive, -1, -1);
- #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
+ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__) || defined(__NetBSD__)
if (! S_ISCHR (st.st_mode))
#else
if (! S_ISBLK (st.st_mode))
{
char *name;
grub_disk_t disk;
- int fd;
-# if !defined(__NetBSD__)
- struct hd_geometry hdg;
- typeof (hdg.start) p_offset;
-# else /* defined(__NetBSD__) */
- struct disklabel label;
- int index;
- u_int32_t p_offset;
-# endif /* !defined(__NetBSD__) */
+ grub_disk_addr_t start;
int dos_part = -1;
int bsd_part = -1;
- auto int find_partition (grub_disk_t disk,
+ auto int find_partition (grub_disk_t dsk,
const grub_partition_t partition);
- int find_partition (grub_disk_t disk __attribute__ ((unused)),
+ int find_partition (grub_disk_t dsk __attribute__ ((unused)),
const grub_partition_t partition)
{
- struct grub_msdos_partition *pcdata = NULL;
-
- if (strcmp (partition->partmap->name, "part_msdos") == 0)
- pcdata = partition->data;
+ grub_disk_addr_t part_start = 0;
+ grub_util_info ("Partition %d starts from %lu",
+ partition->number, partition->start);
- if (pcdata)
- {
- if (pcdata->bsd_part < 0)
- grub_util_info ("DOS partition %d starts from %lu",
- pcdata->dos_part, partition->start);
- else
- grub_util_info ("BSD partition %d,%c starts from %lu",
- pcdata->dos_part, pcdata->bsd_part + 'a',
- partition->start);
- }
- else
- {
- grub_util_info ("Partition %d starts from %lu",
- partition->index, partition->start);
- }
+ part_start = grub_partition_get_start (partition);
- if (start == partition->start)
- if (p_offset == part_start)
++ if (start == part_start)
{
- if (pcdata)
+ if (partition->parent)
{
- dos_part = pcdata->dos_part;
- bsd_part = pcdata->bsd_part;
+ dos_part = partition->parent->number;
+ bsd_part = partition->number;
}
else
{
name = make_device_name (drive, -1, -1);
+ # if !defined(__NetBSD__)
if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
return name;
+ # else /* defined(__NetBSD__) */
+ /* Since os_dev and convert_system_partition_to_system_disk (os_dev) are
+ * different, we know that os_dev is of the form /dev/r[wsc]d[0-9]+[a-z]
+ * and in particular it cannot be a floppy device. */
+ index = os_dev[strlen(os_dev) - 1] - 'a';
+ # endif /* !defined(__NetBSD__) */
- fd = open (os_dev, O_RDONLY);
- if (fd == -1)
- {
- grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", os_dev);
- free (name);
- return 0;
- }
-
-# if !defined(__NetBSD__)
- if (ioctl (fd, HDIO_GETGEO, &hdg))
-# else /* defined(__NetBSD__) */
- configure_device_driver (fd);
- if (ioctl (fd, DIOCGDINFO, &label) == -1)
-# endif /* !defined(__NetBSD__) */
- {
- grub_error (GRUB_ERR_BAD_DEVICE,
- "cannot get disk geometry of `%s'", os_dev);
- close (fd);
- free (name);
- return 0;
- }
-
- close (fd);
-
-# if !defined(__NetBSD__)
- p_offset = hdg.start;
-# else /* defined(__NetBSD__) */
- if (index >= label.d_npartitions)
+ start = find_partition_start (os_dev);
+ if (grub_errno != GRUB_ERR_NONE)
{
- grub_error (GRUB_ERR_BAD_DEVICE,
- "no disk label entry for `%s'", os_dev);
free (name);
return 0;
}