1 /* hostdisk.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/msdos_partition.h>
23 #include <grub/types.h>
25 #include <grub/util/misc.h>
26 #include <grub/util/hostdisk.h>
27 #include <grub/misc.h>
28 #include <grub/i18n.h>
36 #include <sys/types.h>
43 # include <sys/ioctl.h> /* ioctl */
44 # if !defined(__GLIBC__) || \
45 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
46 /* Maybe libc doesn't have large file support. */
47 # include <linux/unistd.h> /* _llseek */
48 # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
50 # define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
51 # endif /* ! BLKFLSBUF */
52 # include <sys/ioctl.h> /* ioctl */
54 # define HDIO_GETGEO 0x0301 /* get device geometry */
55 /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
60 unsigned char sectors
;
61 unsigned short cylinders
;
64 # endif /* ! HDIO_GETGEO */
66 # define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
67 # endif /* ! BLKGETSIZE64 */
71 # endif /* ! MINORBITS */
72 # define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
75 # define FLOPPY_MAJOR 2
76 # endif /* ! FLOPPY_MAJOR */
79 # endif /* ! LOOP_MAJOR */
80 #endif /* __linux__ */
83 # include <sys/ioctl.h>
84 # include <cygwin/fs.h> /* BLKGETSIZE64 */
85 # include <cygwin/hdreg.h> /* HDIO_GETGEO */
86 # define MAJOR(dev) ((unsigned) ((dev) >> 16))
87 # define FLOPPY_MAJOR 2
90 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
91 # include <sys/disk.h> /* DIOCGMEDIASIZE */
92 # include <sys/param.h>
93 # include <sys/sysctl.h>
96 #if defined(__APPLE__)
97 # include <sys/disk.h>
107 /* Check if we have devfs support. */
111 static int dev_devfsd_exists
= -1;
113 if (dev_devfsd_exists
< 0)
117 dev_devfsd_exists
= stat ("/dev/.devfsd", &st
) == 0;
120 return dev_devfsd_exists
;
122 #endif /* __linux__ */
125 find_grub_drive (const char *name
)
131 for (i
= 0; i
< ARRAY_SIZE (map
); i
++)
132 if (map
[i
].drive
&& ! strcmp (map
[i
].drive
, name
))
144 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
152 grub_util_biosdisk_iterate (int (*hook
) (const char *name
))
156 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
157 if (map
[i
].drive
&& hook (map
[i
].drive
))
164 grub_util_biosdisk_open (const char *name
, grub_disk_t disk
)
169 drive
= find_grub_drive (name
);
171 return grub_error (GRUB_ERR_BAD_DEVICE
,
172 "no mapping exists for `%s'", name
);
174 disk
->has_partitions
= 1;
178 #if defined(__MINGW32__)
182 size
= grub_util_get_disk_size (map
[drive
].device
);
185 grub_util_error ("unaligned device size");
187 disk
->total_sectors
= size
>> 9;
189 grub_util_info ("the size of %s is %llu", name
, disk
->total_sectors
);
191 return GRUB_ERR_NONE
;
193 #elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
194 defined(__FreeBSD_kernel__) || defined(__APPLE__)
196 unsigned long long nr
;
199 fd
= open (map
[drive
].device
, O_RDONLY
);
201 return grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' while attempting to get disk size", map
[drive
].device
);
203 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
204 if (fstat (fd
, &st
) < 0 || ! S_ISCHR (st
.st_mode
))
206 if (fstat (fd
, &st
) < 0 || ! S_ISBLK (st
.st_mode
))
213 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
214 if (ioctl (fd
, DIOCGMEDIASIZE
, &nr
))
215 # elif defined(__APPLE__)
216 if (ioctl (fd
, DKIOCGETBLOCKCOUNT
, &nr
))
218 if (ioctl (fd
, BLKGETSIZE64
, &nr
))
227 #if defined (__APPLE__)
228 disk
->total_sectors
= nr
;
230 disk
->total_sectors
= nr
/ 512;
233 grub_util_error ("unaligned device size");
236 grub_util_info ("the size of %s is %llu", name
, disk
->total_sectors
);
238 return GRUB_ERR_NONE
;
242 /* In GNU/Hurd, stat() will return the right size. */
243 #elif !defined (__GNU__)
244 # warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
246 if (stat (map
[drive
].device
, &st
) < 0)
247 return grub_error (GRUB_ERR_BAD_DEVICE
, "cannot stat `%s'", map
[drive
].device
);
249 disk
->total_sectors
= st
.st_size
>> GRUB_DISK_SECTOR_BITS
;
251 grub_util_info ("the size of %s is %lu", name
, disk
->total_sectors
);
253 return GRUB_ERR_NONE
;
258 linux_find_partition (char *dev
, unsigned long sector
)
260 size_t len
= strlen (dev
);
264 char real_dev
[PATH_MAX
];
266 strcpy(real_dev
, dev
);
268 if (have_devfs () && strcmp (real_dev
+ len
- 5, "/disc") == 0)
270 p
= real_dev
+ len
- 4;
273 else if (real_dev
[len
- 1] >= '0' && real_dev
[len
- 1] <= '9')
284 for (i
= 1; i
< 10000; i
++)
287 struct hd_geometry hdg
;
289 sprintf (p
, format
, i
);
290 fd
= open (real_dev
, O_RDONLY
);
294 if (ioctl (fd
, HDIO_GETGEO
, &hdg
))
302 if (hdg
.start
== sector
)
304 strcpy (dev
, real_dev
);
311 #endif /* __linux__ */
314 open_device (const grub_disk_t disk
, grub_disk_addr_t sector
, int flags
)
319 flags
|= O_LARGEFILE
;
332 /* Linux has a bug that the disk cache for a whole disk is not consistent
333 with the one for a partition of the disk. */
335 int is_partition
= 0;
338 strcpy (dev
, map
[disk
->id
].device
);
339 if (disk
->partition
&& strncmp (map
[disk
->id
].device
, "/dev/", 5) == 0)
340 is_partition
= linux_find_partition (dev
, disk
->partition
->start
);
342 /* Open the partition. */
343 grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev
);
344 fd
= open (dev
, flags
);
347 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s'", dev
);
351 /* Make the buffer cache consistent with the physical disk. */
352 ioctl (fd
, BLKFLSBUF
, 0);
355 sector
-= disk
->partition
->start
;
357 #else /* ! __linux__ */
358 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
359 int sysctl_flags
, sysctl_oldflags
;
360 size_t sysctl_size
= sizeof (sysctl_flags
);
362 if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags
, &sysctl_size
, NULL
, 0))
364 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot get current flags of sysctl kern.geom.debugflags");
367 sysctl_flags
= sysctl_oldflags
| 0x10;
368 if (! (sysctl_oldflags
& 0x10)
369 && sysctlbyname ("kern.geom.debugflags", NULL
, 0, &sysctl_flags
, sysctl_size
))
371 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot set flags of sysctl kern.geom.debugflags");
376 fd
= open (map
[disk
->id
].device
, flags
);
378 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
379 if (! (sysctl_oldflags
& 0x10)
380 && sysctlbyname ("kern.geom.debugflags", NULL
, 0, &sysctl_oldflags
, sysctl_size
))
382 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot set flags back to the old value for sysctl kern.geom.debugflags");
387 #if defined(__APPLE__)
388 /* If we can't have exclusive access, try shared access */
390 fd
= open(map
[disk
->id
].device
, flags
| O_SHLOCK
);
395 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' in open_device()", map
[disk
->id
].device
);
398 #endif /* ! __linux__ */
400 #if defined(__linux__) && (!defined(__GLIBC__) || \
401 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
402 /* Maybe libc doesn't have large file support. */
404 loff_t offset
, result
;
405 static int _llseek (uint filedes
, ulong hi
, ulong lo
,
406 loff_t
*res
, uint wh
);
407 _syscall5 (int, _llseek
, uint
, filedes
, ulong
, hi
, ulong
, lo
,
408 loff_t
*, res
, uint
, wh
);
410 offset
= (loff_t
) sector
<< GRUB_DISK_SECTOR_BITS
;
411 if (_llseek (fd
, offset
>> 32, offset
& 0xffffffff, &result
, SEEK_SET
))
413 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot seek `%s'", map
[disk
->id
].device
);
420 off_t offset
= (off_t
) sector
<< GRUB_DISK_SECTOR_BITS
;
422 if (lseek (fd
, offset
, SEEK_SET
) != offset
)
424 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot seek `%s'", map
[disk
->id
].device
);
434 /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
435 error occurs, otherwise return LEN. */
437 nread (int fd
, char *buf
, size_t len
)
443 ssize_t ret
= read (fd
, buf
, len
);
460 /* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
461 error occurs, otherwise return LEN. */
463 nwrite (int fd
, const char *buf
, size_t len
)
469 ssize_t ret
= write (fd
, buf
, len
);
487 grub_util_biosdisk_read (grub_disk_t disk
, grub_disk_addr_t sector
,
488 grub_size_t size
, char *buf
)
492 fd
= open_device (disk
, sector
, O_RDONLY
);
497 if (sector
== 0 && size
> 1)
499 /* Work around a bug in Linux ez remapping. Linux remaps all
500 sectors that are read together with the MBR in one read. It
501 should only remap the MBR, so we split the read in two
503 if (nread (fd
, buf
, GRUB_DISK_SECTOR_SIZE
) != GRUB_DISK_SECTOR_SIZE
)
505 grub_error (GRUB_ERR_READ_ERROR
, "cannot read `%s'", map
[disk
->id
].device
);
510 buf
+= GRUB_DISK_SECTOR_SIZE
;
513 #endif /* __linux__ */
515 if (nread (fd
, buf
, size
<< GRUB_DISK_SECTOR_BITS
)
516 != (ssize_t
) (size
<< GRUB_DISK_SECTOR_BITS
))
517 grub_error (GRUB_ERR_READ_ERROR
, "cannot read from `%s'", map
[disk
->id
].device
);
524 grub_util_biosdisk_write (grub_disk_t disk
, grub_disk_addr_t sector
,
525 grub_size_t size
, const char *buf
)
529 fd
= open_device (disk
, sector
, O_WRONLY
);
533 if (nwrite (fd
, buf
, size
<< GRUB_DISK_SECTOR_BITS
)
534 != (ssize_t
) (size
<< GRUB_DISK_SECTOR_BITS
))
535 grub_error (GRUB_ERR_WRITE_ERROR
, "cannot write to `%s'", map
[disk
->id
].device
);
541 static struct grub_disk_dev grub_util_biosdisk_dev
=
544 .id
= GRUB_DISK_DEVICE_BIOSDISK_ID
,
545 .iterate
= grub_util_biosdisk_iterate
,
546 .open
= grub_util_biosdisk_open
,
548 .read
= grub_util_biosdisk_read
,
549 .write
= grub_util_biosdisk_write
,
554 read_device_map (const char *dev_map
)
557 char buf
[1024]; /* XXX */
561 auto void show_error (const char *msg
);
562 void show_error (const char *msg
)
564 grub_util_error ("%s:%d: %s", dev_map
, lineno
, msg
);
567 fp
= fopen (dev_map
, "r");
570 grub_util_info (_("Cannot open `%s'"), dev_map
);
574 while (fgets (buf
, sizeof (buf
), fp
))
582 /* Skip leading spaces. */
583 while (*p
&& isspace (*p
))
586 /* If the first character is `#' or NUL, skip this line. */
587 if (*p
== '\0' || *p
== '#')
591 show_error ("No open parenthesis found");
594 /* Find a free slot. */
595 drive
= find_free_slot ();
597 show_error ("Map table size exceeded");
602 show_error ("No close parenthesis found");
604 map
[drive
].drive
= xmalloc (p
- e
+ sizeof ('\0'));
605 strncpy (map
[drive
].drive
, e
, p
- e
+ sizeof ('\0'));
606 map
[drive
].drive
[p
- e
] = '\0';
609 /* Skip leading spaces. */
610 while (*p
&& isspace (*p
))
614 show_error ("No filename found");
616 /* NUL-terminate the filename. */
618 while (*e
&& ! isspace (*e
))
624 if (grub_util_get_disk_size (p
) == -1LL)
626 if (stat (p
, &st
) == -1)
629 free (map
[drive
].drive
);
630 map
[drive
].drive
= NULL
;
631 grub_util_info ("Cannot stat `%s', skipping", p
);
636 /* On Linux, the devfs uses symbolic links horribly, and that
637 confuses the interface very much, so use realpath to expand
639 map
[drive
].device
= xmalloc (PATH_MAX
);
640 if (! realpath (p
, map
[drive
].device
))
641 grub_util_error ("Cannot get the real path of `%s'", p
);
643 map
[drive
].device
= xstrdup (p
);
651 grub_util_biosdisk_init (const char *dev_map
)
653 read_device_map (dev_map
);
654 grub_disk_dev_register (&grub_util_biosdisk_dev
);
658 grub_util_biosdisk_fini (void)
662 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
667 free (map
[i
].device
);
668 map
[i
].drive
= map
[i
].device
= NULL
;
671 grub_disk_dev_unregister (&grub_util_biosdisk_dev
);
675 make_device_name (int drive
, int dos_part
, int bsd_part
)
678 char *dos_part_str
= NULL
;
679 char *bsd_part_str
= NULL
;
682 dos_part_str
= xasprintf (",%d", dos_part
+ 1);
685 bsd_part_str
= xasprintf (",%c", dos_part
+ 'a');
687 ret
= xasprintf ("%s%s%s", map
[drive
].drive
,
689 bsd_part_str
? : "");
701 convert_system_partition_to_system_disk (const char *os_dev
)
703 #if defined(__linux__)
704 char *path
= xmalloc (PATH_MAX
);
705 if (! realpath (os_dev
, path
))
708 if (strncmp ("/dev/", path
, 5) == 0)
712 /* If this is an IDE disk. */
713 if (strncmp ("ide/", p
, 4) == 0)
715 p
= strstr (p
, "part");
722 /* If this is a SCSI disk. */
723 if (strncmp ("scsi/", p
, 5) == 0)
725 p
= strstr (p
, "part");
732 /* If this is a DAC960 disk. */
733 if (strncmp ("rd/c", p
, 4) == 0)
735 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
743 /* If this is a Mylex AcceleRAID Array. */
744 if (strncmp ("rs/c", p
, 4) == 0)
746 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
753 /* If this is a CCISS disk. */
754 if (strncmp ("cciss/c", p
, sizeof ("cciss/c") - 1) == 0)
756 /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
764 /* If this is a Compaq Intelligent Drive Array. */
765 if (strncmp ("ida/c", p
, sizeof ("ida/c") - 1) == 0)
767 /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
775 /* If this is an I2O disk. */
776 if (strncmp ("i2o/hd", p
, sizeof ("i2o/hd") - 1) == 0)
778 /* /dev/i2o/hd[a-z]([0-9]+)? */
779 p
[sizeof ("i2o/hda") - 1] = '\0';
783 /* If this is a MultiMediaCard (MMC). */
784 if (strncmp ("mmcblk", p
, sizeof ("mmcblk") - 1) == 0)
786 /* /dev/mmcblk[0-9]+(p[0-9]+)? */
794 /* If this is an IDE, SCSI or Virtio disk. */
795 if (strncmp ("vdisk", p
, 5) == 0
796 && p
[5] >= 'a' && p
[5] <= 'z')
798 /* /dev/vdisk[a-z][0-9]* */
802 if ((strncmp ("hd", p
, 2) == 0
803 || strncmp ("vd", p
, 2) == 0
804 || strncmp ("sd", p
, 2) == 0)
805 && p
[2] >= 'a' && p
[2] <= 'z')
807 /* /dev/[hsv]d[a-z][0-9]* */
812 /* If this is a Xen virtual block device. */
813 if ((strncmp ("xvd", p
, 3) == 0) && p
[3] >= 'a' && p
[3] <= 'z')
815 /* /dev/xvd[a-z][0-9]* */
823 #elif defined(__GNU__)
824 char *path
= xstrdup (os_dev
);
825 if (strncmp ("/dev/sd", path
, 7) == 0 || strncmp ("/dev/hd", path
, 7) == 0)
827 char *p
= strchr (path
+ 7, 's');
833 #elif defined(__CYGWIN__)
834 char *path
= xstrdup (os_dev
);
835 if (strncmp ("/dev/sd", path
, 7) == 0 && 'a' <= path
[7] && path
[7] <= 'z')
839 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
840 char *path
= xstrdup (os_dev
);
841 if (strncmp ("/dev/", path
, 5) == 0)
844 for (p
= path
+ 5; *p
; ++p
)
845 if (grub_isdigit(*p
))
856 # warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
857 return xstrdup (os_dev
);
861 #if defined(__linux__) || defined(__CYGWIN__)
863 device_is_wholedisk (const char *os_dev
)
865 int len
= strlen (os_dev
);
867 if (os_dev
[len
- 1] < '0' || os_dev
[len
- 1] > '9')
874 find_system_device (const char *os_dev
)
879 os_disk
= convert_system_partition_to_system_disk (os_dev
);
883 for (i
= 0; i
< ARRAY_SIZE (map
); i
++)
886 else if (strcmp (map
[i
].device
, os_disk
) == 0)
892 if (i
== ARRAY_SIZE (map
))
893 grub_util_error (_("device count exceeds limit"));
895 map
[i
].device
= os_disk
;
896 map
[i
].drive
= xstrdup (os_disk
);
902 grub_util_biosdisk_get_grub_dev (const char *os_dev
)
907 if (stat (os_dev
, &st
) < 0)
909 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot stat `%s'", os_dev
);
913 drive
= find_system_device (os_dev
);
916 grub_error (GRUB_ERR_BAD_DEVICE
,
917 "no mapping exists for `%s'", os_dev
);
921 if (grub_strcmp (os_dev
, convert_system_partition_to_system_disk (os_dev
))
923 return make_device_name (drive
, -1, -1);
925 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
926 if (! S_ISCHR (st
.st_mode
))
928 if (! S_ISBLK (st
.st_mode
))
930 return make_device_name (drive
, -1, -1);
932 #if defined(__linux__) || defined(__CYGWIN__)
933 /* Linux counts partitions uniformly, whether a BSD partition or a DOS
934 partition, so mapping them to GRUB devices is not trivial.
935 Here, get the start sector of a partition by HDIO_GETGEO, and
936 compare it with each partition GRUB recognizes.
938 Cygwin /dev/sdXN emulation uses Windows partition mapping. It
939 does not count the extended partition and missing primary
940 partitions. Use same method as on Linux here. */
945 struct hd_geometry hdg
;
948 auto int find_partition (grub_disk_t disk
,
949 const grub_partition_t partition
);
951 int find_partition (grub_disk_t disk
__attribute__ ((unused
)),
952 const grub_partition_t partition
)
954 struct grub_msdos_partition
*pcdata
= NULL
;
956 if (strcmp (partition
->partmap
->name
, "part_msdos") == 0)
957 pcdata
= partition
->data
;
961 if (pcdata
->bsd_part
< 0)
962 grub_util_info ("DOS partition %d starts from %lu",
963 pcdata
->dos_part
, partition
->start
);
965 grub_util_info ("BSD partition %d,%c starts from %lu",
966 pcdata
->dos_part
, pcdata
->bsd_part
+ 'a',
971 grub_util_info ("Partition %d starts from %lu",
972 partition
->index
, partition
->start
);
975 if (hdg
.start
== partition
->start
)
979 dos_part
= pcdata
->dos_part
;
980 bsd_part
= pcdata
->bsd_part
;
984 dos_part
= partition
->index
;
993 name
= make_device_name (drive
, -1, -1);
995 if (MAJOR (st
.st_rdev
) == FLOPPY_MAJOR
)
998 fd
= open (os_dev
, O_RDONLY
);
1001 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' while attempting to get disk geometry", os_dev
);
1006 if (ioctl (fd
, HDIO_GETGEO
, &hdg
))
1008 grub_error (GRUB_ERR_BAD_DEVICE
,
1009 "cannot get geometry of `%s'", os_dev
);
1017 grub_util_info ("%s starts from %lu", os_dev
, hdg
.start
);
1019 if (hdg
.start
== 0 && device_is_wholedisk (os_dev
))
1022 grub_util_info ("opening the device %s", name
);
1023 disk
= grub_disk_open (name
);
1029 grub_partition_iterate (disk
, find_partition
);
1030 if (grub_errno
!= GRUB_ERR_NONE
)
1032 grub_disk_close (disk
);
1038 grub_disk_close (disk
);
1039 grub_error (GRUB_ERR_BAD_DEVICE
,
1040 "cannot find the partition of `%s'", os_dev
);
1044 return make_device_name (drive
, dos_part
, bsd_part
);
1047 #elif defined(__GNU__)
1048 /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
1054 p
= strrchr (os_dev
, 's');
1061 n
= strtol (p
, &q
, 10);
1062 if (p
!= q
&& n
!= GRUB_LONG_MIN
&& n
!= GRUB_LONG_MAX
)
1064 dos_part
= (int) n
- 1;
1066 if (*q
>= 'a' && *q
<= 'g')
1067 bsd_part
= *q
- 'a';
1071 return make_device_name (drive
, dos_part
, bsd_part
);
1074 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
1075 /* FreeBSD uses "/dev/[a-z]+[0-9]+(s[0-9]+[a-z]?)?". */
1080 if (strncmp ("/dev/", os_dev
, 5) == 0)
1086 for (p
= os_dev
+ 5; *p
; ++p
)
1087 if (grub_isdigit(*p
))
1089 p
= strchr (p
, 's');
1093 n
= strtol (p
, &q
, 10);
1094 if (p
!= q
&& n
!= GRUB_LONG_MIN
&& n
!= GRUB_LONG_MAX
)
1096 dos_part
= (int) n
- 1;
1098 if (*q
>= 'a' && *q
<= 'g')
1099 bsd_part
= *q
- 'a';
1106 return make_device_name (drive
, dos_part
, bsd_part
);
1110 # warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
1111 return make_device_name (drive
, -1, -1);