changing mime-type of docs/*.texi and docs/texinfo.tex to text/plain
[grub2/phcoder.git] / util / biosdisk.c
blob5465cb0581bac09c8e34d5fb6e7959a8daf8edf3
1 /* biosdisk.c - emulate biosdisk */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008 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>
24 #include <grub/err.h>
25 #include <grub/util/misc.h>
26 #include <grub/util/biosdisk.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <assert.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <limits.h>
40 #ifdef __linux__
41 # include <sys/ioctl.h> /* ioctl */
42 # if !defined(__GLIBC__) || \
43 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
44 /* Maybe libc doesn't have large file support. */
45 # include <linux/unistd.h> /* _llseek */
46 # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
47 # ifndef BLKFLSBUF
48 # define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
49 # endif /* ! BLKFLSBUF */
50 # include <sys/ioctl.h> /* ioctl */
51 # ifndef HDIO_GETGEO
52 # define HDIO_GETGEO 0x0301 /* get device geometry */
53 /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
54 defined. */
55 struct hd_geometry
57 unsigned char heads;
58 unsigned char sectors;
59 unsigned short cylinders;
60 unsigned long start;
62 # endif /* ! HDIO_GETGEO */
63 # ifndef BLKGETSIZE64
64 # define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
65 # endif /* ! BLKGETSIZE64 */
66 # ifndef MAJOR
67 # ifndef MINORBITS
68 # define MINORBITS 8
69 # endif /* ! MINORBITS */
70 # define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
71 # endif /* ! MAJOR */
72 # ifndef FLOPPY_MAJOR
73 # define FLOPPY_MAJOR 2
74 # endif /* ! FLOPPY_MAJOR */
75 # ifndef LOOP_MAJOR
76 # define LOOP_MAJOR 7
77 # endif /* ! LOOP_MAJOR */
78 #endif /* __linux__ */
80 #ifdef __CYGWIN__
81 # include <sys/ioctl.h>
82 # include <cygwin/fs.h> /* BLKGETSIZE64 */
83 # include <cygwin/hdreg.h> /* HDIO_GETGEO */
84 # define MAJOR(dev) ((unsigned) ((dev) >> 16))
85 # define FLOPPY_MAJOR 2
86 #endif
88 struct
90 char *drive;
91 char *device;
92 } map[256];
94 #ifdef __linux__
95 /* Check if we have devfs support. */
96 static int
97 have_devfs (void)
99 static int dev_devfsd_exists = -1;
101 if (dev_devfsd_exists < 0)
103 struct stat st;
105 dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
108 return dev_devfsd_exists;
110 #endif /* __linux__ */
112 static int
113 find_grub_drive (const char *name)
115 unsigned int i;
117 if (name)
119 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
120 if (map[i].drive && ! strcmp (map[i].drive, name))
121 return i;
124 return -1;
127 static int
128 find_free_slot ()
130 unsigned int i;
132 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
133 if (! map[i].drive)
134 return i;
136 return -1;
139 static int
140 grub_util_biosdisk_iterate (int (*hook) (const char *name))
142 unsigned i;
144 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
145 if (map[i].drive && hook (map[i].drive))
146 return 1;
148 return 0;
151 static grub_err_t
152 grub_util_biosdisk_open (const char *name, grub_disk_t disk)
154 int drive;
155 struct stat st;
157 drive = find_grub_drive (name);
158 if (drive < 0)
159 return grub_error (GRUB_ERR_BAD_DEVICE,
160 "no mapping exists for `%s'", name);
162 disk->has_partitions = 1;
163 disk->id = drive;
165 /* Get the size. */
166 #if defined(__MINGW32__)
168 grub_uint64_t size;
170 size = grub_util_get_disk_size (map[drive].device);
172 if (size % 512)
173 grub_util_error ("unaligned device size");
175 disk->total_sectors = size >> 9;
177 grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
179 return GRUB_ERR_NONE;
181 #elif defined(__linux__) || defined(__CYGWIN__)
183 unsigned long long nr;
184 int fd;
186 fd = open (map[drive].device, O_RDONLY);
187 if (fd == -1)
188 return grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device);
190 if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
192 close (fd);
193 goto fail;
196 if (ioctl (fd, BLKGETSIZE64, &nr))
198 close (fd);
199 goto fail;
202 close (fd);
203 disk->total_sectors = nr / 512;
205 if (nr % 512)
206 grub_util_error ("unaligned device size");
208 grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
210 return GRUB_ERR_NONE;
213 fail:
214 /* In GNU/Hurd, stat() will return the right size. */
215 #elif !defined (__GNU__)
216 # warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
217 #endif
218 if (stat (map[drive].device, &st) < 0)
219 return grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", map[drive].device);
221 disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS;
223 grub_util_info ("the size of %s is %lu", name, disk->total_sectors);
225 return GRUB_ERR_NONE;
228 #ifdef __linux__
229 static int
230 linux_find_partition (char *dev, unsigned long sector)
232 size_t len = strlen (dev);
233 const char *format;
234 char *p;
235 int i;
236 char real_dev[PATH_MAX];
238 strcpy(real_dev, dev);
240 if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0)
242 p = real_dev + len - 4;
243 format = "part%d";
245 else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
247 p = real_dev + len;
248 format = "p%d";
250 else
252 p = real_dev + len;
253 format = "%d";
256 for (i = 1; i < 10000; i++)
258 int fd;
259 struct hd_geometry hdg;
261 sprintf (p, format, i);
262 fd = open (real_dev, O_RDONLY);
263 if (fd == -1)
264 return 0;
266 if (ioctl (fd, HDIO_GETGEO, &hdg))
268 close (fd);
269 return 0;
272 close (fd);
274 if (hdg.start == sector)
276 strcpy (dev, real_dev);
277 return 1;
281 return 0;
283 #endif /* __linux__ */
285 static int
286 open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
288 int fd;
290 #ifdef O_LARGEFILE
291 flags |= O_LARGEFILE;
292 #endif
293 #ifdef O_SYNC
294 flags |= O_SYNC;
295 #endif
296 #ifdef O_FSYNC
297 flags |= O_FSYNC;
298 #endif
299 #ifdef O_BINARY
300 flags |= O_BINARY;
301 #endif
303 #ifdef __linux__
304 /* Linux has a bug that the disk cache for a whole disk is not consistent
305 with the one for a partition of the disk. */
307 int is_partition = 0;
308 char dev[PATH_MAX];
310 strcpy (dev, map[disk->id].device);
311 if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
312 is_partition = linux_find_partition (dev, disk->partition->start);
314 /* Open the partition. */
315 grub_util_info ("opening the device `%s' in open_device()", dev);
316 fd = open (dev, flags);
317 if (fd < 0)
319 grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", dev);
320 return -1;
323 /* Make the buffer cache consistent with the physical disk. */
324 ioctl (fd, BLKFLSBUF, 0);
326 if (is_partition)
327 sector -= disk->partition->start;
329 #else /* ! __linux__ */
330 fd = open (map[disk->id].device, flags);
331 if (fd < 0)
333 grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' in open_device()", map[disk->id].device);
334 return -1;
336 #endif /* ! __linux__ */
338 #if defined(__linux__) && (!defined(__GLIBC__) || \
339 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
340 /* Maybe libc doesn't have large file support. */
342 loff_t offset, result;
343 static int _llseek (uint filedes, ulong hi, ulong lo,
344 loff_t *res, uint wh);
345 _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
346 loff_t *, res, uint, wh);
348 offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
349 if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
351 grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
352 close (fd);
353 return -1;
356 #else
358 off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
360 if (lseek (fd, offset, SEEK_SET) != offset)
362 grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
363 close (fd);
364 return -1;
367 #endif
369 return fd;
372 /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
373 error occurs, otherwise return LEN. */
374 static ssize_t
375 nread (int fd, char *buf, size_t len)
377 ssize_t size = len;
379 while (len)
381 ssize_t ret = read (fd, buf, len);
383 if (ret <= 0)
385 if (errno == EINTR)
386 continue;
387 else
388 return ret;
391 len -= ret;
392 buf += ret;
395 return size;
398 /* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
399 error occurs, otherwise return LEN. */
400 static ssize_t
401 nwrite (int fd, const char *buf, size_t len)
403 ssize_t size = len;
405 while (len)
407 ssize_t ret = write (fd, buf, len);
409 if (ret <= 0)
411 if (errno == EINTR)
412 continue;
413 else
414 return ret;
417 len -= ret;
418 buf += ret;
421 return size;
424 static grub_err_t
425 grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
426 grub_size_t size, char *buf)
428 int fd;
430 fd = open_device (disk, sector, O_RDONLY);
431 if (fd < 0)
432 return grub_errno;
434 #ifdef __linux__
435 if (sector == 0 && size > 1)
437 /* Work around a bug in Linux ez remapping. Linux remaps all
438 sectors that are read together with the MBR in one read. It
439 should only remap the MBR, so we split the read in two
440 parts. -jochen */
441 if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE)
443 grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
444 close (fd);
445 return grub_errno;
448 buf += GRUB_DISK_SECTOR_SIZE;
449 size--;
451 #endif /* __linux__ */
453 if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS)
454 != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
455 grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
457 close (fd);
458 return grub_errno;
461 static grub_err_t
462 grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
463 grub_size_t size, const char *buf)
465 int fd;
467 fd = open_device (disk, sector, O_WRONLY);
468 if (fd < 0)
469 return grub_errno;
471 if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS)
472 != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
473 grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
475 close (fd);
476 return grub_errno;
479 static struct grub_disk_dev grub_util_biosdisk_dev =
481 .name = "biosdisk",
482 .id = GRUB_DISK_DEVICE_BIOSDISK_ID,
483 .iterate = grub_util_biosdisk_iterate,
484 .open = grub_util_biosdisk_open,
485 .close = 0,
486 .read = grub_util_biosdisk_read,
487 .write = grub_util_biosdisk_write,
488 .next = 0
491 static void
492 read_device_map (const char *dev_map)
494 FILE *fp;
495 char buf[1024]; /* XXX */
496 int lineno = 0;
497 struct stat st;
499 auto void show_error (const char *msg);
500 void show_error (const char *msg)
502 grub_util_error ("%s:%d: %s", dev_map, lineno, msg);
505 fp = fopen (dev_map, "r");
506 if (! fp)
507 grub_util_error ("Cannot open `%s'", dev_map);
509 while (fgets (buf, sizeof (buf), fp))
511 char *p = buf;
512 char *e;
513 int drive;
515 lineno++;
517 /* Skip leading spaces. */
518 while (*p && isspace (*p))
519 p++;
521 /* If the first character is `#' or NUL, skip this line. */
522 if (*p == '\0' || *p == '#')
523 continue;
525 if (*p != '(')
526 show_error ("No open parenthesis found");
528 p++;
529 /* Find a free slot. */
530 drive = find_free_slot ();
531 if (drive < 0)
532 show_error ("Map table size exceeded");
534 e = p;
535 p = strchr (p, ')');
536 if (! p)
537 show_error ("No close parenthesis found");
539 map[drive].drive = xmalloc (p - e + sizeof ('\0'));
540 strncpy (map[drive].drive, e, p - e + sizeof ('\0'));
541 map[drive].drive[p - e] = '\0';
543 p++;
544 /* Skip leading spaces. */
545 while (*p && isspace (*p))
546 p++;
548 if (*p == '\0')
549 show_error ("No filename found");
551 /* NUL-terminate the filename. */
552 e = p;
553 while (*e && ! isspace (*e))
554 e++;
555 *e = '\0';
557 if (stat (p, &st) == -1)
559 free (map[drive].drive);
560 map[drive].drive = NULL;
561 grub_util_info ("Cannot stat `%s', skipping", p);
562 continue;
565 #ifdef __linux__
566 /* On Linux, the devfs uses symbolic links horribly, and that
567 confuses the interface very much, so use realpath to expand
568 symbolic links. */
569 map[drive].device = xmalloc (PATH_MAX);
570 if (! realpath (p, map[drive].device))
571 grub_util_error ("Cannot get the real path of `%s'", p);
572 #else
573 map[drive].device = xstrdup (p);
574 #endif
577 fclose (fp);
580 void
581 grub_util_biosdisk_init (const char *dev_map)
583 read_device_map (dev_map);
584 grub_disk_dev_register (&grub_util_biosdisk_dev);
587 void
588 grub_util_biosdisk_fini (void)
590 unsigned i;
592 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
594 if (map[i].drive)
595 free (map[i].drive);
596 if (map[i].device)
597 free (map[i].device);
598 map[i].drive = map[i].device = NULL;
601 grub_disk_dev_unregister (&grub_util_biosdisk_dev);
604 static char *
605 make_device_name (int drive, int dos_part, int bsd_part)
607 char *p;
609 p = xmalloc (30);
610 sprintf (p, "%s", map[drive].drive);
612 if (dos_part >= 0)
613 sprintf (p + strlen (p), ",%d", dos_part + 1);
615 if (bsd_part >= 0)
616 sprintf (p + strlen (p), ",%c", bsd_part + 'a');
618 return p;
621 static char *
622 convert_system_partition_to_system_disk (const char *os_dev)
624 #if defined(__linux__)
625 char *path = xmalloc (PATH_MAX);
626 if (! realpath (os_dev, path))
627 return 0;
629 if (strncmp ("/dev/", path, 5) == 0)
631 char *p = path + 5;
633 /* If this is an IDE disk. */
634 if (strncmp ("ide/", p, 4) == 0)
636 p = strstr (p, "part");
637 if (p)
638 strcpy (p, "disc");
640 return path;
643 /* If this is a SCSI disk. */
644 if (strncmp ("scsi/", p, 5) == 0)
646 p = strstr (p, "part");
647 if (p)
648 strcpy (p, "disc");
650 return path;
653 /* If this is a DAC960 disk. */
654 if (strncmp ("rd/c", p, 4) == 0)
656 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
657 p = strchr (p, 'p');
658 if (p)
659 *p = '\0';
661 return path;
664 /* If this is a CCISS disk. */
665 if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
667 /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
668 p = strchr (p, 'p');
669 if (p)
670 *p = '\0';
672 return path;
675 /* If this is a Compaq Intelligent Drive Array. */
676 if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
678 /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
679 p = strchr (p, 'p');
680 if (p)
681 *p = '\0';
683 return path;
686 /* If this is an I2O disk. */
687 if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
689 /* /dev/i2o/hd[a-z]([0-9]+)? */
690 p[sizeof ("i2o/hda") - 1] = '\0';
691 return path;
694 /* If this is a MultiMediaCard (MMC). */
695 if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
697 /* /dev/mmcblk[0-9]+(p[0-9]+)? */
698 p = strchr (p, 'p');
699 if (p)
700 *p = '\0';
702 return path;
705 /* If this is an IDE, SCSI or Virtio disk. */
706 if ((strncmp ("hd", p, 2) == 0
707 || strncmp ("vd", p, 2) == 0
708 || strncmp ("sd", p, 2) == 0)
709 && p[2] >= 'a' && p[2] <= 'z')
711 /* /dev/[hsv]d[a-z][0-9]* */
712 p[3] = '\0';
713 return path;
716 /* If this is a Xen virtual block device. */
717 if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
719 /* /dev/xvd[a-z][0-9]* */
720 p[4] = '\0';
721 return path;
725 return path;
727 #elif defined(__GNU__)
728 char *path = xstrdup (os_dev);
729 if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
731 char *p = strchr (path + 7, 's');
732 if (p)
733 *p = '\0';
735 return path;
737 #elif defined(__CYGWIN__)
738 char *path = xstrdup (os_dev);
739 if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
740 path[8] = 0;
741 return path;
743 #else
744 # warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
745 return xstrdup (os_dev);
746 #endif
749 static int
750 find_system_device (const char *os_dev)
752 int i;
753 char *os_disk;
755 os_disk = convert_system_partition_to_system_disk (os_dev);
756 if (! os_disk)
757 return -1;
759 for (i = 0; i < (int) (sizeof (map) / sizeof (map[0])); i++)
760 if (map[i].device && strcmp (map[i].device, os_disk) == 0)
762 free (os_disk);
763 return i;
766 free (os_disk);
767 return -1;
770 char *
771 grub_util_biosdisk_get_grub_dev (const char *os_dev)
773 struct stat st;
774 int drive;
776 if (stat (os_dev, &st) < 0)
778 grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
779 return 0;
782 drive = find_system_device (os_dev);
783 if (drive < 0)
785 grub_error (GRUB_ERR_BAD_DEVICE,
786 "no mapping exists for `%s'", os_dev);
787 return 0;
790 if (! S_ISBLK (st.st_mode))
791 return make_device_name (drive, -1, -1);
793 #if defined(__linux__) || defined(__CYGWIN__)
794 /* Linux counts partitions uniformly, whether a BSD partition or a DOS
795 partition, so mapping them to GRUB devices is not trivial.
796 Here, get the start sector of a partition by HDIO_GETGEO, and
797 compare it with each partition GRUB recognizes.
799 Cygwin /dev/sdXN emulation uses Windows partition mapping. It
800 does not count the extended partition and missing primary
801 partitions. Use same method as on Linux here. */
803 char *name;
804 grub_disk_t disk;
805 int fd;
806 struct hd_geometry hdg;
807 int dos_part = -1;
808 int bsd_part = -1;
809 auto int find_partition (grub_disk_t disk,
810 const grub_partition_t partition);
812 int find_partition (grub_disk_t disk __attribute__ ((unused)),
813 const grub_partition_t partition)
815 struct grub_pc_partition *pcdata = NULL;
817 if (strcmp (partition->partmap->name, "pc_partition_map") == 0)
818 pcdata = partition->data;
820 if (pcdata)
822 if (pcdata->bsd_part < 0)
823 grub_util_info ("DOS partition %d starts from %lu",
824 pcdata->dos_part, partition->start);
825 else
826 grub_util_info ("BSD partition %d,%c starts from %lu",
827 pcdata->dos_part, pcdata->bsd_part + 'a',
828 partition->start);
830 else
832 grub_util_info ("Partition %d starts from %lu",
833 partition->index, partition->start);
836 if (hdg.start == partition->start)
838 if (pcdata)
840 dos_part = pcdata->dos_part;
841 bsd_part = pcdata->bsd_part;
843 else
845 dos_part = partition->index;
846 bsd_part = -1;
848 return 1;
851 return 0;
854 name = make_device_name (drive, -1, -1);
856 if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
857 return name;
859 fd = open (os_dev, O_RDONLY);
860 if (fd == -1)
862 grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", os_dev);
863 free (name);
864 return 0;
867 if (ioctl (fd, HDIO_GETGEO, &hdg))
869 grub_error (GRUB_ERR_BAD_DEVICE,
870 "cannot get geometry of `%s'", os_dev);
871 close (fd);
872 free (name);
873 return 0;
876 close (fd);
878 grub_util_info ("%s starts from %lu", os_dev, hdg.start);
880 if (hdg.start == 0)
881 return name;
883 grub_util_info ("opening the device %s", name);
884 disk = grub_disk_open (name);
885 free (name);
887 if (! disk)
888 return 0;
890 grub_partition_iterate (disk, find_partition);
891 if (grub_errno != GRUB_ERR_NONE)
893 grub_disk_close (disk);
894 return 0;
897 if (dos_part < 0)
899 grub_disk_close (disk);
900 grub_error (GRUB_ERR_BAD_DEVICE,
901 "cannot find the partition of `%s'", os_dev);
902 return 0;
905 return make_device_name (drive, dos_part, bsd_part);
908 #elif defined(__GNU__)
909 /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
911 char *p;
912 int dos_part = -1;
913 int bsd_part = -1;
915 p = strrchr (os_dev, 's');
916 if (p)
918 long int n;
919 char *q;
921 p++;
922 n = strtol (p, &q, 10);
923 if (p != q && n != LONG_MIN && n != LONG_MAX)
925 dos_part = (int) n;
927 if (*q >= 'a' && *q <= 'g')
928 bsd_part = *q - 'a';
932 return make_device_name (drive, dos_part, bsd_part);
935 #else
936 # warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
937 return make_device_name (drive, -1, -1);
938 #endif