Update svn:ignore property
[grub2/jjazz.git] / util / hostdisk.c
blob67a1233af7e1f9ba0c6acc1cb804e51e7d3ec048
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/hostdisk.h>
27 #include <grub/misc.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <assert.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <limits.h>
41 #ifdef __linux__
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)) */
48 # ifndef BLKFLSBUF
49 # define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
50 # endif /* ! BLKFLSBUF */
51 # include <sys/ioctl.h> /* ioctl */
52 # ifndef HDIO_GETGEO
53 # define HDIO_GETGEO 0x0301 /* get device geometry */
54 /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
55 defined. */
56 struct hd_geometry
58 unsigned char heads;
59 unsigned char sectors;
60 unsigned short cylinders;
61 unsigned long start;
63 # endif /* ! HDIO_GETGEO */
64 # ifndef BLKGETSIZE64
65 # define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
66 # endif /* ! BLKGETSIZE64 */
67 # ifndef MAJOR
68 # ifndef MINORBITS
69 # define MINORBITS 8
70 # endif /* ! MINORBITS */
71 # define MAJOR(dev) ((unsigned) ((dev) >> MINORBITS))
72 # endif /* ! MAJOR */
73 # ifndef FLOPPY_MAJOR
74 # define FLOPPY_MAJOR 2
75 # endif /* ! FLOPPY_MAJOR */
76 # ifndef LOOP_MAJOR
77 # define LOOP_MAJOR 7
78 # endif /* ! LOOP_MAJOR */
79 #endif /* __linux__ */
81 #ifdef __CYGWIN__
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
87 #endif
89 struct
91 char *drive;
92 char *device;
93 } map[256];
95 #ifdef __linux__
96 /* Check if we have devfs support. */
97 static int
98 have_devfs (void)
100 static int dev_devfsd_exists = -1;
102 if (dev_devfsd_exists < 0)
104 struct stat st;
106 dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
109 return dev_devfsd_exists;
111 #endif /* __linux__ */
113 static int
114 find_grub_drive (const char *name)
116 unsigned int i;
118 if (name)
120 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
121 if (map[i].drive && ! strcmp (map[i].drive, name))
122 return i;
125 return -1;
128 static int
129 find_free_slot ()
131 unsigned int i;
133 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
134 if (! map[i].drive)
135 return i;
137 return -1;
140 static int
141 grub_util_biosdisk_iterate (int (*hook) (const char *name))
143 unsigned i;
145 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
146 if (map[i].drive && hook (map[i].drive))
147 return 1;
149 return 0;
152 static grub_err_t
153 grub_util_biosdisk_open (const char *name, grub_disk_t disk)
155 int drive;
156 struct stat st;
158 drive = find_grub_drive (name);
159 if (drive < 0)
160 return grub_error (GRUB_ERR_BAD_DEVICE,
161 "no mapping exists for `%s'", name);
163 disk->has_partitions = 1;
164 disk->id = drive;
166 /* Get the size. */
167 #if defined(__MINGW32__)
169 grub_uint64_t size;
171 size = grub_util_get_disk_size (map[drive].device);
173 if (size % 512)
174 grub_util_error ("unaligned device size");
176 disk->total_sectors = size >> 9;
178 grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
180 return GRUB_ERR_NONE;
182 #elif defined(__linux__) || defined(__CYGWIN__)
184 unsigned long long nr;
185 int fd;
187 fd = open (map[drive].device, O_RDONLY);
188 if (fd == -1)
189 return grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk size", map[drive].device);
191 if (fstat (fd, &st) < 0 || ! S_ISBLK (st.st_mode))
193 close (fd);
194 goto fail;
197 if (ioctl (fd, BLKGETSIZE64, &nr))
199 close (fd);
200 goto fail;
203 close (fd);
204 disk->total_sectors = nr / 512;
206 if (nr % 512)
207 grub_util_error ("unaligned device size");
209 grub_util_info ("the size of %s is %llu", name, disk->total_sectors);
211 return GRUB_ERR_NONE;
214 fail:
215 /* In GNU/Hurd, stat() will return the right size. */
216 #elif !defined (__GNU__)
217 # warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
218 #endif
219 if (stat (map[drive].device, &st) < 0)
220 return grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", map[drive].device);
222 disk->total_sectors = st.st_size >> GRUB_DISK_SECTOR_BITS;
224 grub_util_info ("the size of %s is %lu", name, disk->total_sectors);
226 return GRUB_ERR_NONE;
229 #ifdef __linux__
230 static int
231 linux_find_partition (char *dev, unsigned long sector)
233 size_t len = strlen (dev);
234 const char *format;
235 char *p;
236 int i;
237 char real_dev[PATH_MAX];
239 strcpy(real_dev, dev);
241 if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0)
243 p = real_dev + len - 4;
244 format = "part%d";
246 else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
248 p = real_dev + len;
249 format = "p%d";
251 else
253 p = real_dev + len;
254 format = "%d";
257 for (i = 1; i < 10000; i++)
259 int fd;
260 struct hd_geometry hdg;
262 sprintf (p, format, i);
263 fd = open (real_dev, O_RDONLY);
264 if (fd == -1)
265 return 0;
267 if (ioctl (fd, HDIO_GETGEO, &hdg))
269 close (fd);
270 return 0;
273 close (fd);
275 if (hdg.start == sector)
277 strcpy (dev, real_dev);
278 return 1;
282 return 0;
284 #endif /* __linux__ */
286 static int
287 open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
289 int fd;
291 #ifdef O_LARGEFILE
292 flags |= O_LARGEFILE;
293 #endif
294 #ifdef O_SYNC
295 flags |= O_SYNC;
296 #endif
297 #ifdef O_FSYNC
298 flags |= O_FSYNC;
299 #endif
300 #ifdef O_BINARY
301 flags |= O_BINARY;
302 #endif
304 #ifdef __linux__
305 /* Linux has a bug that the disk cache for a whole disk is not consistent
306 with the one for a partition of the disk. */
308 int is_partition = 0;
309 char dev[PATH_MAX];
311 strcpy (dev, map[disk->id].device);
312 if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
313 is_partition = linux_find_partition (dev, disk->partition->start);
315 /* Open the partition. */
316 grub_dprintf ("hostdisk", "opening the device `%s' in open_device()", dev);
317 fd = open (dev, flags);
318 if (fd < 0)
320 grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", dev);
321 return -1;
324 /* Make the buffer cache consistent with the physical disk. */
325 ioctl (fd, BLKFLSBUF, 0);
327 if (is_partition)
328 sector -= disk->partition->start;
330 #else /* ! __linux__ */
331 fd = open (map[disk->id].device, flags);
332 if (fd < 0)
334 grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' in open_device()", map[disk->id].device);
335 return -1;
337 #endif /* ! __linux__ */
339 #if defined(__linux__) && (!defined(__GLIBC__) || \
340 ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
341 /* Maybe libc doesn't have large file support. */
343 loff_t offset, result;
344 static int _llseek (uint filedes, ulong hi, ulong lo,
345 loff_t *res, uint wh);
346 _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
347 loff_t *, res, uint, wh);
349 offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
350 if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
352 grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
353 close (fd);
354 return -1;
357 #else
359 off_t offset = (off_t) sector << GRUB_DISK_SECTOR_BITS;
361 if (lseek (fd, offset, SEEK_SET) != offset)
363 grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
364 close (fd);
365 return -1;
368 #endif
370 return fd;
373 /* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
374 error occurs, otherwise return LEN. */
375 static ssize_t
376 nread (int fd, char *buf, size_t len)
378 ssize_t size = len;
380 while (len)
382 ssize_t ret = read (fd, buf, len);
384 if (ret <= 0)
386 if (errno == EINTR)
387 continue;
388 else
389 return ret;
392 len -= ret;
393 buf += ret;
396 return size;
399 /* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
400 error occurs, otherwise return LEN. */
401 static ssize_t
402 nwrite (int fd, const char *buf, size_t len)
404 ssize_t size = len;
406 while (len)
408 ssize_t ret = write (fd, buf, len);
410 if (ret <= 0)
412 if (errno == EINTR)
413 continue;
414 else
415 return ret;
418 len -= ret;
419 buf += ret;
422 return size;
425 static grub_err_t
426 grub_util_biosdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
427 grub_size_t size, char *buf)
429 int fd;
431 fd = open_device (disk, sector, O_RDONLY);
432 if (fd < 0)
433 return grub_errno;
435 #ifdef __linux__
436 if (sector == 0 && size > 1)
438 /* Work around a bug in Linux ez remapping. Linux remaps all
439 sectors that are read together with the MBR in one read. It
440 should only remap the MBR, so we split the read in two
441 parts. -jochen */
442 if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE)
444 grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
445 close (fd);
446 return grub_errno;
449 buf += GRUB_DISK_SECTOR_SIZE;
450 size--;
452 #endif /* __linux__ */
454 if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS)
455 != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
456 grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
458 close (fd);
459 return grub_errno;
462 static grub_err_t
463 grub_util_biosdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
464 grub_size_t size, const char *buf)
466 int fd;
468 fd = open_device (disk, sector, O_WRONLY);
469 if (fd < 0)
470 return grub_errno;
472 if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS)
473 != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
474 grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
476 close (fd);
477 return grub_errno;
480 static struct grub_disk_dev grub_util_biosdisk_dev =
482 .name = "biosdisk",
483 .id = GRUB_DISK_DEVICE_BIOSDISK_ID,
484 .iterate = grub_util_biosdisk_iterate,
485 .open = grub_util_biosdisk_open,
486 .close = 0,
487 .read = grub_util_biosdisk_read,
488 .write = grub_util_biosdisk_write,
489 .next = 0
492 static void
493 read_device_map (const char *dev_map)
495 FILE *fp;
496 char buf[1024]; /* XXX */
497 int lineno = 0;
498 struct stat st;
500 auto void show_error (const char *msg);
501 void show_error (const char *msg)
503 grub_util_error ("%s:%d: %s", dev_map, lineno, msg);
506 fp = fopen (dev_map, "r");
507 if (! fp)
508 grub_util_error ("Cannot open `%s'", dev_map);
510 while (fgets (buf, sizeof (buf), fp))
512 char *p = buf;
513 char *e;
514 int drive;
516 lineno++;
518 /* Skip leading spaces. */
519 while (*p && isspace (*p))
520 p++;
522 /* If the first character is `#' or NUL, skip this line. */
523 if (*p == '\0' || *p == '#')
524 continue;
526 if (*p != '(')
527 show_error ("No open parenthesis found");
529 p++;
530 /* Find a free slot. */
531 drive = find_free_slot ();
532 if (drive < 0)
533 show_error ("Map table size exceeded");
535 e = p;
536 p = strchr (p, ')');
537 if (! p)
538 show_error ("No close parenthesis found");
540 map[drive].drive = xmalloc (p - e + sizeof ('\0'));
541 strncpy (map[drive].drive, e, p - e + sizeof ('\0'));
542 map[drive].drive[p - e] = '\0';
544 p++;
545 /* Skip leading spaces. */
546 while (*p && isspace (*p))
547 p++;
549 if (*p == '\0')
550 show_error ("No filename found");
552 /* NUL-terminate the filename. */
553 e = p;
554 while (*e && ! isspace (*e))
555 e++;
556 *e = '\0';
558 if (stat (p, &st) == -1)
560 free (map[drive].drive);
561 map[drive].drive = NULL;
562 grub_util_info ("Cannot stat `%s', skipping", p);
563 continue;
566 #ifdef __linux__
567 /* On Linux, the devfs uses symbolic links horribly, and that
568 confuses the interface very much, so use realpath to expand
569 symbolic links. */
570 map[drive].device = xmalloc (PATH_MAX);
571 if (! realpath (p, map[drive].device))
572 grub_util_error ("Cannot get the real path of `%s'", p);
573 #else
574 map[drive].device = xstrdup (p);
575 #endif
578 fclose (fp);
581 void
582 grub_util_biosdisk_init (const char *dev_map)
584 read_device_map (dev_map);
585 grub_disk_dev_register (&grub_util_biosdisk_dev);
588 void
589 grub_util_biosdisk_fini (void)
591 unsigned i;
593 for (i = 0; i < sizeof (map) / sizeof (map[0]); i++)
595 if (map[i].drive)
596 free (map[i].drive);
597 if (map[i].device)
598 free (map[i].device);
599 map[i].drive = map[i].device = NULL;
602 grub_disk_dev_unregister (&grub_util_biosdisk_dev);
605 static char *
606 make_device_name (int drive, int dos_part, int bsd_part)
608 char *p;
610 p = xmalloc (30);
611 sprintf (p, "%s", map[drive].drive);
613 if (dos_part >= 0)
614 sprintf (p + strlen (p), ",%d", dos_part + 1);
616 if (bsd_part >= 0)
617 sprintf (p + strlen (p), ",%c", bsd_part + 'a');
619 return p;
622 static char *
623 convert_system_partition_to_system_disk (const char *os_dev)
625 #if defined(__linux__)
626 char *path = xmalloc (PATH_MAX);
627 if (! realpath (os_dev, path))
628 return 0;
630 if (strncmp ("/dev/", path, 5) == 0)
632 char *p = path + 5;
634 /* If this is an IDE disk. */
635 if (strncmp ("ide/", p, 4) == 0)
637 p = strstr (p, "part");
638 if (p)
639 strcpy (p, "disc");
641 return path;
644 /* If this is a SCSI disk. */
645 if (strncmp ("scsi/", p, 5) == 0)
647 p = strstr (p, "part");
648 if (p)
649 strcpy (p, "disc");
651 return path;
654 /* If this is a DAC960 disk. */
655 if (strncmp ("rd/c", p, 4) == 0)
657 /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
658 p = strchr (p, 'p');
659 if (p)
660 *p = '\0';
662 return path;
665 /* If this is a CCISS disk. */
666 if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
668 /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
669 p = strchr (p, 'p');
670 if (p)
671 *p = '\0';
673 return path;
676 /* If this is a Compaq Intelligent Drive Array. */
677 if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
679 /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
680 p = strchr (p, 'p');
681 if (p)
682 *p = '\0';
684 return path;
687 /* If this is an I2O disk. */
688 if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
690 /* /dev/i2o/hd[a-z]([0-9]+)? */
691 p[sizeof ("i2o/hda") - 1] = '\0';
692 return path;
695 /* If this is a MultiMediaCard (MMC). */
696 if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
698 /* /dev/mmcblk[0-9]+(p[0-9]+)? */
699 p = strchr (p, 'p');
700 if (p)
701 *p = '\0';
703 return path;
706 /* If this is an IDE, SCSI or Virtio disk. */
707 if ((strncmp ("hd", p, 2) == 0
708 || strncmp ("vd", p, 2) == 0
709 || strncmp ("sd", p, 2) == 0)
710 && p[2] >= 'a' && p[2] <= 'z')
712 /* /dev/[hsv]d[a-z][0-9]* */
713 p[3] = '\0';
714 return path;
717 /* If this is a Xen virtual block device. */
718 if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
720 /* /dev/xvd[a-z][0-9]* */
721 p[4] = '\0';
722 return path;
726 return path;
728 #elif defined(__GNU__)
729 char *path = xstrdup (os_dev);
730 if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
732 char *p = strchr (path + 7, 's');
733 if (p)
734 *p = '\0';
736 return path;
738 #elif defined(__CYGWIN__)
739 char *path = xstrdup (os_dev);
740 if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
741 path[8] = 0;
742 return path;
744 #else
745 # warning "The function `convert_system_partition_to_system_disk' might not work on your OS correctly."
746 return xstrdup (os_dev);
747 #endif
750 static int
751 find_system_device (const char *os_dev)
753 int i;
754 char *os_disk;
756 os_disk = convert_system_partition_to_system_disk (os_dev);
757 if (! os_disk)
758 return -1;
760 for (i = 0; i < (int) (sizeof (map) / sizeof (map[0])); i++)
761 if (map[i].device && strcmp (map[i].device, os_disk) == 0)
763 free (os_disk);
764 return i;
767 free (os_disk);
768 return -1;
771 char *
772 grub_util_biosdisk_get_grub_dev (const char *os_dev)
774 struct stat st;
775 int drive;
777 if (stat (os_dev, &st) < 0)
779 grub_error (GRUB_ERR_BAD_DEVICE, "cannot stat `%s'", os_dev);
780 return 0;
783 drive = find_system_device (os_dev);
784 if (drive < 0)
786 grub_error (GRUB_ERR_BAD_DEVICE,
787 "no mapping exists for `%s'", os_dev);
788 return 0;
791 if (! S_ISBLK (st.st_mode))
792 return make_device_name (drive, -1, -1);
794 #if defined(__linux__) || defined(__CYGWIN__)
795 /* Linux counts partitions uniformly, whether a BSD partition or a DOS
796 partition, so mapping them to GRUB devices is not trivial.
797 Here, get the start sector of a partition by HDIO_GETGEO, and
798 compare it with each partition GRUB recognizes.
800 Cygwin /dev/sdXN emulation uses Windows partition mapping. It
801 does not count the extended partition and missing primary
802 partitions. Use same method as on Linux here. */
804 char *name;
805 grub_disk_t disk;
806 int fd;
807 struct hd_geometry hdg;
808 int dos_part = -1;
809 int bsd_part = -1;
810 auto int find_partition (grub_disk_t disk,
811 const grub_partition_t partition);
813 int find_partition (grub_disk_t disk __attribute__ ((unused)),
814 const grub_partition_t partition)
816 struct grub_pc_partition *pcdata = NULL;
818 if (strcmp (partition->partmap->name, "pc_partition_map") == 0)
819 pcdata = partition->data;
821 if (pcdata)
823 if (pcdata->bsd_part < 0)
824 grub_util_info ("DOS partition %d starts from %lu",
825 pcdata->dos_part, partition->start);
826 else
827 grub_util_info ("BSD partition %d,%c starts from %lu",
828 pcdata->dos_part, pcdata->bsd_part + 'a',
829 partition->start);
831 else
833 grub_util_info ("Partition %d starts from %lu",
834 partition->index, partition->start);
837 if (hdg.start == partition->start)
839 if (pcdata)
841 dos_part = pcdata->dos_part;
842 bsd_part = pcdata->bsd_part;
844 else
846 dos_part = partition->index;
847 bsd_part = -1;
849 return 1;
852 return 0;
855 name = make_device_name (drive, -1, -1);
857 if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
858 return name;
860 fd = open (os_dev, O_RDONLY);
861 if (fd == -1)
863 grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", os_dev);
864 free (name);
865 return 0;
868 if (ioctl (fd, HDIO_GETGEO, &hdg))
870 grub_error (GRUB_ERR_BAD_DEVICE,
871 "cannot get geometry of `%s'", os_dev);
872 close (fd);
873 free (name);
874 return 0;
877 close (fd);
879 grub_util_info ("%s starts from %lu", os_dev, hdg.start);
881 if (hdg.start == 0)
882 return name;
884 grub_util_info ("opening the device %s", name);
885 disk = grub_disk_open (name);
886 free (name);
888 if (! disk)
889 return 0;
891 grub_partition_iterate (disk, find_partition);
892 if (grub_errno != GRUB_ERR_NONE)
894 grub_disk_close (disk);
895 return 0;
898 if (dos_part < 0)
900 grub_disk_close (disk);
901 grub_error (GRUB_ERR_BAD_DEVICE,
902 "cannot find the partition of `%s'", os_dev);
903 return 0;
906 return make_device_name (drive, dos_part, bsd_part);
909 #elif defined(__GNU__)
910 /* GNU uses "/dev/[hs]d[0-9]+(s[0-9]+[a-z]?)?". */
912 char *p;
913 int dos_part = -1;
914 int bsd_part = -1;
916 p = strrchr (os_dev, 's');
917 if (p)
919 long int n;
920 char *q;
922 p++;
923 n = strtol (p, &q, 10);
924 if (p != q && n != LONG_MIN && n != LONG_MAX)
926 dos_part = (int) n;
928 if (*q >= 'a' && *q <= 'g')
929 bsd_part = *q - 'a';
933 return make_device_name (drive, dos_part, bsd_part);
936 #else
937 # warning "The function `grub_util_biosdisk_get_grub_dev' might not work on your OS correctly."
938 return make_device_name (drive, -1, -1);
939 #endif