xref: /titanic_50/usr/src/grub/grub-0.97/lib/device.c (revision 828d47c166ce67972b1f1929669b9af5be769423)
11b8adde7SWilliam Kucharski /* device.c - Some helper functions for OS devices and BIOS drives */
21b8adde7SWilliam Kucharski /*
31b8adde7SWilliam Kucharski  *  GRUB  --  GRand Unified Bootloader
41b8adde7SWilliam Kucharski  *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005  Free Software Foundation, Inc.
51b8adde7SWilliam Kucharski  *
61b8adde7SWilliam Kucharski  *  This program is free software; you can redistribute it and/or modify
71b8adde7SWilliam Kucharski  *  it under the terms of the GNU General Public License as published by
81b8adde7SWilliam Kucharski  *  the Free Software Foundation; either version 2 of the License, or
91b8adde7SWilliam Kucharski  *  (at your option) any later version.
101b8adde7SWilliam Kucharski  *
111b8adde7SWilliam Kucharski  *  This program is distributed in the hope that it will be useful,
121b8adde7SWilliam Kucharski  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
131b8adde7SWilliam Kucharski  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141b8adde7SWilliam Kucharski  *  GNU General Public License for more details.
151b8adde7SWilliam Kucharski  *
161b8adde7SWilliam Kucharski  *  You should have received a copy of the GNU General Public License
171b8adde7SWilliam Kucharski  *  along with this program; if not, write to the Free Software
181b8adde7SWilliam Kucharski  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
191b8adde7SWilliam Kucharski  */
201b8adde7SWilliam Kucharski 
211b8adde7SWilliam Kucharski /* Try to use glibc's transparant LFS support. */
221b8adde7SWilliam Kucharski #define _LARGEFILE_SOURCE       1
231b8adde7SWilliam Kucharski /* lseek becomes synonymous with lseek64.  */
241b8adde7SWilliam Kucharski #define _FILE_OFFSET_BITS       64
251b8adde7SWilliam Kucharski 
261b8adde7SWilliam Kucharski #include <stdio.h>
271b8adde7SWilliam Kucharski #include <stdlib.h>
281b8adde7SWilliam Kucharski #include <string.h>
291b8adde7SWilliam Kucharski #include <ctype.h>
301b8adde7SWilliam Kucharski #include <assert.h>
311b8adde7SWilliam Kucharski #include <unistd.h>
321b8adde7SWilliam Kucharski #include <sys/types.h>
331b8adde7SWilliam Kucharski #include <sys/stat.h>
341b8adde7SWilliam Kucharski #include <fcntl.h>
351b8adde7SWilliam Kucharski #include <errno.h>
361b8adde7SWilliam Kucharski #include <limits.h>
371b8adde7SWilliam Kucharski #include <stdarg.h>
381b8adde7SWilliam Kucharski 
391b8adde7SWilliam Kucharski #ifdef __linux__
401b8adde7SWilliam Kucharski # if !defined(__GLIBC__) || \
411b8adde7SWilliam Kucharski         ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
421b8adde7SWilliam Kucharski /* Maybe libc doesn't have large file support.  */
431b8adde7SWilliam Kucharski #  include <linux/unistd.h>     /* _llseek */
441b8adde7SWilliam Kucharski # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
451b8adde7SWilliam Kucharski # include <sys/ioctl.h>		/* ioctl */
461b8adde7SWilliam Kucharski # ifndef HDIO_GETGEO
471b8adde7SWilliam Kucharski #  define HDIO_GETGEO	0x0301	/* get device geometry */
481b8adde7SWilliam Kucharski /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
491b8adde7SWilliam Kucharski    defined.  */
501b8adde7SWilliam Kucharski struct hd_geometry
511b8adde7SWilliam Kucharski {
521b8adde7SWilliam Kucharski   unsigned char heads;
531b8adde7SWilliam Kucharski   unsigned char sectors;
541b8adde7SWilliam Kucharski   unsigned short cylinders;
551b8adde7SWilliam Kucharski   unsigned long start;
561b8adde7SWilliam Kucharski };
571b8adde7SWilliam Kucharski # endif /* ! HDIO_GETGEO */
581b8adde7SWilliam Kucharski # ifndef FLOPPY_MAJOR
591b8adde7SWilliam Kucharski #  define FLOPPY_MAJOR	2	/* the major number for floppy */
601b8adde7SWilliam Kucharski # endif /* ! FLOPPY_MAJOR */
611b8adde7SWilliam Kucharski # ifndef MAJOR
621b8adde7SWilliam Kucharski #  define MAJOR(dev)	\
631b8adde7SWilliam Kucharski   ({ \
641b8adde7SWilliam Kucharski      unsigned long long __dev = (dev); \
651b8adde7SWilliam Kucharski      (unsigned) ((__dev >> 8) & 0xfff) \
661b8adde7SWilliam Kucharski                  | ((unsigned int) (__dev >> 32) & ~0xfff); \
671b8adde7SWilliam Kucharski   })
681b8adde7SWilliam Kucharski # endif /* ! MAJOR */
691b8adde7SWilliam Kucharski # ifndef CDROM_GET_CAPABILITY
701b8adde7SWilliam Kucharski #  define CDROM_GET_CAPABILITY	0x5331	/* get capabilities */
711b8adde7SWilliam Kucharski # endif /* ! CDROM_GET_CAPABILITY */
721b8adde7SWilliam Kucharski # ifndef BLKGETSIZE
731b8adde7SWilliam Kucharski #  define BLKGETSIZE	_IO(0x12,96)	/* return device size */
741b8adde7SWilliam Kucharski # endif /* ! BLKGETSIZE */
751b8adde7SWilliam Kucharski #endif /* __linux__ */
761b8adde7SWilliam Kucharski 
771b8adde7SWilliam Kucharski /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
781b8adde7SWilliam Kucharski    kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
791b8adde7SWilliam Kucharski #if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
801b8adde7SWilliam Kucharski # define __FreeBSD_kernel__
811b8adde7SWilliam Kucharski #endif
821b8adde7SWilliam Kucharski #ifdef __FreeBSD_kernel__
831b8adde7SWilliam Kucharski   /* Obtain version of kFreeBSD headers */
841b8adde7SWilliam Kucharski # include <osreldate.h>
851b8adde7SWilliam Kucharski # ifndef __FreeBSD_kernel_version
861b8adde7SWilliam Kucharski #  define __FreeBSD_kernel_version __FreeBSD_version
871b8adde7SWilliam Kucharski # endif
881b8adde7SWilliam Kucharski 
891b8adde7SWilliam Kucharski   /* Runtime detection of kernel */
901b8adde7SWilliam Kucharski # include <sys/utsname.h>
911b8adde7SWilliam Kucharski int
get_kfreebsd_version()921b8adde7SWilliam Kucharski get_kfreebsd_version ()
931b8adde7SWilliam Kucharski {
941b8adde7SWilliam Kucharski   struct utsname uts;
951b8adde7SWilliam Kucharski   int major; int minor, v[2];
961b8adde7SWilliam Kucharski 
971b8adde7SWilliam Kucharski   uname (&uts);
981b8adde7SWilliam Kucharski   sscanf (uts.release, "%d.%d", &major, &minor);
991b8adde7SWilliam Kucharski 
1001b8adde7SWilliam Kucharski   if (major >= 9)
1011b8adde7SWilliam Kucharski     major = 9;
1021b8adde7SWilliam Kucharski   if (major >= 5)
1031b8adde7SWilliam Kucharski     {
1041b8adde7SWilliam Kucharski       v[0] = minor/10; v[1] = minor%10;
1051b8adde7SWilliam Kucharski     }
1061b8adde7SWilliam Kucharski   else
1071b8adde7SWilliam Kucharski     {
1081b8adde7SWilliam Kucharski       v[0] = minor%10; v[1] = minor/10;
1091b8adde7SWilliam Kucharski     }
1101b8adde7SWilliam Kucharski   return major*100000+v[0]*10000+v[1]*1000;
1111b8adde7SWilliam Kucharski }
1121b8adde7SWilliam Kucharski #endif /* __FreeBSD_kernel__ */
1131b8adde7SWilliam Kucharski 
1141b8adde7SWilliam Kucharski #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
1151b8adde7SWilliam Kucharski # include <sys/ioctl.h>		/* ioctl */
1161b8adde7SWilliam Kucharski # include <sys/disklabel.h>
1171b8adde7SWilliam Kucharski # include <sys/cdio.h>		/* CDIOCCLRDEBUG */
1181b8adde7SWilliam Kucharski # if defined(__FreeBSD_kernel__)
1191b8adde7SWilliam Kucharski #  include <sys/param.h>
1201b8adde7SWilliam Kucharski #  if __FreeBSD_kernel_version >= 500040
1211b8adde7SWilliam Kucharski #   include <sys/disk.h>
1221b8adde7SWilliam Kucharski #  endif
1231b8adde7SWilliam Kucharski # endif /* __FreeBSD_kernel__ */
1241b8adde7SWilliam Kucharski #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
1251b8adde7SWilliam Kucharski 
1261b8adde7SWilliam Kucharski #if defined(__sun)
1271b8adde7SWilliam Kucharski # include <sys/dkio.h>
1281b8adde7SWilliam Kucharski #endif /* __sun */
1291b8adde7SWilliam Kucharski 
1301b8adde7SWilliam Kucharski #ifdef HAVE_OPENDISK
1311b8adde7SWilliam Kucharski # include <util.h>
1321b8adde7SWilliam Kucharski #endif /* HAVE_OPENDISK */
1331b8adde7SWilliam Kucharski 
1341b8adde7SWilliam Kucharski #define WITHOUT_LIBC_STUBS	1
1351b8adde7SWilliam Kucharski #include <shared.h>
1361b8adde7SWilliam Kucharski #include <device.h>
1371b8adde7SWilliam Kucharski 
1381b8adde7SWilliam Kucharski /* Get the geometry of a drive DRIVE.  */
1391b8adde7SWilliam Kucharski void
get_drive_geometry(struct geometry * geom,char ** map,int drive)1401b8adde7SWilliam Kucharski get_drive_geometry (struct geometry *geom, char **map, int drive)
1411b8adde7SWilliam Kucharski {
1421b8adde7SWilliam Kucharski   int fd;
1431b8adde7SWilliam Kucharski 
1441b8adde7SWilliam Kucharski   if (geom->flags == -1)
1451b8adde7SWilliam Kucharski     {
1461b8adde7SWilliam Kucharski       fd = open (map[drive], O_RDONLY);
1471b8adde7SWilliam Kucharski       assert (fd >= 0);
1481b8adde7SWilliam Kucharski     }
1491b8adde7SWilliam Kucharski   else
1501b8adde7SWilliam Kucharski     fd = geom->flags;
1511b8adde7SWilliam Kucharski 
1521b8adde7SWilliam Kucharski   /* XXX This is the default size.  */
1531b8adde7SWilliam Kucharski   geom->sector_size = SECTOR_SIZE;
1541b8adde7SWilliam Kucharski 
1551b8adde7SWilliam Kucharski #if defined(__linux__)
1561b8adde7SWilliam Kucharski   /* Linux */
1571b8adde7SWilliam Kucharski   {
1581b8adde7SWilliam Kucharski     struct hd_geometry hdg;
1591b8adde7SWilliam Kucharski     unsigned long nr;
1601b8adde7SWilliam Kucharski 
1611b8adde7SWilliam Kucharski     if (ioctl (fd, HDIO_GETGEO, &hdg))
1621b8adde7SWilliam Kucharski       goto fail;
1631b8adde7SWilliam Kucharski 
1641b8adde7SWilliam Kucharski     if (ioctl (fd, BLKGETSIZE, &nr))
1651b8adde7SWilliam Kucharski       goto fail;
1661b8adde7SWilliam Kucharski 
1671b8adde7SWilliam Kucharski     /* Got the geometry, so save it. */
1681b8adde7SWilliam Kucharski     geom->cylinders = hdg.cylinders;
1691b8adde7SWilliam Kucharski     geom->heads = hdg.heads;
1701b8adde7SWilliam Kucharski     geom->sectors = hdg.sectors;
1711b8adde7SWilliam Kucharski     geom->total_sectors = nr;
1721b8adde7SWilliam Kucharski 
1731b8adde7SWilliam Kucharski     goto success;
1741b8adde7SWilliam Kucharski   }
1751b8adde7SWilliam Kucharski 
1761b8adde7SWilliam Kucharski #elif defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
1771b8adde7SWilliam Kucharski # if defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040
1781b8adde7SWilliam Kucharski   /* kFreeBSD version 5 or later */
1791b8adde7SWilliam Kucharski   if (get_kfreebsd_version () >= 500040)
1801b8adde7SWilliam Kucharski   {
1811b8adde7SWilliam Kucharski     unsigned int sector_size;
1821b8adde7SWilliam Kucharski     off_t media_size;
1831b8adde7SWilliam Kucharski     unsigned int tmp;
1841b8adde7SWilliam Kucharski 
1851b8adde7SWilliam Kucharski     if(ioctl (fd, DIOCGSECTORSIZE, &sector_size) != 0)
1861b8adde7SWilliam Kucharski       sector_size = 512;
1871b8adde7SWilliam Kucharski 
1881b8adde7SWilliam Kucharski     if (ioctl (fd, DIOCGMEDIASIZE, &media_size) != 0)
1891b8adde7SWilliam Kucharski       goto fail;
1901b8adde7SWilliam Kucharski 
1911b8adde7SWilliam Kucharski     geom->total_sectors = media_size / sector_size;
1921b8adde7SWilliam Kucharski 
1931b8adde7SWilliam Kucharski     if (ioctl (fd, DIOCGFWSECTORS, &tmp) == 0)
1941b8adde7SWilliam Kucharski       geom->sectors = tmp;
1951b8adde7SWilliam Kucharski     else
1961b8adde7SWilliam Kucharski       geom->sectors = 63;
1971b8adde7SWilliam Kucharski     if (ioctl (fd, DIOCGFWHEADS, &tmp) == 0)
1981b8adde7SWilliam Kucharski       geom->heads = tmp;
1991b8adde7SWilliam Kucharski     else if (geom->total_sectors <= 63 * 1 * 1024)
2001b8adde7SWilliam Kucharski       geom->heads = 1;
2011b8adde7SWilliam Kucharski     else if (geom->total_sectors <= 63 * 16 * 1024)
2021b8adde7SWilliam Kucharski       geom->heads = 16;
2031b8adde7SWilliam Kucharski     else
2041b8adde7SWilliam Kucharski       geom->heads = 255;
2051b8adde7SWilliam Kucharski 
2061b8adde7SWilliam Kucharski     geom->cylinders = (geom->total_sectors
2071b8adde7SWilliam Kucharski 			   / geom->heads
2081b8adde7SWilliam Kucharski 			   / geom->sectors);
2091b8adde7SWilliam Kucharski 
2101b8adde7SWilliam Kucharski     goto success;
2111b8adde7SWilliam Kucharski   }
2121b8adde7SWilliam Kucharski   else
2131b8adde7SWilliam Kucharski #endif /* defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040 */
2141b8adde7SWilliam Kucharski 
2151b8adde7SWilliam Kucharski   /* kFreeBSD < 5, NetBSD or OpenBSD */
2161b8adde7SWilliam Kucharski   {
2171b8adde7SWilliam Kucharski     struct disklabel hdg;
2181b8adde7SWilliam Kucharski     if (ioctl (fd, DIOCGDINFO, &hdg))
2191b8adde7SWilliam Kucharski       goto fail;
2201b8adde7SWilliam Kucharski 
2211b8adde7SWilliam Kucharski     geom->cylinders = hdg.d_ncylinders;
2221b8adde7SWilliam Kucharski     geom->heads = hdg.d_ntracks;
2231b8adde7SWilliam Kucharski     geom->sectors = hdg.d_nsectors;
2241b8adde7SWilliam Kucharski     geom->total_sectors = hdg.d_secperunit;
2251b8adde7SWilliam Kucharski 
2261b8adde7SWilliam Kucharski     goto success;
2271b8adde7SWilliam Kucharski   }
2281b8adde7SWilliam Kucharski 
2291b8adde7SWilliam Kucharski #elif defined(__sun)
2301b8adde7SWilliam Kucharski   /* Solaris */
2311b8adde7SWilliam Kucharski   {
2321b8adde7SWilliam Kucharski     struct dk_geom dkg;
2331b8adde7SWilliam Kucharski 
2341b8adde7SWilliam Kucharski     if (ioctl(fd, DKIOCG_PHYGEOM, &dkg))
2351b8adde7SWilliam Kucharski       goto fail;
2361b8adde7SWilliam Kucharski     geom->cylinders = dkg.dkg_ncyl;
2371b8adde7SWilliam Kucharski     geom->heads = dkg.dkg_nhead;
2381b8adde7SWilliam Kucharski     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;
2411b8adde7SWilliam Kucharski 
2421b8adde7SWilliam Kucharski     goto success;
2431b8adde7SWilliam Kucharski   }
2441b8adde7SWilliam Kucharski 
2451b8adde7SWilliam Kucharski #else
2461b8adde7SWilliam Kucharski   /* Notably, defined(__GNU__) */
2471b8adde7SWilliam Kucharski # warning "Automatic detection of geometries will be performed only \
2481b8adde7SWilliam Kucharski partially. This is not fatal."
2491b8adde7SWilliam Kucharski #endif
2501b8adde7SWilliam Kucharski 
2511b8adde7SWilliam Kucharski  fail:
2521b8adde7SWilliam Kucharski   {
2531b8adde7SWilliam Kucharski     struct stat st;
2541b8adde7SWilliam Kucharski 
2551b8adde7SWilliam Kucharski     /* FIXME: It would be nice to somehow compute fake C/H/S settings,
2561b8adde7SWilliam Kucharski        given a proper st_blocks size. */
2571b8adde7SWilliam Kucharski     if (drive & 0x80)
2581b8adde7SWilliam Kucharski       {
2591b8adde7SWilliam Kucharski 	geom->cylinders = DEFAULT_HD_CYLINDERS;
2601b8adde7SWilliam Kucharski 	geom->heads = DEFAULT_HD_HEADS;
2611b8adde7SWilliam Kucharski 	geom->sectors = DEFAULT_HD_SECTORS;
2621b8adde7SWilliam Kucharski       }
2631b8adde7SWilliam Kucharski     else
2641b8adde7SWilliam Kucharski       {
2651b8adde7SWilliam Kucharski 	geom->cylinders = DEFAULT_FD_CYLINDERS;
2661b8adde7SWilliam Kucharski 	geom->heads = DEFAULT_FD_HEADS;
2671b8adde7SWilliam Kucharski 	geom->sectors = DEFAULT_FD_SECTORS;
2681b8adde7SWilliam Kucharski       }
2691b8adde7SWilliam Kucharski 
2701b8adde7SWilliam Kucharski     /* Set the total sectors properly, if we can. */
2711b8adde7SWilliam Kucharski     if (! fstat (fd, &st) && st.st_blocks)
2721b8adde7SWilliam Kucharski       geom->total_sectors = st.st_blocks >> SECTOR_BITS;
2731b8adde7SWilliam Kucharski     else
274*828d47c1SShidokht Yadegari       geom->total_sectors = (unsigned long long)geom->cylinders *
275*828d47c1SShidokht Yadegari 	geom->heads * geom->sectors;
2761b8adde7SWilliam Kucharski   }
2771b8adde7SWilliam Kucharski 
2781b8adde7SWilliam Kucharski  success:
2791b8adde7SWilliam Kucharski   if (geom->flags == -1)
2801b8adde7SWilliam Kucharski     close (fd);
2811b8adde7SWilliam Kucharski }
2821b8adde7SWilliam Kucharski 
2831b8adde7SWilliam Kucharski #ifdef __linux__
2841b8adde7SWilliam Kucharski /* Check if we have devfs support.  */
2851b8adde7SWilliam Kucharski static int
have_devfs(void)2861b8adde7SWilliam Kucharski have_devfs (void)
2871b8adde7SWilliam Kucharski {
2881b8adde7SWilliam Kucharski   static int dev_devfsd_exists = -1;
2891b8adde7SWilliam Kucharski 
2901b8adde7SWilliam Kucharski   if (dev_devfsd_exists < 0)
2911b8adde7SWilliam Kucharski     {
2921b8adde7SWilliam Kucharski       struct stat st;
2931b8adde7SWilliam Kucharski 
2941b8adde7SWilliam Kucharski       dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
2951b8adde7SWilliam Kucharski     }
2961b8adde7SWilliam Kucharski 
2971b8adde7SWilliam Kucharski   return dev_devfsd_exists;
2981b8adde7SWilliam Kucharski }
2991b8adde7SWilliam Kucharski #endif /* __linux__ */
3001b8adde7SWilliam Kucharski 
3011b8adde7SWilliam Kucharski /* These three functions are quite different among OSes.  */
3021b8adde7SWilliam Kucharski static void
get_floppy_disk_name(char * name,int unit)3031b8adde7SWilliam Kucharski get_floppy_disk_name (char *name, int unit)
3041b8adde7SWilliam Kucharski {
3051b8adde7SWilliam Kucharski #if defined(__linux__)
3061b8adde7SWilliam Kucharski   /* GNU/Linux */
3071b8adde7SWilliam Kucharski   if (have_devfs ())
3081b8adde7SWilliam Kucharski     sprintf (name, "/dev/floppy/%d", unit);
3091b8adde7SWilliam Kucharski   else
3101b8adde7SWilliam Kucharski     sprintf (name, "/dev/fd%d", unit);
3111b8adde7SWilliam Kucharski #elif defined(__GNU__)
3121b8adde7SWilliam Kucharski   /* GNU/Hurd */
3131b8adde7SWilliam Kucharski   sprintf (name, "/dev/fd%d", unit);
3141b8adde7SWilliam Kucharski #elif defined(__FreeBSD_kernel__)
3151b8adde7SWilliam Kucharski   /* kFreeBSD */
3161b8adde7SWilliam Kucharski   if (get_kfreebsd_version () >= 400000)
3171b8adde7SWilliam Kucharski     sprintf (name, "/dev/fd%d", unit);
3181b8adde7SWilliam Kucharski   else
3191b8adde7SWilliam Kucharski     sprintf (name, "/dev/rfd%d", unit);
3201b8adde7SWilliam Kucharski #elif defined(__NetBSD__)
3211b8adde7SWilliam Kucharski   /* NetBSD */
3221b8adde7SWilliam Kucharski   /* opendisk() doesn't work for floppies.  */
3231b8adde7SWilliam Kucharski   sprintf (name, "/dev/rfd%da", unit);
3241b8adde7SWilliam Kucharski #elif defined(__OpenBSD__)
3251b8adde7SWilliam Kucharski   /* OpenBSD */
3261b8adde7SWilliam Kucharski   sprintf (name, "/dev/rfd%dc", unit);
3271b8adde7SWilliam Kucharski #elif defined(__QNXNTO__)
3281b8adde7SWilliam Kucharski   /* QNX RTP */
3291b8adde7SWilliam Kucharski   sprintf (name, "/dev/fd%d", unit);
3301b8adde7SWilliam Kucharski #elif defined(__sun)
3311b8adde7SWilliam Kucharski   /* Solaris */
3321b8adde7SWilliam Kucharski   sprintf (name, "/dev/rdiskette%d", unit);
3331b8adde7SWilliam Kucharski #else
3341b8adde7SWilliam Kucharski # warning "BIOS floppy drives cannot be guessed in your operating system."
3351b8adde7SWilliam Kucharski   /* Set NAME to a bogus string.  */
3361b8adde7SWilliam Kucharski   *name = 0;
3371b8adde7SWilliam Kucharski #endif
3381b8adde7SWilliam Kucharski }
3391b8adde7SWilliam Kucharski 
3401b8adde7SWilliam Kucharski static void
get_ide_disk_name(char * name,int unit)3411b8adde7SWilliam Kucharski get_ide_disk_name (char *name, int unit)
3421b8adde7SWilliam Kucharski {
3431b8adde7SWilliam Kucharski #if defined(__linux__)
3441b8adde7SWilliam Kucharski   /* GNU/Linux */
3451b8adde7SWilliam Kucharski   sprintf (name, "/dev/hd%c", unit + 'a');
3461b8adde7SWilliam Kucharski #elif defined(__GNU__)
3471b8adde7SWilliam Kucharski   /* GNU/Hurd */
3481b8adde7SWilliam Kucharski   sprintf (name, "/dev/hd%d", unit);
3491b8adde7SWilliam Kucharski #elif defined(__FreeBSD_kernel__)
3501b8adde7SWilliam Kucharski   /* kFreeBSD */
3511b8adde7SWilliam Kucharski   if (get_kfreebsd_version () >= 400000)
3521b8adde7SWilliam Kucharski     sprintf (name, "/dev/ad%d", unit);
3531b8adde7SWilliam Kucharski   else
3541b8adde7SWilliam Kucharski     sprintf (name, "/dev/rwd%d", unit);
3551b8adde7SWilliam Kucharski #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
3561b8adde7SWilliam Kucharski   /* NetBSD */
3571b8adde7SWilliam Kucharski   char shortname[16];
3581b8adde7SWilliam Kucharski   int fd;
3591b8adde7SWilliam Kucharski 
3601b8adde7SWilliam Kucharski   sprintf (shortname, "wd%d", unit);
3611b8adde7SWilliam Kucharski   fd = opendisk (shortname, O_RDONLY, name,
3621b8adde7SWilliam Kucharski 		 16,	/* length of NAME */
3631b8adde7SWilliam Kucharski 		 0	/* char device */
3641b8adde7SWilliam Kucharski 		 );
3651b8adde7SWilliam Kucharski   close (fd);
3661b8adde7SWilliam Kucharski #elif defined(__OpenBSD__)
3671b8adde7SWilliam Kucharski   /* OpenBSD */
3681b8adde7SWilliam Kucharski   sprintf (name, "/dev/rwd%dc", unit);
3691b8adde7SWilliam Kucharski #elif defined(__QNXNTO__)
3701b8adde7SWilliam Kucharski   /* QNX RTP */
3711b8adde7SWilliam Kucharski   /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
3721b8adde7SWilliam Kucharski      contain SCSI disks.  */
3731b8adde7SWilliam Kucharski   sprintf (name, "/dev/hd%d", unit);
3741b8adde7SWilliam Kucharski #elif defined(__sun)
3751b8adde7SWilliam Kucharski   *name = 0;		/* FIXME */
3761b8adde7SWilliam Kucharski #else
3771b8adde7SWilliam Kucharski # warning "BIOS IDE drives cannot be guessed in your operating system."
3781b8adde7SWilliam Kucharski   /* Set NAME to a bogus string.  */
3791b8adde7SWilliam Kucharski   *name = 0;
3801b8adde7SWilliam Kucharski #endif
3811b8adde7SWilliam Kucharski }
3821b8adde7SWilliam Kucharski 
3831b8adde7SWilliam Kucharski static void
get_scsi_disk_name(char * name,int unit)3841b8adde7SWilliam Kucharski get_scsi_disk_name (char *name, int unit)
3851b8adde7SWilliam Kucharski {
3861b8adde7SWilliam Kucharski #if defined(__linux__)
3871b8adde7SWilliam Kucharski   /* GNU/Linux */
3881b8adde7SWilliam Kucharski   sprintf (name, "/dev/sd%c", unit + 'a');
3891b8adde7SWilliam Kucharski #elif defined(__GNU__)
3901b8adde7SWilliam Kucharski   /* GNU/Hurd */
3911b8adde7SWilliam Kucharski   sprintf (name, "/dev/sd%d", unit);
3921b8adde7SWilliam Kucharski #elif defined(__FreeBSD_kernel__)
3931b8adde7SWilliam Kucharski   /* kFreeBSD */
3941b8adde7SWilliam Kucharski   if (get_kfreebsd_version () >= 400000)
3951b8adde7SWilliam Kucharski     sprintf (name, "/dev/da%d", unit);
3961b8adde7SWilliam Kucharski   else
3971b8adde7SWilliam Kucharski     sprintf (name, "/dev/rda%d", unit);
3981b8adde7SWilliam Kucharski #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
3991b8adde7SWilliam Kucharski   /* NetBSD */
4001b8adde7SWilliam Kucharski   char shortname[16];
4011b8adde7SWilliam Kucharski   int fd;
4021b8adde7SWilliam Kucharski 
4031b8adde7SWilliam Kucharski   sprintf (shortname, "sd%d", unit);
4041b8adde7SWilliam Kucharski   fd = opendisk (shortname, O_RDONLY, name,
4051b8adde7SWilliam Kucharski 		 16,	/* length of NAME */
4061b8adde7SWilliam Kucharski 		 0	/* char device */
4071b8adde7SWilliam Kucharski 		 );
4081b8adde7SWilliam Kucharski   close (fd);
4091b8adde7SWilliam Kucharski #elif defined(__OpenBSD__)
4101b8adde7SWilliam Kucharski   /* OpenBSD */
4111b8adde7SWilliam Kucharski   sprintf (name, "/dev/rsd%dc", unit);
4121b8adde7SWilliam Kucharski #elif defined(__QNXNTO__)
4131b8adde7SWilliam Kucharski   /* QNX RTP */
4141b8adde7SWilliam Kucharski   /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
4151b8adde7SWilliam Kucharski      disable the detection of SCSI disks here.  */
4161b8adde7SWilliam Kucharski   *name = 0;
4171b8adde7SWilliam Kucharski #elif defined(__sun)
4181b8adde7SWilliam Kucharski   *name = 0;		/* FIXME */
4191b8adde7SWilliam Kucharski #else
4201b8adde7SWilliam Kucharski # warning "BIOS SCSI drives cannot be guessed in your operating system."
4211b8adde7SWilliam Kucharski   /* Set NAME to a bogus string.  */
4221b8adde7SWilliam Kucharski   *name = 0;
4231b8adde7SWilliam Kucharski #endif
4241b8adde7SWilliam Kucharski }
4251b8adde7SWilliam Kucharski 
4261b8adde7SWilliam Kucharski #ifdef __linux__
4271b8adde7SWilliam Kucharski static void
get_dac960_disk_name(char * name,int controller,int drive)4281b8adde7SWilliam Kucharski get_dac960_disk_name (char *name, int controller, int drive)
4291b8adde7SWilliam Kucharski {
4301b8adde7SWilliam Kucharski   sprintf (name, "/dev/rd/c%dd%d", controller, drive);
4311b8adde7SWilliam Kucharski }
4321b8adde7SWilliam Kucharski 
4331b8adde7SWilliam Kucharski static void
get_ataraid_disk_name(char * name,int unit)4341b8adde7SWilliam Kucharski get_ataraid_disk_name (char *name, int unit)
4351b8adde7SWilliam Kucharski {
4361b8adde7SWilliam Kucharski   sprintf (name, "/dev/ataraid/d%c", unit + '0');
4371b8adde7SWilliam Kucharski }
4381b8adde7SWilliam Kucharski #endif
4391b8adde7SWilliam Kucharski 
4401b8adde7SWilliam Kucharski /* Check if DEVICE can be read. If an error occurs, return zero,
4411b8adde7SWilliam Kucharski    otherwise return non-zero.  */
4421b8adde7SWilliam Kucharski int
check_device(const char * device)4431b8adde7SWilliam Kucharski check_device (const char *device)
4441b8adde7SWilliam Kucharski {
4451b8adde7SWilliam Kucharski   char buf[512];
4461b8adde7SWilliam Kucharski   FILE *fp;
4471b8adde7SWilliam Kucharski 
4481b8adde7SWilliam Kucharski   /* If DEVICE is empty, just return 1.  */
4491b8adde7SWilliam Kucharski   if (*device == 0)
4501b8adde7SWilliam Kucharski     return 1;
4511b8adde7SWilliam Kucharski 
4521b8adde7SWilliam Kucharski   fp = fopen (device, "r");
4531b8adde7SWilliam Kucharski   if (! fp)
4541b8adde7SWilliam Kucharski     {
4551b8adde7SWilliam Kucharski       switch (errno)
4561b8adde7SWilliam Kucharski 	{
4571b8adde7SWilliam Kucharski #ifdef ENOMEDIUM
4581b8adde7SWilliam Kucharski 	case ENOMEDIUM:
4591b8adde7SWilliam Kucharski # if 0
4601b8adde7SWilliam Kucharski 	  /* At the moment, this finds only CDROMs, which can't be
4611b8adde7SWilliam Kucharski 	     read anyway, so leave it out. Code should be
4621b8adde7SWilliam Kucharski 	     reactivated if `removable disks' and CDROMs are
4631b8adde7SWilliam Kucharski 	     supported.  */
4641b8adde7SWilliam Kucharski 	  /* Accept it, it may be inserted.  */
4651b8adde7SWilliam Kucharski 	  return 1;
4661b8adde7SWilliam Kucharski # endif
4671b8adde7SWilliam Kucharski 	  break;
4681b8adde7SWilliam Kucharski #endif /* ENOMEDIUM */
4691b8adde7SWilliam Kucharski 	default:
4701b8adde7SWilliam Kucharski 	  /* Break case and leave.  */
4711b8adde7SWilliam Kucharski 	  break;
4721b8adde7SWilliam Kucharski 	}
4731b8adde7SWilliam Kucharski       /* Error opening the device.  */
4741b8adde7SWilliam Kucharski       return 0;
4751b8adde7SWilliam Kucharski     }
4761b8adde7SWilliam Kucharski 
4771b8adde7SWilliam Kucharski   /* Make sure CD-ROMs don't get assigned a BIOS disk number
4781b8adde7SWilliam Kucharski      before SCSI disks!  */
4791b8adde7SWilliam Kucharski #ifdef __linux__
4801b8adde7SWilliam Kucharski # ifdef CDROM_GET_CAPABILITY
4811b8adde7SWilliam Kucharski   if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
4821b8adde7SWilliam Kucharski     return 0;
4831b8adde7SWilliam Kucharski # else /* ! CDROM_GET_CAPABILITY */
4841b8adde7SWilliam Kucharski   /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl.  */
4851b8adde7SWilliam Kucharski   {
4861b8adde7SWilliam Kucharski     struct hd_geometry hdg;
4871b8adde7SWilliam Kucharski     struct stat st;
4881b8adde7SWilliam Kucharski 
4891b8adde7SWilliam Kucharski     if (fstat (fileno (fp), &st))
4901b8adde7SWilliam Kucharski       return 0;
4911b8adde7SWilliam Kucharski 
4921b8adde7SWilliam Kucharski     /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
4931b8adde7SWilliam Kucharski        succeeds.  */
4941b8adde7SWilliam Kucharski     if (S_ISBLK (st.st_mode)
4951b8adde7SWilliam Kucharski 	&& MAJOR (st.st_rdev) != FLOPPY_MAJOR
4961b8adde7SWilliam Kucharski 	&& ioctl (fileno (fp), HDIO_GETGEO, &hdg))
4971b8adde7SWilliam Kucharski       return 0;
4981b8adde7SWilliam Kucharski   }
4991b8adde7SWilliam Kucharski # endif /* ! CDROM_GET_CAPABILITY */
5001b8adde7SWilliam Kucharski #endif /* __linux__ */
5011b8adde7SWilliam Kucharski 
5021b8adde7SWilliam Kucharski #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
5031b8adde7SWilliam Kucharski # ifdef CDIOCCLRDEBUG
5041b8adde7SWilliam Kucharski   if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
5051b8adde7SWilliam Kucharski     return 0;
5061b8adde7SWilliam Kucharski # endif /* CDIOCCLRDEBUG */
5071b8adde7SWilliam Kucharski #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
5081b8adde7SWilliam Kucharski 
5091b8adde7SWilliam Kucharski   /* Attempt to read the first sector.  */
5101b8adde7SWilliam Kucharski   if (fread (buf, 1, 512, fp) != 512)
5111b8adde7SWilliam Kucharski     {
5121b8adde7SWilliam Kucharski       fclose (fp);
5131b8adde7SWilliam Kucharski       return 0;
5141b8adde7SWilliam Kucharski     }
5151b8adde7SWilliam Kucharski 
5161b8adde7SWilliam Kucharski   fclose (fp);
5171b8adde7SWilliam Kucharski   return 1;
5181b8adde7SWilliam Kucharski }
5191b8adde7SWilliam Kucharski 
5201b8adde7SWilliam Kucharski /* Read mapping information from FP, and write it to MAP.  */
5211b8adde7SWilliam Kucharski static int
read_device_map(FILE * fp,char ** map,const char * map_file)5221b8adde7SWilliam Kucharski read_device_map (FILE *fp, char **map, const char *map_file)
5231b8adde7SWilliam Kucharski {
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)
5281b8adde7SWilliam Kucharski     {
5291b8adde7SWilliam Kucharski       fprintf (stderr, "%s:%d: error: %s\n", map_file, no, msg);
5301b8adde7SWilliam Kucharski     }
5311b8adde7SWilliam Kucharski 
5321b8adde7SWilliam Kucharski   auto void show_warning (int no, const char *msg, ...)
5331b8adde7SWilliam Kucharski     {
5341b8adde7SWilliam Kucharski       va_list ap;
5351b8adde7SWilliam Kucharski 
5361b8adde7SWilliam Kucharski       va_start (ap, msg);
5371b8adde7SWilliam Kucharski       fprintf (stderr, "%s:%d: warning: ", map_file, no);
5381b8adde7SWilliam Kucharski       vfprintf (stderr, msg, ap);
5391b8adde7SWilliam Kucharski       va_end (ap);
5401b8adde7SWilliam Kucharski     }
5411b8adde7SWilliam Kucharski 
5421b8adde7SWilliam Kucharski   /* If there is the device map file, use the data in it instead of
5431b8adde7SWilliam Kucharski      probing devices.  */
5441b8adde7SWilliam Kucharski   char buf[1024];		/* XXX */
5451b8adde7SWilliam Kucharski   int line_number = 0;
5461b8adde7SWilliam Kucharski 
5471b8adde7SWilliam Kucharski   while (fgets (buf, sizeof (buf), fp))
5481b8adde7SWilliam Kucharski     {
5491b8adde7SWilliam Kucharski       char *ptr, *eptr;
5501b8adde7SWilliam Kucharski       int drive;
5511b8adde7SWilliam Kucharski       int is_floppy = 0;
5521b8adde7SWilliam Kucharski 
5531b8adde7SWilliam Kucharski       /* Increase the number of lines.  */
5541b8adde7SWilliam Kucharski       line_number++;
5551b8adde7SWilliam Kucharski 
5561b8adde7SWilliam Kucharski       /* If the first character is '#', skip it.  */
5571b8adde7SWilliam Kucharski       if (buf[0] == '#')
5581b8adde7SWilliam Kucharski 	continue;
5591b8adde7SWilliam Kucharski 
5601b8adde7SWilliam Kucharski       ptr = buf;
5611b8adde7SWilliam Kucharski       /* Skip leading spaces.  */
5621b8adde7SWilliam Kucharski       while (*ptr && isspace (*ptr))
5631b8adde7SWilliam Kucharski 	ptr++;
5641b8adde7SWilliam Kucharski 
5651b8adde7SWilliam Kucharski       /* Skip empty lines.  */
5661b8adde7SWilliam Kucharski       if (! *ptr)
5671b8adde7SWilliam Kucharski 	continue;
5681b8adde7SWilliam Kucharski 
5691b8adde7SWilliam Kucharski       if (*ptr != '(')
5701b8adde7SWilliam Kucharski 	{
5711b8adde7SWilliam Kucharski 	  show_error (line_number, "No open parenthesis found");
5721b8adde7SWilliam Kucharski 	  return 0;
5731b8adde7SWilliam Kucharski 	}
5741b8adde7SWilliam Kucharski 
5751b8adde7SWilliam Kucharski       ptr++;
5761b8adde7SWilliam Kucharski       if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd')
5771b8adde7SWilliam Kucharski 	{
5781b8adde7SWilliam Kucharski 	  show_error (line_number, "Bad drive name");
5791b8adde7SWilliam Kucharski 	  return 0;
5801b8adde7SWilliam Kucharski 	}
5811b8adde7SWilliam Kucharski 
5821b8adde7SWilliam Kucharski       if (*ptr == 'f')
5831b8adde7SWilliam Kucharski 	is_floppy = 1;
5841b8adde7SWilliam Kucharski 
5851b8adde7SWilliam Kucharski       ptr += 2;
5861b8adde7SWilliam Kucharski       drive = strtoul (ptr, &ptr, 10);
5871b8adde7SWilliam Kucharski       if (drive < 0)
5881b8adde7SWilliam Kucharski 	{
5891b8adde7SWilliam Kucharski 	  show_error (line_number, "Bad device number");
5901b8adde7SWilliam Kucharski 	  return 0;
5911b8adde7SWilliam Kucharski 	}
5921b8adde7SWilliam Kucharski       else if (drive > 127)
5931b8adde7SWilliam Kucharski 	{
5941b8adde7SWilliam Kucharski 	  show_warning (line_number,
5951b8adde7SWilliam Kucharski 			"Ignoring %cd%d due to a BIOS limitation",
5961b8adde7SWilliam Kucharski 			is_floppy ? 'f' : 'h', drive);
5971b8adde7SWilliam Kucharski 	  continue;
5981b8adde7SWilliam Kucharski 	}
5991b8adde7SWilliam Kucharski 
6001b8adde7SWilliam Kucharski       if (! is_floppy)
6011b8adde7SWilliam Kucharski 	drive += 0x80;
6021b8adde7SWilliam Kucharski 
6031b8adde7SWilliam Kucharski       if (*ptr != ')')
6041b8adde7SWilliam Kucharski 	{
6051b8adde7SWilliam Kucharski 	  show_error (line_number, "No close parenthesis found");
6061b8adde7SWilliam Kucharski 	  return 0;
6071b8adde7SWilliam Kucharski 	}
6081b8adde7SWilliam Kucharski 
6091b8adde7SWilliam Kucharski       ptr++;
6101b8adde7SWilliam Kucharski       /* Skip spaces.  */
6111b8adde7SWilliam Kucharski       while (*ptr && isspace (*ptr))
6121b8adde7SWilliam Kucharski 	ptr++;
6131b8adde7SWilliam Kucharski 
6141b8adde7SWilliam Kucharski       if (! *ptr)
6151b8adde7SWilliam Kucharski 	{
6161b8adde7SWilliam Kucharski 	  show_error (line_number, "No filename found");
6171b8adde7SWilliam Kucharski 	  return 0;
6181b8adde7SWilliam Kucharski 	}
6191b8adde7SWilliam Kucharski 
6201b8adde7SWilliam Kucharski       /* Terminate the filename.  */
6211b8adde7SWilliam Kucharski       eptr = ptr;
6221b8adde7SWilliam Kucharski       while (*eptr && ! isspace (*eptr))
6231b8adde7SWilliam Kucharski 	eptr++;
6241b8adde7SWilliam Kucharski       *eptr = 0;
6251b8adde7SWilliam Kucharski 
6261b8adde7SWilliam Kucharski       /* Multiple entries for a given drive is not allowed.  */
6271b8adde7SWilliam Kucharski       if (map[drive])
6281b8adde7SWilliam Kucharski 	{
6291b8adde7SWilliam Kucharski 	  show_error (line_number, "Duplicated entry found");
6301b8adde7SWilliam Kucharski 	  return 0;
6311b8adde7SWilliam Kucharski 	}
6321b8adde7SWilliam Kucharski 
6331b8adde7SWilliam Kucharski       map[drive] = strdup (ptr);
6341b8adde7SWilliam Kucharski       assert (map[drive]);
6351b8adde7SWilliam Kucharski     }
6361b8adde7SWilliam Kucharski 
6371b8adde7SWilliam Kucharski   return 1;
6381b8adde7SWilliam Kucharski }
6391b8adde7SWilliam Kucharski 
6401b8adde7SWilliam Kucharski /* Initialize the device map MAP. *MAP will be allocated from the heap
6411b8adde7SWilliam Kucharski    space. If MAP_FILE is not NULL, then read mappings from the file
6421b8adde7SWilliam Kucharski    MAP_FILE if it exists, otherwise, write guessed mappings to the file.
6431b8adde7SWilliam Kucharski    FLOPPY_DISKS is the number of floppy disk drives which will be probed.
6441b8adde7SWilliam Kucharski    If it is zero, don't probe any floppy at all. If it is one, probe one
6451b8adde7SWilliam Kucharski    floppy. If it is two, probe two floppies. And so on.  */
6461b8adde7SWilliam Kucharski int
init_device_map(char *** map,const char * map_file,int floppy_disks)6471b8adde7SWilliam Kucharski init_device_map (char ***map, const char *map_file, int floppy_disks)
6481b8adde7SWilliam Kucharski {
6491b8adde7SWilliam Kucharski   int i;
6501b8adde7SWilliam Kucharski   int num_hd = 0;
6511b8adde7SWilliam Kucharski   FILE *fp = 0;
6521b8adde7SWilliam Kucharski 
6531b8adde7SWilliam Kucharski   assert (map);
6541b8adde7SWilliam Kucharski   assert (*map == 0);
6551b8adde7SWilliam Kucharski   *map = malloc (NUM_DISKS * sizeof (char *));
6561b8adde7SWilliam Kucharski   assert (*map);
6571b8adde7SWilliam Kucharski 
6581b8adde7SWilliam Kucharski   /* Probe devices for creating the device map.  */
6591b8adde7SWilliam Kucharski 
6601b8adde7SWilliam Kucharski   /* Initialize DEVICE_MAP.  */
6611b8adde7SWilliam Kucharski   for (i = 0; i < NUM_DISKS; i++)
6621b8adde7SWilliam Kucharski     (*map)[i] = 0;
6631b8adde7SWilliam Kucharski 
6641b8adde7SWilliam Kucharski   if (map_file)
6651b8adde7SWilliam Kucharski     {
6661b8adde7SWilliam Kucharski       /* Open the device map file.  */
6671b8adde7SWilliam Kucharski       fp = fopen (map_file, "r");
6681b8adde7SWilliam Kucharski       if (fp)
6691b8adde7SWilliam Kucharski 	{
6701b8adde7SWilliam Kucharski 	  int ret;
6711b8adde7SWilliam Kucharski 
6721b8adde7SWilliam Kucharski 	  ret = read_device_map (fp, *map, map_file);
6731b8adde7SWilliam Kucharski 	  fclose (fp);
6741b8adde7SWilliam Kucharski 	  return ret;
6751b8adde7SWilliam Kucharski 	}
6761b8adde7SWilliam Kucharski     }
6771b8adde7SWilliam Kucharski 
6781b8adde7SWilliam Kucharski   /* Print something so that the user does not think GRUB has been
6791b8adde7SWilliam Kucharski      crashed.  */
6801b8adde7SWilliam Kucharski   fprintf (stderr,
6811b8adde7SWilliam Kucharski 	   "Probing devices to guess BIOS drives. "
6821b8adde7SWilliam Kucharski 	   "This may take a long time.\n");
6831b8adde7SWilliam Kucharski 
6841b8adde7SWilliam Kucharski   if (map_file)
6851b8adde7SWilliam Kucharski     /* Try to open the device map file to write the probed data.  */
6861b8adde7SWilliam Kucharski     fp = fopen (map_file, "w");
6871b8adde7SWilliam Kucharski 
6881b8adde7SWilliam Kucharski   /* Floppies.  */
6891b8adde7SWilliam Kucharski   for (i = 0; i < floppy_disks; i++)
6901b8adde7SWilliam Kucharski     {
6911b8adde7SWilliam Kucharski       char name[16];
6921b8adde7SWilliam Kucharski 
6931b8adde7SWilliam Kucharski       get_floppy_disk_name (name, i);
6941b8adde7SWilliam Kucharski       /* In floppies, write the map, whether check_device succeeds
6951b8adde7SWilliam Kucharski 	 or not, because the user just does not insert floppies.  */
6961b8adde7SWilliam Kucharski       if (fp)
6971b8adde7SWilliam Kucharski 	fprintf (fp, "(fd%d)\t%s\n", i, name);
6981b8adde7SWilliam Kucharski 
6991b8adde7SWilliam Kucharski       if (check_device (name))
7001b8adde7SWilliam Kucharski 	{
7011b8adde7SWilliam Kucharski 	  (*map)[i] = strdup (name);
7021b8adde7SWilliam Kucharski 	  assert ((*map)[i]);
7031b8adde7SWilliam Kucharski 	}
7041b8adde7SWilliam Kucharski     }
7051b8adde7SWilliam Kucharski 
7061b8adde7SWilliam Kucharski #ifdef __linux__
7071b8adde7SWilliam Kucharski   if (have_devfs ())
7081b8adde7SWilliam Kucharski     {
7091b8adde7SWilliam Kucharski       while (1)
7101b8adde7SWilliam Kucharski 	{
7111b8adde7SWilliam Kucharski 	  char discn[32];
7121b8adde7SWilliam Kucharski 	  char name[PATH_MAX];
7131b8adde7SWilliam Kucharski 	  struct stat st;
7141b8adde7SWilliam Kucharski 
7151b8adde7SWilliam Kucharski 	  /* Linux creates symlinks "/dev/discs/discN" for convenience.
7161b8adde7SWilliam Kucharski 	     The way to number disks is the same as GRUB's.  */
7171b8adde7SWilliam Kucharski 	  sprintf (discn, "/dev/discs/disc%d", num_hd);
7181b8adde7SWilliam Kucharski 	  if (stat (discn, &st) < 0)
7191b8adde7SWilliam Kucharski 	    break;
7201b8adde7SWilliam Kucharski 
7211b8adde7SWilliam Kucharski 	  if (realpath (discn, name))
7221b8adde7SWilliam Kucharski 	    {
7231b8adde7SWilliam Kucharski 	      strcat (name, "/disc");
7241b8adde7SWilliam Kucharski 	      (*map)[num_hd + 0x80] = strdup (name);
7251b8adde7SWilliam Kucharski 	      assert ((*map)[num_hd + 0x80]);
7261b8adde7SWilliam Kucharski 
7271b8adde7SWilliam Kucharski 	      /* If the device map file is opened, write the map.  */
7281b8adde7SWilliam Kucharski 	      if (fp)
7291b8adde7SWilliam Kucharski 		fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7301b8adde7SWilliam Kucharski 	    }
7311b8adde7SWilliam Kucharski 
7321b8adde7SWilliam Kucharski 	  num_hd++;
7331b8adde7SWilliam Kucharski 	}
7341b8adde7SWilliam Kucharski 
7351b8adde7SWilliam Kucharski       /* OK, close the device map file if opened.  */
7361b8adde7SWilliam Kucharski       if (fp)
7371b8adde7SWilliam Kucharski 	fclose (fp);
7381b8adde7SWilliam Kucharski 
7391b8adde7SWilliam Kucharski       return 1;
7401b8adde7SWilliam Kucharski     }
7411b8adde7SWilliam Kucharski #endif /* __linux__ */
7421b8adde7SWilliam Kucharski 
7431b8adde7SWilliam Kucharski   /* IDE disks.  */
7441b8adde7SWilliam Kucharski   for (i = 0; i < 8; i++)
7451b8adde7SWilliam Kucharski     {
7461b8adde7SWilliam Kucharski       char name[16];
7471b8adde7SWilliam Kucharski 
7481b8adde7SWilliam Kucharski       get_ide_disk_name (name, i);
7491b8adde7SWilliam Kucharski       if (check_device (name))
7501b8adde7SWilliam Kucharski 	{
7511b8adde7SWilliam Kucharski 	  (*map)[num_hd + 0x80] = strdup (name);
7521b8adde7SWilliam Kucharski 	  assert ((*map)[num_hd + 0x80]);
7531b8adde7SWilliam Kucharski 
7541b8adde7SWilliam Kucharski 	  /* If the device map file is opened, write the map.  */
7551b8adde7SWilliam Kucharski 	  if (fp)
7561b8adde7SWilliam Kucharski 	    fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7571b8adde7SWilliam Kucharski 
7581b8adde7SWilliam Kucharski 	  num_hd++;
7591b8adde7SWilliam Kucharski 	}
7601b8adde7SWilliam Kucharski     }
7611b8adde7SWilliam Kucharski 
7621b8adde7SWilliam Kucharski #ifdef __linux__
7631b8adde7SWilliam Kucharski   /* ATARAID disks.  */
7641b8adde7SWilliam Kucharski   for (i = 0; i < 8; i++)
7651b8adde7SWilliam Kucharski     {
7661b8adde7SWilliam Kucharski       char name[20];
7671b8adde7SWilliam Kucharski 
7681b8adde7SWilliam Kucharski       get_ataraid_disk_name (name, i);
7691b8adde7SWilliam Kucharski       if (check_device (name))
7701b8adde7SWilliam Kucharski         {
7711b8adde7SWilliam Kucharski           (*map)[num_hd + 0x80] = strdup (name);
7721b8adde7SWilliam Kucharski           assert ((*map)[num_hd + 0x80]);
7731b8adde7SWilliam Kucharski 
7741b8adde7SWilliam Kucharski           /* If the device map file is opened, write the map.  */
7751b8adde7SWilliam Kucharski           if (fp)
7761b8adde7SWilliam Kucharski             fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7771b8adde7SWilliam Kucharski 
7781b8adde7SWilliam Kucharski           num_hd++;
7791b8adde7SWilliam Kucharski         }
7801b8adde7SWilliam Kucharski     }
7811b8adde7SWilliam Kucharski #endif /* __linux__ */
7821b8adde7SWilliam Kucharski 
7831b8adde7SWilliam Kucharski   /* The rest is SCSI disks.  */
7841b8adde7SWilliam Kucharski   for (i = 0; i < 16; i++)
7851b8adde7SWilliam Kucharski     {
7861b8adde7SWilliam Kucharski       char name[16];
7871b8adde7SWilliam Kucharski 
7881b8adde7SWilliam Kucharski       get_scsi_disk_name (name, i);
7891b8adde7SWilliam Kucharski       if (check_device (name))
7901b8adde7SWilliam Kucharski 	{
7911b8adde7SWilliam Kucharski 	  (*map)[num_hd + 0x80] = strdup (name);
7921b8adde7SWilliam Kucharski 	  assert ((*map)[num_hd + 0x80]);
7931b8adde7SWilliam Kucharski 
7941b8adde7SWilliam Kucharski 	  /* If the device map file is opened, write the map.  */
7951b8adde7SWilliam Kucharski 	  if (fp)
7961b8adde7SWilliam Kucharski 	    fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7971b8adde7SWilliam Kucharski 
7981b8adde7SWilliam Kucharski 	  num_hd++;
7991b8adde7SWilliam Kucharski 	}
8001b8adde7SWilliam Kucharski     }
8011b8adde7SWilliam Kucharski 
8021b8adde7SWilliam Kucharski #ifdef __linux__
8031b8adde7SWilliam Kucharski   /* This is for DAC960 - we have
8041b8adde7SWilliam Kucharski      /dev/rd/c<controller>d<logical drive>p<partition>.
8051b8adde7SWilliam Kucharski 
8061b8adde7SWilliam Kucharski      DAC960 driver currently supports up to 8 controllers, 32 logical
8071b8adde7SWilliam Kucharski      drives, and 7 partitions.  */
8081b8adde7SWilliam Kucharski   {
8091b8adde7SWilliam Kucharski     int controller, drive;
8101b8adde7SWilliam Kucharski 
8111b8adde7SWilliam Kucharski     for (controller = 0; controller < 8; controller++)
8121b8adde7SWilliam Kucharski       {
8131b8adde7SWilliam Kucharski 	for (drive = 0; drive < 15; drive++)
8141b8adde7SWilliam Kucharski 	  {
8151b8adde7SWilliam Kucharski 	    char name[24];
8161b8adde7SWilliam Kucharski 
8171b8adde7SWilliam Kucharski 	    get_dac960_disk_name (name, controller, drive);
8181b8adde7SWilliam Kucharski 	    if (check_device (name))
8191b8adde7SWilliam Kucharski 	      {
8201b8adde7SWilliam Kucharski 		(*map)[num_hd + 0x80] = strdup (name);
8211b8adde7SWilliam Kucharski 		assert ((*map)[num_hd + 0x80]);
8221b8adde7SWilliam Kucharski 
8231b8adde7SWilliam Kucharski 		/* If the device map file is opened, write the map.  */
8241b8adde7SWilliam Kucharski 		if (fp)
8251b8adde7SWilliam Kucharski 		  fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
8261b8adde7SWilliam Kucharski 
8271b8adde7SWilliam Kucharski 		num_hd++;
8281b8adde7SWilliam Kucharski 	      }
8291b8adde7SWilliam Kucharski 	  }
8301b8adde7SWilliam Kucharski       }
8311b8adde7SWilliam Kucharski   }
8321b8adde7SWilliam Kucharski #endif /* __linux__ */
8331b8adde7SWilliam Kucharski 
8341b8adde7SWilliam Kucharski   /* OK, close the device map file if opened.  */
8351b8adde7SWilliam Kucharski   if (fp)
8361b8adde7SWilliam Kucharski     fclose (fp);
8371b8adde7SWilliam Kucharski 
8381b8adde7SWilliam Kucharski   return 1;
8391b8adde7SWilliam Kucharski }
8401b8adde7SWilliam Kucharski 
8411b8adde7SWilliam Kucharski /* Restore the memory consumed for MAP.  */
8421b8adde7SWilliam Kucharski void
restore_device_map(char ** map)8431b8adde7SWilliam Kucharski restore_device_map (char **map)
8441b8adde7SWilliam Kucharski {
8451b8adde7SWilliam Kucharski   int i;
8461b8adde7SWilliam Kucharski 
8471b8adde7SWilliam Kucharski   for (i = 0; i < NUM_DISKS; i++)
8481b8adde7SWilliam Kucharski     if (map[i])
8491b8adde7SWilliam Kucharski       free (map[i]);
8501b8adde7SWilliam Kucharski 
8511b8adde7SWilliam Kucharski   free (map);
8521b8adde7SWilliam Kucharski }
8531b8adde7SWilliam Kucharski 
8541b8adde7SWilliam Kucharski #ifdef __linux__
8551b8adde7SWilliam Kucharski /* Linux-only functions, because Linux has a bug that the disk cache for
8561b8adde7SWilliam Kucharski    a whole disk is not consistent with the one for a partition of the
8571b8adde7SWilliam Kucharski    disk.  */
8581b8adde7SWilliam Kucharski int
is_disk_device(char ** map,int drive)8591b8adde7SWilliam Kucharski is_disk_device (char **map, int drive)
8601b8adde7SWilliam Kucharski {
8611b8adde7SWilliam Kucharski   struct stat st;
8621b8adde7SWilliam Kucharski 
8631b8adde7SWilliam Kucharski   assert (map[drive] != 0);
8641b8adde7SWilliam Kucharski   assert (stat (map[drive], &st) == 0);
8651b8adde7SWilliam Kucharski   /* For now, disk devices under Linux are all block devices.  */
8661b8adde7SWilliam Kucharski   return S_ISBLK (st.st_mode);
8671b8adde7SWilliam Kucharski }
8681b8adde7SWilliam Kucharski 
8691b8adde7SWilliam Kucharski int
write_to_partition(char ** map,int drive,int partition,int sector,int size,const char * buf)8701b8adde7SWilliam Kucharski write_to_partition (char **map, int drive, int partition,
8711b8adde7SWilliam Kucharski 		    int sector, int size, const char *buf)
8721b8adde7SWilliam Kucharski {
8731b8adde7SWilliam Kucharski   char dev[PATH_MAX];	/* XXX */
8741b8adde7SWilliam Kucharski   int fd;
8751b8adde7SWilliam Kucharski 
8761b8adde7SWilliam Kucharski   if ((partition & 0x00FF00) != 0x00FF00)
8771b8adde7SWilliam Kucharski     {
8781b8adde7SWilliam Kucharski       /* If the partition is a BSD partition, it is difficult to
8791b8adde7SWilliam Kucharski 	 obtain the representation in Linux. So don't support that.  */
8801b8adde7SWilliam Kucharski       errnum = ERR_DEV_VALUES;
8811b8adde7SWilliam Kucharski       return 1;
8821b8adde7SWilliam Kucharski     }
8831b8adde7SWilliam Kucharski 
8841b8adde7SWilliam Kucharski   assert (map[drive] != 0);
8851b8adde7SWilliam Kucharski 
8861b8adde7SWilliam Kucharski   strcpy (dev, map[drive]);
8871b8adde7SWilliam Kucharski   if (have_devfs ())
8881b8adde7SWilliam Kucharski     {
8891b8adde7SWilliam Kucharski       if (strcmp (dev + strlen(dev) - 5, "/disc") == 0)
8901b8adde7SWilliam Kucharski 	strcpy (dev + strlen(dev) - 5, "/part");
8911b8adde7SWilliam Kucharski     }
8921b8adde7SWilliam Kucharski   sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1);
8931b8adde7SWilliam Kucharski 
8941b8adde7SWilliam Kucharski   /* Open the partition.  */
8951b8adde7SWilliam Kucharski   fd = open (dev, O_RDWR);
8961b8adde7SWilliam Kucharski   if (fd < 0)
8971b8adde7SWilliam Kucharski     {
8981b8adde7SWilliam Kucharski       errnum = ERR_NO_PART;
8991b8adde7SWilliam Kucharski       return 0;
9001b8adde7SWilliam Kucharski     }
9011b8adde7SWilliam Kucharski 
9021b8adde7SWilliam Kucharski #if defined(__linux__) && (!defined(__GLIBC__) || \
9031b8adde7SWilliam Kucharski         ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
9041b8adde7SWilliam Kucharski   /* Maybe libc doesn't have large file support.  */
9051b8adde7SWilliam Kucharski   {
9061b8adde7SWilliam Kucharski     loff_t offset, result;
9071b8adde7SWilliam Kucharski     static int _llseek (uint filedes, ulong hi, ulong lo,
9081b8adde7SWilliam Kucharski                         loff_t *res, uint wh);
9091b8adde7SWilliam Kucharski     _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
9101b8adde7SWilliam Kucharski                loff_t *, res, uint, wh);
9111b8adde7SWilliam Kucharski 
9121b8adde7SWilliam Kucharski     offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
9131b8adde7SWilliam Kucharski     if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
9141b8adde7SWilliam Kucharski       {
9151b8adde7SWilliam Kucharski 	errnum = ERR_DEV_VALUES;
9161b8adde7SWilliam Kucharski 	return 0;
9171b8adde7SWilliam Kucharski       }
9181b8adde7SWilliam Kucharski   }
9191b8adde7SWilliam Kucharski #else
9201b8adde7SWilliam Kucharski   {
9211b8adde7SWilliam Kucharski     off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
9221b8adde7SWilliam Kucharski 
9231b8adde7SWilliam Kucharski     if (lseek (fd, offset, SEEK_SET) != offset)
9241b8adde7SWilliam Kucharski       {
9251b8adde7SWilliam Kucharski 	errnum = ERR_DEV_VALUES;
9261b8adde7SWilliam Kucharski 	return 0;
9271b8adde7SWilliam Kucharski       }
9281b8adde7SWilliam Kucharski   }
9291b8adde7SWilliam Kucharski #endif
9301b8adde7SWilliam Kucharski 
9311b8adde7SWilliam Kucharski   if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE))
9321b8adde7SWilliam Kucharski     {
9331b8adde7SWilliam Kucharski       close (fd);
9341b8adde7SWilliam Kucharski       errnum = ERR_WRITE;
9351b8adde7SWilliam Kucharski       return 0;
9361b8adde7SWilliam Kucharski     }
9371b8adde7SWilliam Kucharski 
9381b8adde7SWilliam Kucharski   sync ();	/* Paranoia.  */
9391b8adde7SWilliam Kucharski   close (fd);
9401b8adde7SWilliam Kucharski 
9411b8adde7SWilliam Kucharski   return 1;
9421b8adde7SWilliam Kucharski }
9431b8adde7SWilliam Kucharski #endif /* __linux__ */
944