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>
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>
95 #if defined(__APPLE__)
96 # include <sys/disk.h>
106 /* Check if we have devfs support. */
110 static int dev_devfsd_exists
= -1;
112 if (dev_devfsd_exists
< 0)
116 dev_devfsd_exists
= stat ("/dev/.devfsd", &st
) == 0;
119 return dev_devfsd_exists
;
121 #endif /* __linux__ */
124 find_grub_drive (const char *name
)
130 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
131 if (map
[i
].drive
&& ! strcmp (map
[i
].drive
, name
))
143 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
151 grub_util_biosdisk_iterate (int (*hook
) (const char *name
))
155 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
156 if (map
[i
].drive
&& hook (map
[i
].drive
))
163 grub_util_biosdisk_open (const char *name
, grub_disk_t disk
)
168 drive
= find_grub_drive (name
);
170 return grub_error (GRUB_ERR_BAD_DEVICE
,
171 "no mapping exists for `%s'", name
);
173 disk
->has_partitions
= 1;
177 #if defined(__MINGW32__)
181 size
= grub_util_get_disk_size (map
[drive
].device
);
184 grub_util_error ("unaligned device size");
186 disk
->total_sectors
= size
>> 9;
188 grub_util_info ("the size of %s is %llu", name
, disk
->total_sectors
);
190 return GRUB_ERR_NONE
;
192 #elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) || \
193 defined(__FreeBSD_kernel__) || defined(__APPLE__)
195 unsigned long long nr
;
198 fd
= open (map
[drive
].device
, O_RDONLY
);
200 return grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' while attempting to get disk size", map
[drive
].device
);
202 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
203 if (fstat (fd
, &st
) < 0 || ! S_ISCHR (st
.st_mode
))
205 if (fstat (fd
, &st
) < 0 || ! S_ISBLK (st
.st_mode
))
212 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
213 if (ioctl (fd
, DIOCGMEDIASIZE
, &nr
))
214 # elif defined(__APPLE__)
215 if (ioctl (fd
, DKIOCGETBLOCKCOUNT
, &nr
))
217 if (ioctl (fd
, BLKGETSIZE64
, &nr
))
226 #if defined (__APPLE__)
227 disk
->total_sectors
= nr
;
229 disk
->total_sectors
= nr
/ 512;
232 grub_util_error ("unaligned device size");
235 grub_util_info ("the size of %s is %llu", name
, disk
->total_sectors
);
237 return GRUB_ERR_NONE
;
241 /* In GNU/Hurd, stat() will return the right size. */
242 #elif !defined (__GNU__)
243 # warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
245 if (stat (map
[drive
].device
, &st
) < 0)
246 return grub_error (GRUB_ERR_BAD_DEVICE
, "cannot stat `%s'", map
[drive
].device
);
248 disk
->total_sectors
= st
.st_size
>> GRUB_DISK_SECTOR_BITS
;
250 grub_util_info ("the size of %s is %lu", name
, disk
->total_sectors
);
252 return GRUB_ERR_NONE
;
257 linux_find_partition (char *dev
, unsigned long sector
)
259 size_t len
= strlen (dev
);
263 char real_dev
[PATH_MAX
];
265 strcpy(real_dev
, dev
);
267 if (have_devfs () && strcmp (real_dev
+ len
- 5, "/disc") == 0)
269 p
= real_dev
+ len
- 4;
272 else if (real_dev
[len
- 1] >= '0' && real_dev
[len
- 1] <= '9')
283 for (i
= 1; i
< 10000; i
++)
286 struct hd_geometry hdg
;
288 sprintf (p
, format
, i
);
289 fd
= open (real_dev
, O_RDONLY
);
293 if (ioctl (fd
, HDIO_GETGEO
, &hdg
))
301 if (hdg
.start
== sector
)
303 strcpy (dev
, real_dev
);
310 #endif /* __linux__ */
313 open_device (const grub_disk_t disk
, grub_disk_addr_t sector
, int flags
)
318 flags
|= O_LARGEFILE
;
331 /* Linux has a bug that the disk cache for a whole disk is not consistent
332 with the one for a partition of the disk. */
334 int is_partition
= 0;
337 strcpy (dev
, map
[disk
->id
].device
);
338 if (disk
->partition
&& strncmp (map
[disk
->id
].device
, "/dev/", 5) == 0)
339 is_partition
= linux_find_partition (dev
, disk
->partition
->start
);
341 /* Open the partition. */
342 grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev
);
343 fd
= open (dev
, flags
);
346 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s'", dev
);
350 /* Make the buffer cache consistent with the physical disk. */
351 ioctl (fd
, BLKFLSBUF
, 0);
354 sector
-= disk
->partition
->start
;
356 #else /* ! __linux__ */
357 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
358 int sysctl_flags
, sysctl_oldflags
;
359 size_t sysctl_size
= sizeof (sysctl_flags
);
361 if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags
, &sysctl_size
, NULL
, 0))
363 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot get current flags of sysctl kern.geom.debugflags");
366 sysctl_flags
= sysctl_oldflags
| 0x10;
367 if (! (sysctl_oldflags
& 0x10)
368 && sysctlbyname ("kern.geom.debugflags", NULL
, 0, &sysctl_flags
, sysctl_size
))
370 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot set flags of sysctl kern.geom.debugflags");
375 fd
= open (map
[disk
->id
].device
, flags
);
377 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
378 if (! (sysctl_oldflags
& 0x10)
379 && sysctlbyname ("kern.geom.debugflags", NULL
, 0, &sysctl_oldflags
, sysctl_size
))
381 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot set flags back to the old value for sysctl kern.geom.debugflags");
386 #if defined(__APPLE__)
387 /* If we can't have exclusive access, try shared access */
389 fd
= open(map
[disk
->id
].device
, flags
| O_SHLOCK
);
394 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' in open_device()", map
[disk
->id
].device
);
397 #endif /* ! __linux__ */
399 #if defined(__linux__) && (!defined(__GLIBC__) || \
400 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
401 /* Maybe libc doesn't have large file support. */
403 loff_t offset
, result
;
404 static int _llseek (uint filedes
, ulong hi
, ulong lo
,
405 loff_t
*res
, uint wh
);
406 _syscall5 (int, _llseek
, uint
, filedes
, ulong
, hi
, ulong
, lo
,
407 loff_t
*, res
, uint
, wh
);
409 offset
= (loff_t
) sector
<< GRUB_DISK_SECTOR_BITS
;
410 if (_llseek (fd
, offset
>> 32, offset
& 0xffffffff, &result
, SEEK_SET
))
412 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot seek `%s'", map
[disk
->id
].device
);
419 off_t offset
= (off_t
) sector
<< GRUB_DISK_SECTOR_BITS
;
421 if (lseek (fd
, offset
, SEEK_SET
) != offset
)
423 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot seek `%s'", map
[disk
->id
].device
);
433 /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
434 error occurs, otherwise return LEN. */
436 nread (int fd
, char *buf
, size_t len
)
442 ssize_t ret
= read (fd
, buf
, len
);
459 /* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
460 error occurs, otherwise return LEN. */
462 nwrite (int fd
, const char *buf
, size_t len
)
468 ssize_t ret
= write (fd
, buf
, len
);
486 grub_util_biosdisk_read (grub_disk_t disk
, grub_disk_addr_t sector
,
487 grub_size_t size
, char *buf
)
491 fd
= open_device (disk
, sector
, O_RDONLY
);
496 if (sector
== 0 && size
> 1)
498 /* Work around a bug in Linux ez remapping. Linux remaps all
499 sectors that are read together with the MBR in one read. It
500 should only remap the MBR, so we split the read in two
502 if (nread (fd
, buf
, GRUB_DISK_SECTOR_SIZE
) != GRUB_DISK_SECTOR_SIZE
)
504 grub_error (GRUB_ERR_READ_ERROR
, "cannot read `%s'", map
[disk
->id
].device
);
509 buf
+= GRUB_DISK_SECTOR_SIZE
;
512 #endif /* __linux__ */
514 if (nread (fd
, buf
, size
<< GRUB_DISK_SECTOR_BITS
)
515 != (ssize_t
) (size
<< GRUB_DISK_SECTOR_BITS
))
516 grub_error (GRUB_ERR_READ_ERROR
, "cannot read from `%s'", map
[disk
->id
].device
);
523 grub_util_biosdisk_write (grub_disk_t disk
, grub_disk_addr_t sector
,
524 grub_size_t size
, const char *buf
)
528 fd
= open_device (disk
, sector
, O_WRONLY
);
532 if (nwrite (fd
, buf
, size
<< GRUB_DISK_SECTOR_BITS
)
533 != (ssize_t
) (size
<< GRUB_DISK_SECTOR_BITS
))
534 grub_error (GRUB_ERR_WRITE_ERROR
, "cannot write to `%s'", map
[disk
->id
].device
);
540 static struct grub_disk_dev grub_util_biosdisk_dev
=
543 .id
= GRUB_DISK_DEVICE_BIOSDISK_ID
,
544 .iterate
= grub_util_biosdisk_iterate
,
545 .open
= grub_util_biosdisk_open
,
547 .read
= grub_util_biosdisk_read
,
548 .write
= grub_util_biosdisk_write
,
553 read_device_map (const char *dev_map
)
556 char buf
[1024]; /* XXX */
560 auto void show_error (const char *msg
);
561 void show_error (const char *msg
)
563 grub_util_error ("%s:%d: %s", dev_map
, lineno
, msg
);
566 fp
= fopen (dev_map
, "r");
568 grub_util_error ("Cannot open `%s'", dev_map
);
570 while (fgets (buf
, sizeof (buf
), fp
))
578 /* Skip leading spaces. */
579 while (*p
&& isspace (*p
))
582 /* If the first character is `#' or NUL, skip this line. */
583 if (*p
== '\0' || *p
== '#')
587 show_error ("No open parenthesis found");
590 /* Find a free slot. */
591 drive
= find_free_slot ();
593 show_error ("Map table size exceeded");
598 show_error ("No close parenthesis found");
600 map
[drive
].drive
= xmalloc (p
- e
+ sizeof ('\0'));
601 strncpy (map
[drive
].drive
, e
, p
- e
+ sizeof ('\0'));
602 map
[drive
].drive
[p
- e
] = '\0';
605 /* Skip leading spaces. */
606 while (*p
&& isspace (*p
))
610 show_error ("No filename found");
612 /* NUL-terminate the filename. */
614 while (*e
&& ! isspace (*e
))
620 if (grub_util_get_disk_size (p
) == -1LL)
622 if (stat (p
, &st
) == -1)
625 free (map
[drive
].drive
);
626 map
[drive
].drive
= NULL
;
627 grub_util_info ("Cannot stat `%s', skipping", p
);
632 /* On Linux, the devfs uses symbolic links horribly, and that
633 confuses the interface very much, so use realpath to expand
635 map
[drive
].device
= xmalloc (PATH_MAX
);
636 if (! realpath (p
, map
[drive
].device
))
637 grub_util_error ("Cannot get the real path of `%s'", p
);
639 map
[drive
].device
= xstrdup (p
);
647 grub_util_biosdisk_init (const char *dev_map
)
649 read_device_map (dev_map
);
650 grub_disk_dev_register (&grub_util_biosdisk_dev
);
654 grub_util_biosdisk_fini (void)
658 for (i
= 0; i
< sizeof (map
) / sizeof (map
[0]); i
++)
663 free (map
[i
].device
);
664 map
[i
].drive
= map
[i
].device
= NULL
;
667 grub_disk_dev_unregister (&grub_util_biosdisk_dev
);
671 make_device_name (int drive
, int dos_part
, int bsd_part
)
673 int len
= strlen(map
[drive
].drive
);
678 /* Add in char length of dos_part+1 */
679 int tmp
= dos_part
+ 1;
681 while ((tmp
/= 10) != 0)
687 /* Length to alloc is: char length of map[drive].drive, plus
688 * char length of (dos_part+1) or of bsd_part, plus
689 * 2 for the comma and a null/end of string (\0)
691 p
= xmalloc (len
+ 2);
692 sprintf (p
, "%s", map
[drive
].drive
);
695 sprintf (p
+ strlen (p
), ",%d", dos_part
+ 1);
698 sprintf (p
+ strlen (p
), ",%c", bsd_part
+ 'a');
704 convert_system_partition_to_system_disk (const char *os_dev
)
706 #if defined(__linux__)
707 char *path
= xmalloc (PATH_MAX
);
708 if (! realpath (os_dev
, path
))
711 if (strncmp ("/dev/", path
, 5) == 0)
715 /* If this is an IDE disk. */
716 if (strncmp ("ide/", p
, 4) == 0)
718 p
= strstr (p
, "part");
725 /* If this is a SCSI disk. */
726 if (strncmp ("scsi/", p
, 5) == 0)
728 p
= strstr (p
, "part");
735 /* If this is a DAC960 disk. */
736 if (strncmp ("rd/c", p
, 4) == 0)
738 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
746 /* If this is a Mylex AcceleRAID Array. */
747 if (strncmp ("rs/c", p
, 4) == 0)
749 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
756 /* If this is a CCISS disk. */
757 if (strncmp ("cciss/c", p
, sizeof ("cciss/c") - 1) == 0)
759 /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
767 /* If this is a Compaq Intelligent Drive Array. */
768 if (strncmp ("ida/c", p
, sizeof ("ida/c") - 1) == 0)
770 /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
778 /* If this is an I2O disk. */
779 if (strncmp ("i2o/hd", p
, sizeof ("i2o/hd") - 1) == 0)
781 /* /dev/i2o/hd[a-z]([0-9]+)? */
782 p
[sizeof ("i2o/hda") - 1] = '\0';
786 /* If this is a MultiMediaCard (MMC). */
787 if (strncmp ("mmcblk", p
, sizeof ("mmcblk") - 1) == 0)
789 /* /dev/mmcblk[0-9]+(p[0-9]+)? */
797 /* If this is an IDE, SCSI or Virtio disk. */
798 if (strncmp ("vdisk", p
, 5) == 0
799 && p
[5] >= 'a' && p
[5] <= 'z')
801 /* /dev/vdisk[a-z][0-9]* */
805 if ((strncmp ("hd", p
, 2) == 0
806 || strncmp ("vd", p
, 2) == 0
807 || strncmp ("sd", p
, 2) == 0)
808 && p
[2] >= 'a' && p
[2] <= 'z')
810 /* /dev/[hsv]d[a-z][0-9]* */
815 /* If this is a Xen virtual block device. */
816 if ((strncmp ("xvd", p
, 3) == 0) && p
[3] >= 'a' && p
[3] <= 'z')
818 /* /dev/xvd[a-z][0-9]* */
826 #elif defined(__GNU__)
827 char *path
= xstrdup (os_dev
);
828 if (strncmp ("/dev/sd", path
, 7) == 0 || strncmp ("/dev/hd", path
, 7) == 0)
830 char *p
= strchr (path
+ 7, 's');
836 #elif defined(__CYGWIN__)
837 char *path
= xstrdup (os_dev
);
838 if (strncmp ("/dev/sd", path
, 7) == 0 && 'a' <= path
[7] && path
[7] <= 'z')
842 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
843 char *path
= xstrdup (os_dev
);
844 if (strncmp ("/dev/", path
, 5) == 0)
847 for (p
= path
+ 5; *p
; ++p
)
848 if (grub_isdigit(*p
))
859 # warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
860 return xstrdup (os_dev
);
864 #if defined(__linux__) || defined(__CYGWIN__)
866 device_is_wholedisk (const char *os_dev
)
868 int len
= strlen (os_dev
);
870 if (os_dev
[len
- 1] < '0' || os_dev
[len
- 1] > '9')
877 find_system_device (const char *os_dev
)
882 os_disk
= convert_system_partition_to_system_disk (os_dev
);
886 for (i
= 0; i
< (int) (sizeof (map
) / sizeof (map
[0])); i
++)
887 if (map
[i
].device
&& strcmp (map
[i
].device
, os_disk
) == 0)
898 grub_util_biosdisk_get_grub_dev (const char *os_dev
)
903 if (stat (os_dev
, &st
) < 0)
905 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot stat `%s'", os_dev
);
909 drive
= find_system_device (os_dev
);
912 grub_error (GRUB_ERR_BAD_DEVICE
,
913 "no mapping exists for `%s'", os_dev
);
917 if (grub_strcmp (os_dev
, convert_system_partition_to_system_disk (os_dev
))
919 return make_device_name (drive
, -1, -1);
921 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
922 if (! S_ISCHR (st
.st_mode
))
924 if (! S_ISBLK (st
.st_mode
))
926 return make_device_name (drive
, -1, -1);
928 #if defined(__linux__) || defined(__CYGWIN__)
929 /* Linux counts partitions uniformly, whether a BSD partition or a DOS
930 partition, so mapping them to GRUB devices is not trivial.
931 Here, get the start sector of a partition by HDIO_GETGEO, and
932 compare it with each partition GRUB recognizes.
934 Cygwin /dev/sdXN emulation uses Windows partition mapping. It
935 does not count the extended partition and missing primary
936 partitions. Use same method as on Linux here. */
941 struct hd_geometry hdg
;
944 auto int find_partition (grub_disk_t disk
,
945 const grub_partition_t partition
);
947 int find_partition (grub_disk_t disk
__attribute__ ((unused
)),
948 const grub_partition_t partition
)
950 struct grub_msdos_partition
*pcdata
= NULL
;
952 if (strcmp (partition
->partmap
->name
, "part_msdos") == 0)
953 pcdata
= partition
->data
;
957 if (pcdata
->bsd_part
< 0)
958 grub_util_info ("DOS partition %d starts from %lu",
959 pcdata
->dos_part
, partition
->start
);
961 grub_util_info ("BSD partition %d,%c starts from %lu",
962 pcdata
->dos_part
, pcdata
->bsd_part
+ 'a',
967 grub_util_info ("Partition %d starts from %lu",
968 partition
->index
, partition
->start
);
971 if (hdg
.start
== partition
->start
)
975 dos_part
= pcdata
->dos_part
;
976 bsd_part
= pcdata
->bsd_part
;
980 dos_part
= partition
->index
;
989 name
= make_device_name (drive
, -1, -1);
991 if (MAJOR (st
.st_rdev
) == FLOPPY_MAJOR
)
994 fd
= open (os_dev
, O_RDONLY
);
997 grub_error (GRUB_ERR_BAD_DEVICE
, "cannot open `%s' while attempting to get disk geometry", os_dev
);
1002 if (ioctl (fd
, HDIO_GETGEO
, &hdg
))
1004 grub_error (GRUB_ERR_BAD_DEVICE
,
1005 "cannot get geometry of `%s'", os_dev
);
1013 grub_util_info ("%s starts from %lu", os_dev
, hdg
.start
);
1015 if (hdg
.start
== 0 && device_is_wholedisk (os_dev
))
1018 grub_util_info ("opening the device %s", name
);
1019 disk
= grub_disk_open (name
);
1025 grub_partition_iterate (disk
, find_partition
);
1026 if (grub_errno
!= GRUB_ERR_NONE
)
1028 grub_disk_close (disk
);
1034 grub_disk_close (disk
);
1035 grub_error (GRUB_ERR_BAD_DEVICE
,
1036 "cannot find the partition of `%s'", os_dev
);
1040 return make_device_name (drive
, dos_part
, bsd_part
);
1043 #elif defined(__GNU__)
1044 /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
1050 p
= strrchr (os_dev
, 's');
1057 n
= strtol (p
, &q
, 10);
1058 if (p
!= q
&& n
!= GRUB_LONG_MIN
&& n
!= GRUB_LONG_MAX
)
1060 dos_part
= (int) n
- 1;
1062 if (*q
>= 'a' && *q
<= 'g')
1063 bsd_part
= *q
- 'a';
1067 return make_device_name (drive
, dos_part
, bsd_part
);
1070 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
1071 /* FreeBSD uses "/dev/[a-z]+[0-9]+(s[0-9]+[a-z]?)?". */
1076 if (strncmp ("/dev/", os_dev
, 5) == 0)
1082 for (p
= os_dev
+ 5; *p
; ++p
)
1083 if (grub_isdigit(*p
))
1085 p
= strchr (p
, 's');
1089 n
= strtol (p
, &q
, 10);
1090 if (p
!= q
&& n
!= GRUB_LONG_MIN
&& n
!= GRUB_LONG_MAX
)
1092 dos_part
= (int) n
- 1;
1094 if (*q
>= 'a' && *q
<= 'g')
1095 bsd_part
= *q
- 'a';
1102 return make_device_name (drive
, dos_part
, bsd_part
);
1106 # warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
1107 return make_device_name (drive
, -1, -1);