xref: /illumos-gate/usr/src/grub/grub-0.97/lib/device.c (revision 828d47c1)
17c478bd9Sstevel@tonic-gate /* device.c - Some helper functions for OS devices and BIOS drives */
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  *  GRUB  --  GRand Unified Bootloader
41b8adde7SWilliam Kucharski  *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005  Free Software Foundation, Inc.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate  *  it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate  *  the Free Software Foundation; either version 2 of the License, or
97c478bd9Sstevel@tonic-gate  *  (at your option) any later version.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  *  This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate  *  GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  *  You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate  *  along with this program; if not, write to the Free Software
187c478bd9Sstevel@tonic-gate  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197c478bd9Sstevel@tonic-gate  */
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate /* Try to use glibc's transparant LFS support. */
227c478bd9Sstevel@tonic-gate #define _LARGEFILE_SOURCE       1
237c478bd9Sstevel@tonic-gate /* lseek becomes synonymous with lseek64.  */
247c478bd9Sstevel@tonic-gate #define _FILE_OFFSET_BITS       64
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <stdio.h>
277c478bd9Sstevel@tonic-gate #include <stdlib.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <ctype.h>
307c478bd9Sstevel@tonic-gate #include <assert.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <errno.h>
367c478bd9Sstevel@tonic-gate #include <limits.h>
377c478bd9Sstevel@tonic-gate #include <stdarg.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #ifdef __linux__
407c478bd9Sstevel@tonic-gate # if !defined(__GLIBC__) || \
417c478bd9Sstevel@tonic-gate         ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
427c478bd9Sstevel@tonic-gate /* Maybe libc doesn't have large file support.  */
437c478bd9Sstevel@tonic-gate #  include <linux/unistd.h>     /* _llseek */
447c478bd9Sstevel@tonic-gate # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
457c478bd9Sstevel@tonic-gate # include <sys/ioctl.h>		/* ioctl */
467c478bd9Sstevel@tonic-gate # ifndef HDIO_GETGEO
477c478bd9Sstevel@tonic-gate #  define HDIO_GETGEO	0x0301	/* get device geometry */
487c478bd9Sstevel@tonic-gate /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
497c478bd9Sstevel@tonic-gate    defined.  */
507c478bd9Sstevel@tonic-gate struct hd_geometry
517c478bd9Sstevel@tonic-gate {
527c478bd9Sstevel@tonic-gate   unsigned char heads;
537c478bd9Sstevel@tonic-gate   unsigned char sectors;
547c478bd9Sstevel@tonic-gate   unsigned short cylinders;
557c478bd9Sstevel@tonic-gate   unsigned long start;
567c478bd9Sstevel@tonic-gate };
577c478bd9Sstevel@tonic-gate # endif /* ! HDIO_GETGEO */
587c478bd9Sstevel@tonic-gate # ifndef FLOPPY_MAJOR
597c478bd9Sstevel@tonic-gate #  define FLOPPY_MAJOR	2	/* the major number for floppy */
607c478bd9Sstevel@tonic-gate # endif /* ! FLOPPY_MAJOR */
617c478bd9Sstevel@tonic-gate # ifndef MAJOR
627c478bd9Sstevel@tonic-gate #  define MAJOR(dev)	\
637c478bd9Sstevel@tonic-gate   ({ \
647c478bd9Sstevel@tonic-gate      unsigned long long __dev = (dev); \
657c478bd9Sstevel@tonic-gate      (unsigned) ((__dev >> 8) & 0xfff) \
667c478bd9Sstevel@tonic-gate                  | ((unsigned int) (__dev >> 32) & ~0xfff); \
677c478bd9Sstevel@tonic-gate   })
687c478bd9Sstevel@tonic-gate # endif /* ! MAJOR */
697c478bd9Sstevel@tonic-gate # ifndef CDROM_GET_CAPABILITY
707c478bd9Sstevel@tonic-gate #  define CDROM_GET_CAPABILITY	0x5331	/* get capabilities */
717c478bd9Sstevel@tonic-gate # endif /* ! CDROM_GET_CAPABILITY */
727c478bd9Sstevel@tonic-gate # ifndef BLKGETSIZE
737c478bd9Sstevel@tonic-gate #  define BLKGETSIZE	_IO(0x12,96)	/* return device size */
747c478bd9Sstevel@tonic-gate # endif /* ! BLKGETSIZE */
757c478bd9Sstevel@tonic-gate #endif /* __linux__ */
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
787c478bd9Sstevel@tonic-gate    kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
797c478bd9Sstevel@tonic-gate #if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
807c478bd9Sstevel@tonic-gate # define __FreeBSD_kernel__
817c478bd9Sstevel@tonic-gate #endif
827c478bd9Sstevel@tonic-gate #ifdef __FreeBSD_kernel__
837c478bd9Sstevel@tonic-gate   /* Obtain version of kFreeBSD headers */
847c478bd9Sstevel@tonic-gate # include <osreldate.h>
857c478bd9Sstevel@tonic-gate # ifndef __FreeBSD_kernel_version
867c478bd9Sstevel@tonic-gate #  define __FreeBSD_kernel_version __FreeBSD_version
877c478bd9Sstevel@tonic-gate # endif
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate   /* Runtime detection of kernel */
907c478bd9Sstevel@tonic-gate # include <sys/utsname.h>
917c478bd9Sstevel@tonic-gate int
get_kfreebsd_version()927c478bd9Sstevel@tonic-gate get_kfreebsd_version ()
937c478bd9Sstevel@tonic-gate {
947c478bd9Sstevel@tonic-gate   struct utsname uts;
957c478bd9Sstevel@tonic-gate   int major; int minor, v[2];
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate   uname (&uts);
987c478bd9Sstevel@tonic-gate   sscanf (uts.release, "%d.%d", &major, &minor);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate   if (major >= 9)
1017c478bd9Sstevel@tonic-gate     major = 9;
1027c478bd9Sstevel@tonic-gate   if (major >= 5)
1037c478bd9Sstevel@tonic-gate     {
1047c478bd9Sstevel@tonic-gate       v[0] = minor/10; v[1] = minor%10;
1057c478bd9Sstevel@tonic-gate     }
1067c478bd9Sstevel@tonic-gate   else
1077c478bd9Sstevel@tonic-gate     {
1087c478bd9Sstevel@tonic-gate       v[0] = minor%10; v[1] = minor/10;
1097c478bd9Sstevel@tonic-gate     }
1107c478bd9Sstevel@tonic-gate   return major*100000+v[0]*10000+v[1]*1000;
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate #endif /* __FreeBSD_kernel__ */
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
1157c478bd9Sstevel@tonic-gate # include <sys/ioctl.h>		/* ioctl */
1167c478bd9Sstevel@tonic-gate # include <sys/disklabel.h>
1177c478bd9Sstevel@tonic-gate # include <sys/cdio.h>		/* CDIOCCLRDEBUG */
1187c478bd9Sstevel@tonic-gate # if defined(__FreeBSD_kernel__)
1197c478bd9Sstevel@tonic-gate #  include <sys/param.h>
1207c478bd9Sstevel@tonic-gate #  if __FreeBSD_kernel_version >= 500040
1217c478bd9Sstevel@tonic-gate #   include <sys/disk.h>
1227c478bd9Sstevel@tonic-gate #  endif
1237c478bd9Sstevel@tonic-gate # endif /* __FreeBSD_kernel__ */
1247c478bd9Sstevel@tonic-gate #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate #if defined(__sun)
1277c478bd9Sstevel@tonic-gate # include <sys/dkio.h>
1287c478bd9Sstevel@tonic-gate #endif /* __sun */
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate #ifdef HAVE_OPENDISK
1317c478bd9Sstevel@tonic-gate # include <util.h>
1327c478bd9Sstevel@tonic-gate #endif /* HAVE_OPENDISK */
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate #define WITHOUT_LIBC_STUBS	1
1357c478bd9Sstevel@tonic-gate #include <shared.h>
1367c478bd9Sstevel@tonic-gate #include <device.h>
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /* Get the geometry of a drive DRIVE.  */
1397c478bd9Sstevel@tonic-gate void
get_drive_geometry(struct geometry * geom,char ** map,int drive)1407c478bd9Sstevel@tonic-gate get_drive_geometry (struct geometry *geom, char **map, int drive)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate   int fd;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate   if (geom->flags == -1)
1457c478bd9Sstevel@tonic-gate     {
1467c478bd9Sstevel@tonic-gate       fd = open (map[drive], O_RDONLY);
1477c478bd9Sstevel@tonic-gate       assert (fd >= 0);
1487c478bd9Sstevel@tonic-gate     }
1497c478bd9Sstevel@tonic-gate   else
1507c478bd9Sstevel@tonic-gate     fd = geom->flags;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate   /* XXX This is the default size.  */
1537c478bd9Sstevel@tonic-gate   geom->sector_size = SECTOR_SIZE;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate #if defined(__linux__)
1567c478bd9Sstevel@tonic-gate   /* Linux */
1577c478bd9Sstevel@tonic-gate   {
1587c478bd9Sstevel@tonic-gate     struct hd_geometry hdg;
1597c478bd9Sstevel@tonic-gate     unsigned long nr;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate     if (ioctl (fd, HDIO_GETGEO, &hdg))
1627c478bd9Sstevel@tonic-gate       goto fail;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate     if (ioctl (fd, BLKGETSIZE, &nr))
1657c478bd9Sstevel@tonic-gate       goto fail;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate     /* Got the geometry, so save it. */
1687c478bd9Sstevel@tonic-gate     geom->cylinders = hdg.cylinders;
1697c478bd9Sstevel@tonic-gate     geom->heads = hdg.heads;
1707c478bd9Sstevel@tonic-gate     geom->sectors = hdg.sectors;
1717c478bd9Sstevel@tonic-gate     geom->total_sectors = nr;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate     goto success;
1747c478bd9Sstevel@tonic-gate   }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate #elif defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
1777c478bd9Sstevel@tonic-gate # if defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040
1787c478bd9Sstevel@tonic-gate   /* kFreeBSD version 5 or later */
1797c478bd9Sstevel@tonic-gate   if (get_kfreebsd_version () >= 500040)
1807c478bd9Sstevel@tonic-gate   {
1817c478bd9Sstevel@tonic-gate     unsigned int sector_size;
1827c478bd9Sstevel@tonic-gate     off_t media_size;
1837c478bd9Sstevel@tonic-gate     unsigned int tmp;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate     if(ioctl (fd, DIOCGSECTORSIZE, &sector_size) != 0)
1867c478bd9Sstevel@tonic-gate       sector_size = 512;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate     if (ioctl (fd, DIOCGMEDIASIZE, &media_size) != 0)
1897c478bd9Sstevel@tonic-gate       goto fail;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate     geom->total_sectors = media_size / sector_size;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate     if (ioctl (fd, DIOCGFWSECTORS, &tmp) == 0)
1947c478bd9Sstevel@tonic-gate       geom->sectors = tmp;
1957c478bd9Sstevel@tonic-gate     else
1967c478bd9Sstevel@tonic-gate       geom->sectors = 63;
1977c478bd9Sstevel@tonic-gate     if (ioctl (fd, DIOCGFWHEADS, &tmp) == 0)
1987c478bd9Sstevel@tonic-gate       geom->heads = tmp;
1997c478bd9Sstevel@tonic-gate     else if (geom->total_sectors <= 63 * 1 * 1024)
2007c478bd9Sstevel@tonic-gate       geom->heads = 1;
2017c478bd9Sstevel@tonic-gate     else if (geom->total_sectors <= 63 * 16 * 1024)
2027c478bd9Sstevel@tonic-gate       geom->heads = 16;
2037c478bd9Sstevel@tonic-gate     else
2047c478bd9Sstevel@tonic-gate       geom->heads = 255;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate     geom->cylinders = (geom->total_sectors
2077c478bd9Sstevel@tonic-gate 			   / geom->heads
2087c478bd9Sstevel@tonic-gate 			   / geom->sectors);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate     goto success;
2117c478bd9Sstevel@tonic-gate   }
2127c478bd9Sstevel@tonic-gate   else
2137c478bd9Sstevel@tonic-gate #endif /* defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040 */
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate   /* kFreeBSD < 5, NetBSD or OpenBSD */
2167c478bd9Sstevel@tonic-gate   {
2177c478bd9Sstevel@tonic-gate     struct disklabel hdg;
2187c478bd9Sstevel@tonic-gate     if (ioctl (fd, DIOCGDINFO, &hdg))
2197c478bd9Sstevel@tonic-gate       goto fail;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate     geom->cylinders = hdg.d_ncylinders;
2227c478bd9Sstevel@tonic-gate     geom->heads = hdg.d_ntracks;
2237c478bd9Sstevel@tonic-gate     geom->sectors = hdg.d_nsectors;
2247c478bd9Sstevel@tonic-gate     geom->total_sectors = hdg.d_secperunit;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate     goto success;
2277c478bd9Sstevel@tonic-gate   }
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate #elif defined(__sun)
2307c478bd9Sstevel@tonic-gate   /* Solaris */
2317c478bd9Sstevel@tonic-gate   {
2327c478bd9Sstevel@tonic-gate     struct dk_geom dkg;
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate     if (ioctl(fd, DKIOCG_PHYGEOM, &dkg))
2357c478bd9Sstevel@tonic-gate       goto fail;
2367c478bd9Sstevel@tonic-gate     geom->cylinders = dkg.dkg_ncyl;
2377c478bd9Sstevel@tonic-gate     geom->heads = dkg.dkg_nhead;
2387c478bd9Sstevel@tonic-gate     geom->sectors = dkg.dkg_nsect;
239*828d47c1SShidokht Yadegari     geom->total_sectors = (unsigned long long)dkg.dkg_ncyl * dkg.dkg_nhead
240*828d47c1SShidokht Yadegari 	* dkg.dkg_nsect;
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate     goto success;
2437c478bd9Sstevel@tonic-gate   }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate #else
2467c478bd9Sstevel@tonic-gate   /* Notably, defined(__GNU__) */
2477c478bd9Sstevel@tonic-gate # warning "Automatic detection of geometries will be performed only \
2487c478bd9Sstevel@tonic-gate partially. This is not fatal."
2497c478bd9Sstevel@tonic-gate #endif
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate  fail:
2527c478bd9Sstevel@tonic-gate   {
2537c478bd9Sstevel@tonic-gate     struct stat st;
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate     /* FIXME: It would be nice to somehow compute fake C/H/S settings,
2567c478bd9Sstevel@tonic-gate        given a proper st_blocks size. */
2577c478bd9Sstevel@tonic-gate     if (drive & 0x80)
2587c478bd9Sstevel@tonic-gate       {
2597c478bd9Sstevel@tonic-gate 	geom->cylinders = DEFAULT_HD_CYLINDERS;
2607c478bd9Sstevel@tonic-gate 	geom->heads = DEFAULT_HD_HEADS;
2617c478bd9Sstevel@tonic-gate 	geom->sectors = DEFAULT_HD_SECTORS;
2627c478bd9Sstevel@tonic-gate       }
2637c478bd9Sstevel@tonic-gate     else
2647c478bd9Sstevel@tonic-gate       {
2657c478bd9Sstevel@tonic-gate 	geom->cylinders = DEFAULT_FD_CYLINDERS;
2667c478bd9Sstevel@tonic-gate 	geom->heads = DEFAULT_FD_HEADS;
2677c478bd9Sstevel@tonic-gate 	geom->sectors = DEFAULT_FD_SECTORS;
2687c478bd9Sstevel@tonic-gate       }
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate     /* Set the total sectors properly, if we can. */
2717c478bd9Sstevel@tonic-gate     if (! fstat (fd, &st) && st.st_blocks)
2721b8adde7SWilliam Kucharski       geom->total_sectors = st.st_blocks >> SECTOR_BITS;
2737c478bd9Sstevel@tonic-gate     else
274*828d47c1SShidokht Yadegari       geom->total_sectors = (unsigned long long)geom->cylinders *
275*828d47c1SShidokht Yadegari 	geom->heads * geom->sectors;
2767c478bd9Sstevel@tonic-gate   }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate  success:
2797c478bd9Sstevel@tonic-gate   if (geom->flags == -1)
2807c478bd9Sstevel@tonic-gate     close (fd);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate #ifdef __linux__
2847c478bd9Sstevel@tonic-gate /* Check if we have devfs support.  */
2857c478bd9Sstevel@tonic-gate static int
have_devfs(void)2867c478bd9Sstevel@tonic-gate have_devfs (void)
2877c478bd9Sstevel@tonic-gate {
2887c478bd9Sstevel@tonic-gate   static int dev_devfsd_exists = -1;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate   if (dev_devfsd_exists < 0)
2917c478bd9Sstevel@tonic-gate     {
2927c478bd9Sstevel@tonic-gate       struct stat st;
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate       dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
2957c478bd9Sstevel@tonic-gate     }
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate   return dev_devfsd_exists;
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate #endif /* __linux__ */
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate /* These three functions are quite different among OSes.  */
3027c478bd9Sstevel@tonic-gate static void
get_floppy_disk_name(char * name,int unit)3037c478bd9Sstevel@tonic-gate get_floppy_disk_name (char *name, int unit)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate #if defined(__linux__)
3067c478bd9Sstevel@tonic-gate   /* GNU/Linux */
3077c478bd9Sstevel@tonic-gate   if (have_devfs ())
3087c478bd9Sstevel@tonic-gate     sprintf (name, "/dev/floppy/%d", unit);
3097c478bd9Sstevel@tonic-gate   else
3107c478bd9Sstevel@tonic-gate     sprintf (name, "/dev/fd%d", unit);
3117c478bd9Sstevel@tonic-gate #elif defined(__GNU__)
3127c478bd9Sstevel@tonic-gate   /* GNU/Hurd */
3137c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/fd%d", unit);
3147c478bd9Sstevel@tonic-gate #elif defined(__FreeBSD_kernel__)
3157c478bd9Sstevel@tonic-gate   /* kFreeBSD */
3167c478bd9Sstevel@tonic-gate   if (get_kfreebsd_version () >= 400000)
3177c478bd9Sstevel@tonic-gate     sprintf (name, "/dev/fd%d", unit);
3187c478bd9Sstevel@tonic-gate   else
3197c478bd9Sstevel@tonic-gate     sprintf (name, "/dev/rfd%d", unit);
3207c478bd9Sstevel@tonic-gate #elif defined(__NetBSD__)
3217c478bd9Sstevel@tonic-gate   /* NetBSD */
3227c478bd9Sstevel@tonic-gate   /* opendisk() doesn't work for floppies.  */
3237c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/rfd%da", unit);
3247c478bd9Sstevel@tonic-gate #elif defined(__OpenBSD__)
3257c478bd9Sstevel@tonic-gate   /* OpenBSD */
3267c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/rfd%dc", unit);
3277c478bd9Sstevel@tonic-gate #elif defined(__QNXNTO__)
3287c478bd9Sstevel@tonic-gate   /* QNX RTP */
3297c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/fd%d", unit);
3307c478bd9Sstevel@tonic-gate #elif defined(__sun)
3317c478bd9Sstevel@tonic-gate   /* Solaris */
3327c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/rdiskette%d", unit);
3337c478bd9Sstevel@tonic-gate #else
3347c478bd9Sstevel@tonic-gate # warning "BIOS floppy drives cannot be guessed in your operating system."
3357c478bd9Sstevel@tonic-gate   /* Set NAME to a bogus string.  */
3367c478bd9Sstevel@tonic-gate   *name = 0;
3377c478bd9Sstevel@tonic-gate #endif
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate static void
get_ide_disk_name(char * name,int unit)3417c478bd9Sstevel@tonic-gate get_ide_disk_name (char *name, int unit)
3427c478bd9Sstevel@tonic-gate {
3437c478bd9Sstevel@tonic-gate #if defined(__linux__)
3447c478bd9Sstevel@tonic-gate   /* GNU/Linux */
3457c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/hd%c", unit + 'a');
3467c478bd9Sstevel@tonic-gate #elif defined(__GNU__)
3477c478bd9Sstevel@tonic-gate   /* GNU/Hurd */
3487c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/hd%d", unit);
3497c478bd9Sstevel@tonic-gate #elif defined(__FreeBSD_kernel__)
3507c478bd9Sstevel@tonic-gate   /* kFreeBSD */
3517c478bd9Sstevel@tonic-gate   if (get_kfreebsd_version () >= 400000)
3527c478bd9Sstevel@tonic-gate     sprintf (name, "/dev/ad%d", unit);
3537c478bd9Sstevel@tonic-gate   else
3547c478bd9Sstevel@tonic-gate     sprintf (name, "/dev/rwd%d", unit);
3557c478bd9Sstevel@tonic-gate #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
3567c478bd9Sstevel@tonic-gate   /* NetBSD */
3577c478bd9Sstevel@tonic-gate   char shortname[16];
3587c478bd9Sstevel@tonic-gate   int fd;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate   sprintf (shortname, "wd%d", unit);
3617c478bd9Sstevel@tonic-gate   fd = opendisk (shortname, O_RDONLY, name,
3627c478bd9Sstevel@tonic-gate 		 16,	/* length of NAME */
3637c478bd9Sstevel@tonic-gate 		 0	/* char device */
3647c478bd9Sstevel@tonic-gate 		 );
3657c478bd9Sstevel@tonic-gate   close (fd);
3667c478bd9Sstevel@tonic-gate #elif defined(__OpenBSD__)
3677c478bd9Sstevel@tonic-gate   /* OpenBSD */
3687c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/rwd%dc", unit);
3697c478bd9Sstevel@tonic-gate #elif defined(__QNXNTO__)
3707c478bd9Sstevel@tonic-gate   /* QNX RTP */
3717c478bd9Sstevel@tonic-gate   /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
3727c478bd9Sstevel@tonic-gate      contain SCSI disks.  */
3737c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/hd%d", unit);
3747c478bd9Sstevel@tonic-gate #elif defined(__sun)
3757c478bd9Sstevel@tonic-gate   *name = 0;		/* FIXME */
3767c478bd9Sstevel@tonic-gate #else
3777c478bd9Sstevel@tonic-gate # warning "BIOS IDE drives cannot be guessed in your operating system."
3787c478bd9Sstevel@tonic-gate   /* Set NAME to a bogus string.  */
3797c478bd9Sstevel@tonic-gate   *name = 0;
3807c478bd9Sstevel@tonic-gate #endif
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate static void
get_scsi_disk_name(char * name,int unit)3847c478bd9Sstevel@tonic-gate get_scsi_disk_name (char *name, int unit)
3857c478bd9Sstevel@tonic-gate {
3867c478bd9Sstevel@tonic-gate #if defined(__linux__)
3877c478bd9Sstevel@tonic-gate   /* GNU/Linux */
3887c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/sd%c", unit + 'a');
3897c478bd9Sstevel@tonic-gate #elif defined(__GNU__)
3907c478bd9Sstevel@tonic-gate   /* GNU/Hurd */
3917c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/sd%d", unit);
3927c478bd9Sstevel@tonic-gate #elif defined(__FreeBSD_kernel__)
3937c478bd9Sstevel@tonic-gate   /* kFreeBSD */
3947c478bd9Sstevel@tonic-gate   if (get_kfreebsd_version () >= 400000)
3957c478bd9Sstevel@tonic-gate     sprintf (name, "/dev/da%d", unit);
3967c478bd9Sstevel@tonic-gate   else
3977c478bd9Sstevel@tonic-gate     sprintf (name, "/dev/rda%d", unit);
3987c478bd9Sstevel@tonic-gate #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
3997c478bd9Sstevel@tonic-gate   /* NetBSD */
4007c478bd9Sstevel@tonic-gate   char shortname[16];
4017c478bd9Sstevel@tonic-gate   int fd;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate   sprintf (shortname, "sd%d", unit);
4047c478bd9Sstevel@tonic-gate   fd = opendisk (shortname, O_RDONLY, name,
4057c478bd9Sstevel@tonic-gate 		 16,	/* length of NAME */
4067c478bd9Sstevel@tonic-gate 		 0	/* char device */
4077c478bd9Sstevel@tonic-gate 		 );
4087c478bd9Sstevel@tonic-gate   close (fd);
4097c478bd9Sstevel@tonic-gate #elif defined(__OpenBSD__)
4107c478bd9Sstevel@tonic-gate   /* OpenBSD */
4117c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/rsd%dc", unit);
4127c478bd9Sstevel@tonic-gate #elif defined(__QNXNTO__)
4137c478bd9Sstevel@tonic-gate   /* QNX RTP */
4147c478bd9Sstevel@tonic-gate   /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
4157c478bd9Sstevel@tonic-gate      disable the detection of SCSI disks here.  */
4167c478bd9Sstevel@tonic-gate   *name = 0;
4177c478bd9Sstevel@tonic-gate #elif defined(__sun)
4187c478bd9Sstevel@tonic-gate   *name = 0;		/* FIXME */
4197c478bd9Sstevel@tonic-gate #else
4207c478bd9Sstevel@tonic-gate # warning "BIOS SCSI drives cannot be guessed in your operating system."
4217c478bd9Sstevel@tonic-gate   /* Set NAME to a bogus string.  */
4227c478bd9Sstevel@tonic-gate   *name = 0;
4237c478bd9Sstevel@tonic-gate #endif
4247c478bd9Sstevel@tonic-gate }
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate #ifdef __linux__
4277c478bd9Sstevel@tonic-gate static void
get_dac960_disk_name(char * name,int controller,int drive)4287c478bd9Sstevel@tonic-gate get_dac960_disk_name (char *name, int controller, int drive)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/rd/c%dd%d", controller, drive);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate static void
get_ataraid_disk_name(char * name,int unit)4347c478bd9Sstevel@tonic-gate get_ataraid_disk_name (char *name, int unit)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate   sprintf (name, "/dev/ataraid/d%c", unit + '0');
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate #endif
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate /* Check if DEVICE can be read. If an error occurs, return zero,
4417c478bd9Sstevel@tonic-gate    otherwise return non-zero.  */
4427c478bd9Sstevel@tonic-gate int
check_device(const char * device)4437c478bd9Sstevel@tonic-gate check_device (const char *device)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate   char buf[512];
4467c478bd9Sstevel@tonic-gate   FILE *fp;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate   /* If DEVICE is empty, just return 1.  */
4497c478bd9Sstevel@tonic-gate   if (*device == 0)
4507c478bd9Sstevel@tonic-gate     return 1;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate   fp = fopen (device, "r");
4537c478bd9Sstevel@tonic-gate   if (! fp)
4547c478bd9Sstevel@tonic-gate     {
4557c478bd9Sstevel@tonic-gate       switch (errno)
4567c478bd9Sstevel@tonic-gate 	{
4577c478bd9Sstevel@tonic-gate #ifdef ENOMEDIUM
4587c478bd9Sstevel@tonic-gate 	case ENOMEDIUM:
4597c478bd9Sstevel@tonic-gate # if 0
4607c478bd9Sstevel@tonic-gate 	  /* At the moment, this finds only CDROMs, which can't be
4617c478bd9Sstevel@tonic-gate 	     read anyway, so leave it out. Code should be
4627c478bd9Sstevel@tonic-gate 	     reactivated if `removable disks' and CDROMs are
4637c478bd9Sstevel@tonic-gate 	     supported.  */
4647c478bd9Sstevel@tonic-gate 	  /* Accept it, it may be inserted.  */
4657c478bd9Sstevel@tonic-gate 	  return 1;
4667c478bd9Sstevel@tonic-gate # endif
4677c478bd9Sstevel@tonic-gate 	  break;
4687c478bd9Sstevel@tonic-gate #endif /* ENOMEDIUM */
4697c478bd9Sstevel@tonic-gate 	default:
4707c478bd9Sstevel@tonic-gate 	  /* Break case and leave.  */
4717c478bd9Sstevel@tonic-gate 	  break;
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate       /* Error opening the device.  */
4747c478bd9Sstevel@tonic-gate       return 0;
4757c478bd9Sstevel@tonic-gate     }
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate   /* Make sure CD-ROMs don't get assigned a BIOS disk number
4787c478bd9Sstevel@tonic-gate      before SCSI disks!  */
4797c478bd9Sstevel@tonic-gate #ifdef __linux__
4807c478bd9Sstevel@tonic-gate # ifdef CDROM_GET_CAPABILITY
4817c478bd9Sstevel@tonic-gate   if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
4827c478bd9Sstevel@tonic-gate     return 0;
4837c478bd9Sstevel@tonic-gate # else /* ! CDROM_GET_CAPABILITY */
4847c478bd9Sstevel@tonic-gate   /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl.  */
4857c478bd9Sstevel@tonic-gate   {
4867c478bd9Sstevel@tonic-gate     struct hd_geometry hdg;
4877c478bd9Sstevel@tonic-gate     struct stat st;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate     if (fstat (fileno (fp), &st))
4907c478bd9Sstevel@tonic-gate       return 0;
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate     /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
4937c478bd9Sstevel@tonic-gate        succeeds.  */
4947c478bd9Sstevel@tonic-gate     if (S_ISBLK (st.st_mode)
4957c478bd9Sstevel@tonic-gate 	&& MAJOR (st.st_rdev) != FLOPPY_MAJOR
4967c478bd9Sstevel@tonic-gate 	&& ioctl (fileno (fp), HDIO_GETGEO, &hdg))
4977c478bd9Sstevel@tonic-gate       return 0;
4987c478bd9Sstevel@tonic-gate   }
4997c478bd9Sstevel@tonic-gate # endif /* ! CDROM_GET_CAPABILITY */
5007c478bd9Sstevel@tonic-gate #endif /* __linux__ */
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
5037c478bd9Sstevel@tonic-gate # ifdef CDIOCCLRDEBUG
5047c478bd9Sstevel@tonic-gate   if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
5057c478bd9Sstevel@tonic-gate     return 0;
5067c478bd9Sstevel@tonic-gate # endif /* CDIOCCLRDEBUG */
5077c478bd9Sstevel@tonic-gate #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate   /* Attempt to read the first sector.  */
5107c478bd9Sstevel@tonic-gate   if (fread (buf, 1, 512, fp) != 512)
5117c478bd9Sstevel@tonic-gate     {
5127c478bd9Sstevel@tonic-gate       fclose (fp);
5137c478bd9Sstevel@tonic-gate       return 0;
5147c478bd9Sstevel@tonic-gate     }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate   fclose (fp);
5177c478bd9Sstevel@tonic-gate   return 1;
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate /* Read mapping information from FP, and write it to MAP.  */
5217c478bd9Sstevel@tonic-gate static int
read_device_map(FILE * fp,char ** map,const char * map_file)5227c478bd9Sstevel@tonic-gate read_device_map (FILE *fp, char **map, const char *map_file)
5237c478bd9Sstevel@tonic-gate {
5241b8adde7SWilliam Kucharski   auto void show_error (int no, const char *msg);
5251b8adde7SWilliam Kucharski   auto void show_warning (int no, const char *msg, ...);
5261b8adde7SWilliam Kucharski 
5271b8adde7SWilliam Kucharski   auto void show_error (int no, const char *msg)
5287c478bd9Sstevel@tonic-gate     {
5297c478bd9Sstevel@tonic-gate       fprintf (stderr, "%s:%d: error: %s\n", map_file, no, msg);
5307c478bd9Sstevel@tonic-gate     }
5317c478bd9Sstevel@tonic-gate 
5321b8adde7SWilliam Kucharski   auto void show_warning (int no, const char *msg, ...)
5337c478bd9Sstevel@tonic-gate     {
5347c478bd9Sstevel@tonic-gate       va_list ap;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate       va_start (ap, msg);
5377c478bd9Sstevel@tonic-gate       fprintf (stderr, "%s:%d: warning: ", map_file, no);
5387c478bd9Sstevel@tonic-gate       vfprintf (stderr, msg, ap);
5397c478bd9Sstevel@tonic-gate       va_end (ap);
5407c478bd9Sstevel@tonic-gate     }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate   /* If there is the device map file, use the data in it instead of
5437c478bd9Sstevel@tonic-gate      probing devices.  */
5447c478bd9Sstevel@tonic-gate   char buf[1024];		/* XXX */
5457c478bd9Sstevel@tonic-gate   int line_number = 0;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate   while (fgets (buf, sizeof (buf), fp))
5487c478bd9Sstevel@tonic-gate     {
5497c478bd9Sstevel@tonic-gate       char *ptr, *eptr;
5507c478bd9Sstevel@tonic-gate       int drive;
5517c478bd9Sstevel@tonic-gate       int is_floppy = 0;
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate       /* Increase the number of lines.  */
5547c478bd9Sstevel@tonic-gate       line_number++;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate       /* If the first character is '#', skip it.  */
5577c478bd9Sstevel@tonic-gate       if (buf[0] == '#')
5587c478bd9Sstevel@tonic-gate 	continue;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate       ptr = buf;
5617c478bd9Sstevel@tonic-gate       /* Skip leading spaces.  */
5627c478bd9Sstevel@tonic-gate       while (*ptr && isspace (*ptr))
5637c478bd9Sstevel@tonic-gate 	ptr++;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate       /* Skip empty lines.  */
5667c478bd9Sstevel@tonic-gate       if (! *ptr)
5677c478bd9Sstevel@tonic-gate 	continue;
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate       if (*ptr != '(')
5707c478bd9Sstevel@tonic-gate 	{
5717c478bd9Sstevel@tonic-gate 	  show_error (line_number, "No open parenthesis found");
5727c478bd9Sstevel@tonic-gate 	  return 0;
5737c478bd9Sstevel@tonic-gate 	}
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate       ptr++;
5767c478bd9Sstevel@tonic-gate       if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd')
5777c478bd9Sstevel@tonic-gate 	{
5787c478bd9Sstevel@tonic-gate 	  show_error (line_number, "Bad drive name");
5797c478bd9Sstevel@tonic-gate 	  return 0;
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate       if (*ptr == 'f')
5837c478bd9Sstevel@tonic-gate 	is_floppy = 1;
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate       ptr += 2;
5867c478bd9Sstevel@tonic-gate       drive = strtoul (ptr, &ptr, 10);
5877c478bd9Sstevel@tonic-gate       if (drive < 0)
5887c478bd9Sstevel@tonic-gate 	{
5897c478bd9Sstevel@tonic-gate 	  show_error (line_number, "Bad device number");
5907c478bd9Sstevel@tonic-gate 	  return 0;
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate       else if (drive > 127)
5937c478bd9Sstevel@tonic-gate 	{
5947c478bd9Sstevel@tonic-gate 	  show_warning (line_number,
5957c478bd9Sstevel@tonic-gate 			"Ignoring %cd%d due to a BIOS limitation",
5967c478bd9Sstevel@tonic-gate 			is_floppy ? 'f' : 'h', drive);
5977c478bd9Sstevel@tonic-gate 	  continue;
5987c478bd9Sstevel@tonic-gate 	}
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate       if (! is_floppy)
6017c478bd9Sstevel@tonic-gate 	drive += 0x80;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate       if (*ptr != ')')
6047c478bd9Sstevel@tonic-gate 	{
6057c478bd9Sstevel@tonic-gate 	  show_error (line_number, "No close parenthesis found");
6067c478bd9Sstevel@tonic-gate 	  return 0;
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate       ptr++;
6107c478bd9Sstevel@tonic-gate       /* Skip spaces.  */
6117c478bd9Sstevel@tonic-gate       while (*ptr && isspace (*ptr))
6127c478bd9Sstevel@tonic-gate 	ptr++;
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate       if (! *ptr)
6157c478bd9Sstevel@tonic-gate 	{
6167c478bd9Sstevel@tonic-gate 	  show_error (line_number, "No filename found");
6177c478bd9Sstevel@tonic-gate 	  return 0;
6187c478bd9Sstevel@tonic-gate 	}
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate       /* Terminate the filename.  */
6217c478bd9Sstevel@tonic-gate       eptr = ptr;
6227c478bd9Sstevel@tonic-gate       while (*eptr && ! isspace (*eptr))
6237c478bd9Sstevel@tonic-gate 	eptr++;
6247c478bd9Sstevel@tonic-gate       *eptr = 0;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate       /* Multiple entries for a given drive is not allowed.  */
6277c478bd9Sstevel@tonic-gate       if (map[drive])
6287c478bd9Sstevel@tonic-gate 	{
6297c478bd9Sstevel@tonic-gate 	  show_error (line_number, "Duplicated entry found");
6307c478bd9Sstevel@tonic-gate 	  return 0;
6317c478bd9Sstevel@tonic-gate 	}
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate       map[drive] = strdup (ptr);
6347c478bd9Sstevel@tonic-gate       assert (map[drive]);
6357c478bd9Sstevel@tonic-gate     }
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate   return 1;
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /* Initialize the device map MAP. *MAP will be allocated from the heap
6417c478bd9Sstevel@tonic-gate    space. If MAP_FILE is not NULL, then read mappings from the file
6427c478bd9Sstevel@tonic-gate    MAP_FILE if it exists, otherwise, write guessed mappings to the file.
6437c478bd9Sstevel@tonic-gate    FLOPPY_DISKS is the number of floppy disk drives which will be probed.
6447c478bd9Sstevel@tonic-gate    If it is zero, don't probe any floppy at all. If it is one, probe one
6457c478bd9Sstevel@tonic-gate    floppy. If it is two, probe two floppies. And so on.  */
6467c478bd9Sstevel@tonic-gate int
init_device_map(char *** map,const char * map_file,int floppy_disks)6477c478bd9Sstevel@tonic-gate init_device_map (char ***map, const char *map_file, int floppy_disks)
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate   int i;
6507c478bd9Sstevel@tonic-gate   int num_hd = 0;
6517c478bd9Sstevel@tonic-gate   FILE *fp = 0;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate   assert (map);
6547c478bd9Sstevel@tonic-gate   assert (*map == 0);
6557c478bd9Sstevel@tonic-gate   *map = malloc (NUM_DISKS * sizeof (char *));
6567c478bd9Sstevel@tonic-gate   assert (*map);
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate   /* Probe devices for creating the device map.  */
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate   /* Initialize DEVICE_MAP.  */
6617c478bd9Sstevel@tonic-gate   for (i = 0; i < NUM_DISKS; i++)
6627c478bd9Sstevel@tonic-gate     (*map)[i] = 0;
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate   if (map_file)
6657c478bd9Sstevel@tonic-gate     {
6667c478bd9Sstevel@tonic-gate       /* Open the device map file.  */
6677c478bd9Sstevel@tonic-gate       fp = fopen (map_file, "r");
6687c478bd9Sstevel@tonic-gate       if (fp)
6697c478bd9Sstevel@tonic-gate 	{
6707c478bd9Sstevel@tonic-gate 	  int ret;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	  ret = read_device_map (fp, *map, map_file);
6737c478bd9Sstevel@tonic-gate 	  fclose (fp);
6747c478bd9Sstevel@tonic-gate 	  return ret;
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate     }
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate   /* Print something so that the user does not think GRUB has been
6797c478bd9Sstevel@tonic-gate      crashed.  */
6807c478bd9Sstevel@tonic-gate   fprintf (stderr,
6817c478bd9Sstevel@tonic-gate 	   "Probing devices to guess BIOS drives. "
6827c478bd9Sstevel@tonic-gate 	   "This may take a long time.\n");
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate   if (map_file)
6857c478bd9Sstevel@tonic-gate     /* Try to open the device map file to write the probed data.  */
6867c478bd9Sstevel@tonic-gate     fp = fopen (map_file, "w");
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate   /* Floppies.  */
6897c478bd9Sstevel@tonic-gate   for (i = 0; i < floppy_disks; i++)
6907c478bd9Sstevel@tonic-gate     {
6917c478bd9Sstevel@tonic-gate       char name[16];
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate       get_floppy_disk_name (name, i);
6947c478bd9Sstevel@tonic-gate       /* In floppies, write the map, whether check_device succeeds
6957c478bd9Sstevel@tonic-gate 	 or not, because the user just does not insert floppies.  */
6967c478bd9Sstevel@tonic-gate       if (fp)
6977c478bd9Sstevel@tonic-gate 	fprintf (fp, "(fd%d)\t%s\n", i, name);
6987c478bd9Sstevel@tonic-gate 
6997c478bd9Sstevel@tonic-gate       if (check_device (name))
7007c478bd9Sstevel@tonic-gate 	{
7017c478bd9Sstevel@tonic-gate 	  (*map)[i] = strdup (name);
7027c478bd9Sstevel@tonic-gate 	  assert ((*map)[i]);
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate     }
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate #ifdef __linux__
7077c478bd9Sstevel@tonic-gate   if (have_devfs ())
7087c478bd9Sstevel@tonic-gate     {
7097c478bd9Sstevel@tonic-gate       while (1)
7107c478bd9Sstevel@tonic-gate 	{
7117c478bd9Sstevel@tonic-gate 	  char discn[32];
7127c478bd9Sstevel@tonic-gate 	  char name[PATH_MAX];
7137c478bd9Sstevel@tonic-gate 	  struct stat st;
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	  /* Linux creates symlinks "/dev/discs/discN" for convenience.
7167c478bd9Sstevel@tonic-gate 	     The way to number disks is the same as GRUB's.  */
7177c478bd9Sstevel@tonic-gate 	  sprintf (discn, "/dev/discs/disc%d", num_hd);
7187c478bd9Sstevel@tonic-gate 	  if (stat (discn, &st) < 0)
7197c478bd9Sstevel@tonic-gate 	    break;
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	  if (realpath (discn, name))
7227c478bd9Sstevel@tonic-gate 	    {
7237c478bd9Sstevel@tonic-gate 	      strcat (name, "/disc");
7247c478bd9Sstevel@tonic-gate 	      (*map)[num_hd + 0x80] = strdup (name);
7257c478bd9Sstevel@tonic-gate 	      assert ((*map)[num_hd + 0x80]);
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	      /* If the device map file is opened, write the map.  */
7287c478bd9Sstevel@tonic-gate 	      if (fp)
7297c478bd9Sstevel@tonic-gate 		fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7307c478bd9Sstevel@tonic-gate 	    }
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	  num_hd++;
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate       /* OK, close the device map file if opened.  */
7367c478bd9Sstevel@tonic-gate       if (fp)
7377c478bd9Sstevel@tonic-gate 	fclose (fp);
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate       return 1;
7407c478bd9Sstevel@tonic-gate     }
7417c478bd9Sstevel@tonic-gate #endif /* __linux__ */
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate   /* IDE disks.  */
7447c478bd9Sstevel@tonic-gate   for (i = 0; i < 8; i++)
7457c478bd9Sstevel@tonic-gate     {
7467c478bd9Sstevel@tonic-gate       char name[16];
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate       get_ide_disk_name (name, i);
7497c478bd9Sstevel@tonic-gate       if (check_device (name))
7507c478bd9Sstevel@tonic-gate 	{
7517c478bd9Sstevel@tonic-gate 	  (*map)[num_hd + 0x80] = strdup (name);
7527c478bd9Sstevel@tonic-gate 	  assert ((*map)[num_hd + 0x80]);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	  /* If the device map file is opened, write the map.  */
7557c478bd9Sstevel@tonic-gate 	  if (fp)
7567c478bd9Sstevel@tonic-gate 	    fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	  num_hd++;
7597c478bd9Sstevel@tonic-gate 	}
7607c478bd9Sstevel@tonic-gate     }
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate #ifdef __linux__
7637c478bd9Sstevel@tonic-gate   /* ATARAID disks.  */
7647c478bd9Sstevel@tonic-gate   for (i = 0; i < 8; i++)
7657c478bd9Sstevel@tonic-gate     {
7667c478bd9Sstevel@tonic-gate       char name[20];
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate       get_ataraid_disk_name (name, i);
7697c478bd9Sstevel@tonic-gate       if (check_device (name))
7707c478bd9Sstevel@tonic-gate         {
7717c478bd9Sstevel@tonic-gate           (*map)[num_hd + 0x80] = strdup (name);
7727c478bd9Sstevel@tonic-gate           assert ((*map)[num_hd + 0x80]);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate           /* If the device map file is opened, write the map.  */
7757c478bd9Sstevel@tonic-gate           if (fp)
7767c478bd9Sstevel@tonic-gate             fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate           num_hd++;
7797c478bd9Sstevel@tonic-gate         }
7807c478bd9Sstevel@tonic-gate     }
7817c478bd9Sstevel@tonic-gate #endif /* __linux__ */
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate   /* The rest is SCSI disks.  */
7847c478bd9Sstevel@tonic-gate   for (i = 0; i < 16; i++)
7857c478bd9Sstevel@tonic-gate     {
7867c478bd9Sstevel@tonic-gate       char name[16];
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate       get_scsi_disk_name (name, i);
7897c478bd9Sstevel@tonic-gate       if (check_device (name))
7907c478bd9Sstevel@tonic-gate 	{
7917c478bd9Sstevel@tonic-gate 	  (*map)[num_hd + 0x80] = strdup (name);
7927c478bd9Sstevel@tonic-gate 	  assert ((*map)[num_hd + 0x80]);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	  /* If the device map file is opened, write the map.  */
7957c478bd9Sstevel@tonic-gate 	  if (fp)
7967c478bd9Sstevel@tonic-gate 	    fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	  num_hd++;
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate     }
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate #ifdef __linux__
8037c478bd9Sstevel@tonic-gate   /* This is for DAC960 - we have
8047c478bd9Sstevel@tonic-gate      /dev/rd/c<controller>d<logical drive>p<partition>.
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate      DAC960 driver currently supports up to 8 controllers, 32 logical
8077c478bd9Sstevel@tonic-gate      drives, and 7 partitions.  */
8087c478bd9Sstevel@tonic-gate   {
8097c478bd9Sstevel@tonic-gate     int controller, drive;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate     for (controller = 0; controller < 8; controller++)
8127c478bd9Sstevel@tonic-gate       {
8137c478bd9Sstevel@tonic-gate 	for (drive = 0; drive < 15; drive++)
8147c478bd9Sstevel@tonic-gate 	  {
8157c478bd9Sstevel@tonic-gate 	    char name[24];
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	    get_dac960_disk_name (name, controller, drive);
8187c478bd9Sstevel@tonic-gate 	    if (check_device (name))
8197c478bd9Sstevel@tonic-gate 	      {
8207c478bd9Sstevel@tonic-gate 		(*map)[num_hd + 0x80] = strdup (name);
8217c478bd9Sstevel@tonic-gate 		assert ((*map)[num_hd + 0x80]);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 		/* If the device map file is opened, write the map.  */
8247c478bd9Sstevel@tonic-gate 		if (fp)
8257c478bd9Sstevel@tonic-gate 		  fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 		num_hd++;
8287c478bd9Sstevel@tonic-gate 	      }
8297c478bd9Sstevel@tonic-gate 	  }
8307c478bd9Sstevel@tonic-gate       }
8317c478bd9Sstevel@tonic-gate   }
8327c478bd9Sstevel@tonic-gate #endif /* __linux__ */
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate   /* OK, close the device map file if opened.  */
8357c478bd9Sstevel@tonic-gate   if (fp)
8367c478bd9Sstevel@tonic-gate     fclose (fp);
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate   return 1;
8397c478bd9Sstevel@tonic-gate }
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate /* Restore the memory consumed for MAP.  */
8427c478bd9Sstevel@tonic-gate void
restore_device_map(char ** map)8437c478bd9Sstevel@tonic-gate restore_device_map (char **map)
8447c478bd9Sstevel@tonic-gate {
8457c478bd9Sstevel@tonic-gate   int i;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate   for (i = 0; i < NUM_DISKS; i++)
8487c478bd9Sstevel@tonic-gate     if (map[i])
8497c478bd9Sstevel@tonic-gate       free (map[i]);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate   free (map);
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate #ifdef __linux__
8557c478bd9Sstevel@tonic-gate /* Linux-only functions, because Linux has a bug that the disk cache for
8567c478bd9Sstevel@tonic-gate    a whole disk is not consistent with the one for a partition of the
8577c478bd9Sstevel@tonic-gate    disk.  */
8587c478bd9Sstevel@tonic-gate int
is_disk_device(char ** map,int drive)8597c478bd9Sstevel@tonic-gate is_disk_device (char **map, int drive)
8607c478bd9Sstevel@tonic-gate {
8617c478bd9Sstevel@tonic-gate   struct stat st;
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate   assert (map[drive] != 0);
8647c478bd9Sstevel@tonic-gate   assert (stat (map[drive], &st) == 0);
8657c478bd9Sstevel@tonic-gate   /* For now, disk devices under Linux are all block devices.  */
8667c478bd9Sstevel@tonic-gate   return S_ISBLK (st.st_mode);
8677c478bd9Sstevel@tonic-gate }
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate int
write_to_partition(char ** map,int drive,int partition,int sector,int size,const char * buf)8707c478bd9Sstevel@tonic-gate write_to_partition (char **map, int drive, int partition,
8717c478bd9Sstevel@tonic-gate 		    int sector, int size, const char *buf)
8727c478bd9Sstevel@tonic-gate {
8737c478bd9Sstevel@tonic-gate   char dev[PATH_MAX];	/* XXX */
8747c478bd9Sstevel@tonic-gate   int fd;
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate   if ((partition & 0x00FF00) != 0x00FF00)
8777c478bd9Sstevel@tonic-gate     {
8787c478bd9Sstevel@tonic-gate       /* If the partition is a BSD partition, it is difficult to
8797c478bd9Sstevel@tonic-gate 	 obtain the representation in Linux. So don't support that.  */
8807c478bd9Sstevel@tonic-gate       errnum = ERR_DEV_VALUES;
8817c478bd9Sstevel@tonic-gate       return 1;
8827c478bd9Sstevel@tonic-gate     }
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate   assert (map[drive] != 0);
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate   strcpy (dev, map[drive]);
8877c478bd9Sstevel@tonic-gate   if (have_devfs ())
8887c478bd9Sstevel@tonic-gate     {
8897c478bd9Sstevel@tonic-gate       if (strcmp (dev + strlen(dev) - 5, "/disc") == 0)
8907c478bd9Sstevel@tonic-gate 	strcpy (dev + strlen(dev) - 5, "/part");
8917c478bd9Sstevel@tonic-gate     }
8927c478bd9Sstevel@tonic-gate   sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate   /* Open the partition.  */
8957c478bd9Sstevel@tonic-gate   fd = open (dev, O_RDWR);
8967c478bd9Sstevel@tonic-gate   if (fd < 0)
8977c478bd9Sstevel@tonic-gate     {
8987c478bd9Sstevel@tonic-gate       errnum = ERR_NO_PART;
8997c478bd9Sstevel@tonic-gate       return 0;
9007c478bd9Sstevel@tonic-gate     }
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate #if defined(__linux__) && (!defined(__GLIBC__) || \
9037c478bd9Sstevel@tonic-gate         ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
9047c478bd9Sstevel@tonic-gate   /* Maybe libc doesn't have large file support.  */
9057c478bd9Sstevel@tonic-gate   {
9067c478bd9Sstevel@tonic-gate     loff_t offset, result;
9077c478bd9Sstevel@tonic-gate     static int _llseek (uint filedes, ulong hi, ulong lo,
9087c478bd9Sstevel@tonic-gate                         loff_t *res, uint wh);
9097c478bd9Sstevel@tonic-gate     _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
9107c478bd9Sstevel@tonic-gate                loff_t *, res, uint, wh);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate     offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
9137c478bd9Sstevel@tonic-gate     if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
9147c478bd9Sstevel@tonic-gate       {
9157c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
9167c478bd9Sstevel@tonic-gate 	return 0;
9177c478bd9Sstevel@tonic-gate       }
9187c478bd9Sstevel@tonic-gate   }
9197c478bd9Sstevel@tonic-gate #else
9207c478bd9Sstevel@tonic-gate   {
9217c478bd9Sstevel@tonic-gate     off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate     if (lseek (fd, offset, SEEK_SET) != offset)
9247c478bd9Sstevel@tonic-gate       {
9257c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
9267c478bd9Sstevel@tonic-gate 	return 0;
9277c478bd9Sstevel@tonic-gate       }
9287c478bd9Sstevel@tonic-gate   }
9297c478bd9Sstevel@tonic-gate #endif
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate   if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE))
9327c478bd9Sstevel@tonic-gate     {
9337c478bd9Sstevel@tonic-gate       close (fd);
9347c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
9357c478bd9Sstevel@tonic-gate       return 0;
9367c478bd9Sstevel@tonic-gate     }
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate   sync ();	/* Paranoia.  */
9397c478bd9Sstevel@tonic-gate   close (fd);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate   return 1;
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate #endif /* __linux__ */
944