1 /* biosdisk.c - emulate biosdisk */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/disk.h>
21 #include <grub/partition.h>
22 #include <grub/pc_partition.h>
23 #include <grub/types.h>
25 #include <grub/util/misc.h>
26 #include <grub/util/hostdisk.h>
27 #include <grub/misc.h>
35 #include <sys/types.h>
42 # include <sys/ioctl.h> /* ioctl */
43 # if !defined(__GLIBC__) || \
44 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
45 /* Maybe libc doesn't have large file support. */
46 # include <linux/unistd.h> /* _llseek */
47 # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
49 # define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
50 # endif /* ! BLKFLSBUF */
51 # include <sys/ioctl.h> /* ioctl */
53 # define HDIO_GETGEO 0x0301 /* get device geometry */
54 /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
59 unsigned char sectors
;
60 unsigned short cylinders
;
63 # endif /* ! HDIO_GETGEO */
65 # define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
66 # endif /* ! BLKGETSIZE64 */
70 # endif /* ! MINORBITS */
71 # define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
74 # define FLOPPY_MAJOR 2
75 # endif /* ! FLOPPY_MAJOR */
78 # endif /* ! LOOP_MAJOR */
79 #endif /* __linux__ */
82 # include <sys/ioctl.h>
83 # include <cygwin/fs.h> /* BLKGETSIZE64 */
84 # include <cygwin/hdreg.h> /* HDIO_GETGEO */
85 # define MAJOR(dev) ((unsigned) ((dev) >> 16))
86 # define FLOPPY_MAJOR 2
89 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
90 # include <sys/disk.h> /* DIOCGMEDIASIZE */
91 # include <sys/param.h>
92 # include <sys/sysctl.h>
102 /* Check if we have devfs support. */
106 static int dev_devfsd_exists
= -1;
108 if (dev_devfsd_exists
< 0)
112 dev_devfsd_exists
= stat ("/dev/.devfsd", &st
) == 0;
115 return dev_devfsd_exists
;
117 #endif /* __linux__ */
120 find_grub_drive (const char *name
)
126 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
127 if (map
[i
].drive
&& ! strcmp (map
[i
].drive
, name
))
139 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
147 grub_util_biosdisk_iterate (int (*hook
) (const char *name
))
151 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
152 if (map
[i
].drive
&& hook (map
[i
].drive
))
159 grub_util_biosdisk_open (const char *name
, grub_disk_t disk
)
164 drive
= find_grub_drive (name
);
166 return grub_error (GRUB_ERR_BAD_DEVICE
,
167 "no mapping exists for `%s'", name
);
169 disk
->has_partitions
= 1;
173 #if defined(__MINGW32__)
177 size
= grub_util_get_disk_size (map
[drive
].device
);
180 grub_util_error ("unaligned device size");
182 disk
->total_sectors
= size
>> 9;
184 grub_util_info ("the size of %s is %llu", name
, disk
->total_sectors
);
186 return GRUB_ERR_NONE
;
188 #elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
190 unsigned long long nr
;
193 fd
= open (map
[drive
].device
, O_RDONLY
);
195 return grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' while attempting to get disk size", map
[drive
].device
);
197 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
198 if (fstat (fd
, &st
) < 0 || ! S_ISCHR (st
.st_mode
))
200 if (fstat (fd
, &st
) < 0 || ! S_ISBLK (st
.st_mode
))
207 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
208 if (ioctl (fd
, DIOCGMEDIASIZE
, &nr
))
210 if (ioctl (fd
, BLKGETSIZE64
, &nr
))
218 disk
->total_sectors
= nr
/ 512;
221 grub_util_error ("unaligned device size");
223 grub_util_info ("the size of %s is %llu", name
, disk
->total_sectors
);
225 return GRUB_ERR_NONE
;
229 /* In GNU/Hurd, stat() will return the right size. */
230 #elif !defined (__GNU__)
231 # warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
233 if (stat (map
[drive
].device
, &st
) < 0)
234 return grub_error (GRUB_ERR_BAD_DEVICE
, "cannot stat `%s'", map
[drive
].device
);
236 disk
->total_sectors
= st
.st_size
>> GRUB_DISK_SECTOR_BITS
;
238 grub_util_info ("the size of %s is %lu", name
, disk
->total_sectors
);
240 return GRUB_ERR_NONE
;
245 linux_find_partition (char *dev
, unsigned long sector
)
247 size_t len
= strlen (dev
);
251 char real_dev
[PATH_MAX
];
253 strcpy(real_dev
, dev
);
255 if (have_devfs () && strcmp (real_dev
+ len
- 5, "/disc") == 0)
257 p
= real_dev
+ len
- 4;
260 else if (real_dev
[len
- 1] >= '0' && real_dev
[len
- 1] <= '9')
271 for (i
= 1; i
< 10000; i
++)
274 struct hd_geometry hdg
;
276 sprintf (p
, format
, i
);
277 fd
= open (real_dev
, O_RDONLY
);
281 if (ioctl (fd
, HDIO_GETGEO
, &hdg
))
289 if (hdg
.start
== sector
)
291 strcpy (dev
, real_dev
);
298 #endif /* __linux__ */
301 open_device (const grub_disk_t disk
, grub_disk_addr_t sector
, int flags
)
306 flags
|= O_LARGEFILE
;
319 /* Linux has a bug that the disk cache for a whole disk is not consistent
320 with the one for a partition of the disk. */
322 int is_partition
= 0;
325 strcpy (dev
, map
[disk
->id
].device
);
326 if (disk
->partition
&& strncmp (map
[disk
->id
].device
, "/dev/", 5) == 0)
327 is_partition
= linux_find_partition (dev
, disk
->partition
->start
);
329 /* Open the partition. */
330 grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev
);
331 fd
= open (dev
, flags
);
334 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s'", dev
);
338 /* Make the buffer cache consistent with the physical disk. */
339 ioctl (fd
, BLKFLSBUF
, 0);
342 sector
-= disk
->partition
->start
;
344 #else /* ! __linux__ */
345 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
346 int sysctl_flags
, sysctl_oldflags
;
347 const size_t sysctl_size
= sizeof (sysctl_flags
);
349 if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags
, &sysctl_size
, NULL
, 0))
351 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot get current flags of sysctl kern.geom.debugflags");
354 sysctl_flags
= sysctl_oldflags
| 0x10;
355 if (! (sysctl_oldflags
& 0x10)
356 && sysctlbyname ("kern.geom.debugflags", NULL
, 0, &sysctl_flags
, sysctl_size
))
358 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot set flags of sysctl kern.geom.debugflags");
363 fd
= open (map
[disk
->id
].device
, flags
);
365 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
366 if (! (sysctl_oldflags
& 0x10)
367 && sysctlbyname ("kern.geom.debugflags", NULL
, 0, &sysctl_oldflags
, sysctl_size
))
369 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot set flags back to the old value for sysctl kern.geom.debugflags");
376 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' in open_device()", map
[disk
->id
].device
);
379 #endif /* ! __linux__ */
381 #if defined(__linux__) && (!defined(__GLIBC__) || \
382 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
383 /* Maybe libc doesn't have large file support. */
385 loff_t offset
, result
;
386 static int _llseek (uint filedes
, ulong hi
, ulong lo
,
387 loff_t
*res
, uint wh
);
388 _syscall5 (int, _llseek
, uint
, filedes
, ulong
, hi
, ulong
, lo
,
389 loff_t
*, res
, uint
, wh
);
391 offset
= (loff_t
) sector
<< GRUB_DISK_SECTOR_BITS
;
392 if (_llseek (fd
, offset
>> 32, offset
& 0xffffffff, &result
, SEEK_SET
))
394 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot seek `%s'", map
[disk
->id
].device
);
401 off_t offset
= (off_t
) sector
<< GRUB_DISK_SECTOR_BITS
;
403 if (lseek (fd
, offset
, SEEK_SET
) != offset
)
405 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot seek `%s'", map
[disk
->id
].device
);
415 /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
416 error occurs, otherwise return LEN. */
418 nread (int fd
, char *buf
, size_t len
)
424 ssize_t ret
= read (fd
, buf
, len
);
441 /* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
442 error occurs, otherwise return LEN. */
444 nwrite (int fd
, const char *buf
, size_t len
)
450 ssize_t ret
= write (fd
, buf
, len
);
468 grub_util_biosdisk_read (grub_disk_t disk
, grub_disk_addr_t sector
,
469 grub_size_t size
, char *buf
)
473 fd
= open_device (disk
, sector
, O_RDONLY
);
478 if (sector
== 0 && size
> 1)
480 /* Work around a bug in Linux ez remapping. Linux remaps all
481 sectors that are read together with the MBR in one read. It
482 should only remap the MBR, so we split the read in two
484 if (nread (fd
, buf
, GRUB_DISK_SECTOR_SIZE
) != GRUB_DISK_SECTOR_SIZE
)
486 grub_error (GRUB_ERR_READ_ERROR
, "cannot read `%s'", map
[disk
->id
].device
);
491 buf
+= GRUB_DISK_SECTOR_SIZE
;
494 #endif /* __linux__ */
496 if (nread (fd
, buf
, size
<< GRUB_DISK_SECTOR_BITS
)
497 != (ssize_t
) (size
<< GRUB_DISK_SECTOR_BITS
))
498 grub_error (GRUB_ERR_READ_ERROR
, "cannot read from `%s'", map
[disk
->id
].device
);
505 grub_util_biosdisk_write (grub_disk_t disk
, grub_disk_addr_t sector
,
506 grub_size_t size
, const char *buf
)
510 fd
= open_device (disk
, sector
, O_WRONLY
);
514 if (nwrite (fd
, buf
, size
<< GRUB_DISK_SECTOR_BITS
)
515 != (ssize_t
) (size
<< GRUB_DISK_SECTOR_BITS
))
516 grub_error (GRUB_ERR_WRITE_ERROR
, "cannot write to `%s'", map
[disk
->id
].device
);
522 static struct grub_disk_dev grub_util_biosdisk_dev
=
525 .id
= GRUB_DISK_DEVICE_BIOSDISK_ID
,
526 .iterate
= grub_util_biosdisk_iterate
,
527 .open
= grub_util_biosdisk_open
,
529 .read
= grub_util_biosdisk_read
,
530 .write
= grub_util_biosdisk_write
,
535 read_device_map (const char *dev_map
)
538 char buf
[1024]; /* XXX */
542 auto void show_error (const char *msg
);
543 void show_error (const char *msg
)
545 grub_util_error ("%s:%d: %s", dev_map
, lineno
, msg
);
548 fp
= fopen (dev_map
, "r");
550 grub_util_error ("Cannot open `%s'", dev_map
);
552 while (fgets (buf
, sizeof (buf
), fp
))
560 /* Skip leading spaces. */
561 while (*p
&& isspace (*p
))
564 /* If the first character is `#' or NUL, skip this line. */
565 if (*p
== '\0' || *p
== '#')
569 show_error ("No open parenthesis found");
572 /* Find a free slot. */
573 drive
= find_free_slot ();
575 show_error ("Map table size exceeded");
580 show_error ("No close parenthesis found");
582 map
[drive
].drive
= xmalloc (p
- e
+ sizeof ('\0'));
583 strncpy (map
[drive
].drive
, e
, p
- e
+ sizeof ('\0'));
584 map
[drive
].drive
[p
- e
] = '\0';
587 /* Skip leading spaces. */
588 while (*p
&& isspace (*p
))
592 show_error ("No filename found");
594 /* NUL-terminate the filename. */
596 while (*e
&& ! isspace (*e
))
602 if (grub_util_get_disk_size (p
) == -1LL)
604 if (stat (p
, &st
) == -1)
607 free (map
[drive
].drive
);
608 map
[drive
].drive
= NULL
;
609 grub_util_info ("Cannot stat `%s', skipping", p
);
614 /* On Linux, the devfs uses symbolic links horribly, and that
615 confuses the interface very much, so use realpath to expand
617 map
[drive
].device
= xmalloc (PATH_MAX
);
618 if (! realpath (p
, map
[drive
].device
))
619 grub_util_error ("Cannot get the real path of `%s'", p
);
621 map
[drive
].device
= xstrdup (p
);
629 grub_util_biosdisk_init (const char *dev_map
)
631 read_device_map (dev_map
);
632 grub_disk_dev_register (&grub_util_biosdisk_dev
);
636 grub_util_biosdisk_fini (void)
640 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
645 free (map
[i
].device
);
646 map
[i
].drive
= map
[i
].device
= NULL
;
649 grub_disk_dev_unregister (&grub_util_biosdisk_dev
);
653 make_device_name (int drive
, int dos_part
, int bsd_part
)
655 int len
= strlen(map
[drive
].drive
);
660 /* Add in char length of dos_part+1 */
661 int tmp
= dos_part
+ 1;
663 while ((tmp
/= 10) != 0)
669 /* Length to alloc is: char length of map[drive].drive, plus
670 * char length of (dos_part+1) or of bsd_part, plus
671 * 2 for the comma and a null/end of string (\0)
673 p
= xmalloc (len
+ 2);
674 sprintf (p
, "%s", map
[drive
].drive
);
677 sprintf (p
+ strlen (p
), ",%d", dos_part
+ 1);
680 sprintf (p
+ strlen (p
), ",%c", bsd_part
+ 'a');
686 convert_system_partition_to_system_disk (const char *os_dev
)
688 #if defined(__linux__)
689 char *path
= xmalloc (PATH_MAX
);
690 if (! realpath (os_dev
, path
))
693 if (strncmp ("/dev/", path
, 5) == 0)
697 /* If this is an IDE disk. */
698 if (strncmp ("ide/", p
, 4) == 0)
700 p
= strstr (p
, "part");
707 /* If this is a SCSI disk. */
708 if (strncmp ("scsi/", p
, 5) == 0)
710 p
= strstr (p
, "part");
717 /* If this is a DAC960 disk. */
718 if (strncmp ("rd/c", p
, 4) == 0)
720 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
728 /* If this is a CCISS disk. */
729 if (strncmp ("cciss/c", p
, sizeof ("cciss/c") - 1) == 0)
731 /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
739 /* If this is a Compaq Intelligent Drive Array. */
740 if (strncmp ("ida/c", p
, sizeof ("ida/c") - 1) == 0)
742 /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
750 /* If this is an I2O disk. */
751 if (strncmp ("i2o/hd", p
, sizeof ("i2o/hd") - 1) == 0)
753 /* /dev/i2o/hd[a-z]([0-9]+)? */
754 p
[sizeof ("i2o/hda") - 1] = '\0';
758 /* If this is a MultiMediaCard (MMC). */
759 if (strncmp ("mmcblk", p
, sizeof ("mmcblk") - 1) == 0)
761 /* /dev/mmcblk[0-9]+(p[0-9]+)? */
769 /* If this is an IDE, SCSI or Virtio disk. */
770 if (strncmp ("vdisk", p
, 5) == 0
771 && p
[5] >= 'a' && p
[5] <= 'z')
773 /* /dev/vdisk[a-z][0-9]* */
777 if ((strncmp ("hd", p
, 2) == 0
778 || strncmp ("vd", p
, 2) == 0
779 || strncmp ("sd", p
, 2) == 0)
780 && p
[2] >= 'a' && p
[2] <= 'z')
782 /* /dev/[hsv]d[a-z][0-9]* */
787 /* If this is a Xen virtual block device. */
788 if ((strncmp ("xvd", p
, 3) == 0) && p
[3] >= 'a' && p
[3] <= 'z')
790 /* /dev/xvd[a-z][0-9]* */
798 #elif defined(__GNU__)
799 char *path
= xstrdup (os_dev
);
800 if (strncmp ("/dev/sd", path
, 7) == 0 || strncmp ("/dev/hd", path
, 7) == 0)
802 char *p
= strchr (path
+ 7, 's');
808 #elif defined(__CYGWIN__)
809 char *path
= xstrdup (os_dev
);
810 if (strncmp ("/dev/sd", path
, 7) == 0 && 'a' <= path
[7] && path
[7] <= 'z')
814 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
815 char *path
= xstrdup (os_dev
);
816 if (strncmp ("/dev/", path
, 5) == 0)
819 for (p
= path
+ 5; *p
; ++p
)
820 if (grub_isdigit(*p
))
831 # warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
832 return xstrdup (os_dev
);
837 device_is_wholedisk (const char *os_dev
)
839 int len
= strlen (os_dev
);
841 if (os_dev
[len
- 1] < '0' || os_dev
[len
- 1] > '9')
847 find_system_device (const char *os_dev
)
852 os_disk
= convert_system_partition_to_system_disk (os_dev
);
856 for (i
= 0; i
< (int) (sizeof (map
) / sizeof (map
[0])); i
++)
857 if (map
[i
].device
&& strcmp (map
[i
].device
, os_disk
) == 0)
868 grub_util_biosdisk_get_grub_dev (const char *os_dev
)
873 if (stat (os_dev
, &st
) < 0)
875 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot stat `%s'", os_dev
);
879 drive
= find_system_device (os_dev
);
882 grub_error (GRUB_ERR_BAD_DEVICE
,
883 "no mapping exists for `%s'", os_dev
);
887 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
888 if (! S_ISCHR (st
.st_mode
))
890 if (! S_ISBLK (st
.st_mode
))
892 return make_device_name (drive
, -1, -1);
894 #if defined(__linux__) || defined(__CYGWIN__)
895 /* Linux counts partitions uniformly, whether a BSD partition or a DOS
896 partition, so mapping them to GRUB devices is not trivial.
897 Here, get the start sector of a partition by HDIO_GETGEO, and
898 compare it with each partition GRUB recognizes.
900 Cygwin /dev/sdXN emulation uses Windows partition mapping. It
901 does not count the extended partition and missing primary
902 partitions. Use same method as on Linux here. */
907 struct hd_geometry hdg
;
910 auto int find_partition (grub_disk_t disk
,
911 const grub_partition_t partition
);
913 int find_partition (grub_disk_t disk
__attribute__ ((unused
)),
914 const grub_partition_t partition
)
916 struct grub_pc_partition
*pcdata
= NULL
;
918 if (strcmp (partition
->partmap
->name
, "pc_partition_map") == 0)
919 pcdata
= partition
->data
;
923 if (pcdata
->bsd_part
< 0)
924 grub_util_info ("DOS partition %d starts from %lu",
925 pcdata
->dos_part
, partition
->start
);
927 grub_util_info ("BSD partition %d,%c starts from %lu",
928 pcdata
->dos_part
, pcdata
->bsd_part
+ 'a',
933 grub_util_info ("Partition %d starts from %lu",
934 partition
->index
, partition
->start
);
937 if (hdg
.start
== partition
->start
)
941 dos_part
= pcdata
->dos_part
;
942 bsd_part
= pcdata
->bsd_part
;
946 dos_part
= partition
->index
;
955 name
= make_device_name (drive
, -1, -1);
957 if (MAJOR (st
.st_rdev
) == FLOPPY_MAJOR
)
960 fd
= open (os_dev
, O_RDONLY
);
963 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' while attempting to get disk geometry", os_dev
);
968 if (ioctl (fd
, HDIO_GETGEO
, &hdg
))
970 grub_error (GRUB_ERR_BAD_DEVICE
,
971 "cannot get geometry of `%s'", os_dev
);
979 grub_util_info ("%s starts from %lu", os_dev
, hdg
.start
);
981 if (hdg
.start
== 0 && device_is_wholedisk (os_dev
))
984 grub_util_info ("opening the device %s", name
);
985 disk
= grub_disk_open (name
);
991 grub_partition_iterate (disk
, find_partition
);
992 if (grub_errno
!= GRUB_ERR_NONE
)
994 grub_disk_close (disk
);
1000 grub_disk_close (disk
);
1001 grub_error (GRUB_ERR_BAD_DEVICE
,
1002 "cannot find the partition of `%s'", os_dev
);
1006 return make_device_name (drive
, dos_part
, bsd_part
);
1009 #elif defined(__GNU__)
1010 /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
1016 p
= strrchr (os_dev
, 's');
1023 n
= strtol (p
, &q
, 10);
1024 if (p
!= q
&& n
!= GRUB_LONG_MIN
&& n
!= GRUB_LONG_MAX
)
1028 if (*q
>= 'a' && *q
<= 'g')
1029 bsd_part
= *q
- 'a';
1033 return make_device_name (drive
, dos_part
, bsd_part
);
1036 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
1037 /* FreeBSD uses "/dev/[a-z]+[0-9]+(s[0-9]+[a-z]?)?". */
1042 if (strncmp ("/dev/", os_dev
, 5) == 0)
1047 for (p
= os_dev
+ 5; *p
; ++p
)
1048 if (grub_isdigit(*p
))
1050 p
= strchr (p
, 's');
1054 n
= strtol (p
, &q
, 10);
1055 if (p
!= q
&& n
!= GRUB_LONG_MIN
&& n
!= GRUB_LONG_MAX
)
1057 dos_part
= (int) n
- 1;
1059 if (*q
>= 'a' && *q
<= 'g')
1060 bsd_part
= *q
- 'a';
1067 return make_device_name (drive
, dos_part
, bsd_part
);
1071 # warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
1072 return make_device_name (drive
, -1, -1);