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, §or_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