18044SWilliam.Kucharski@Sun.COM /* device.c - Some helper functions for OS devices and BIOS drives */
28044SWilliam.Kucharski@Sun.COM /*
38044SWilliam.Kucharski@Sun.COM * GRUB -- GRand Unified Bootloader
48044SWilliam.Kucharski@Sun.COM * Copyright (C) 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc.
58044SWilliam.Kucharski@Sun.COM *
68044SWilliam.Kucharski@Sun.COM * This program is free software; you can redistribute it and/or modify
78044SWilliam.Kucharski@Sun.COM * it under the terms of the GNU General Public License as published by
88044SWilliam.Kucharski@Sun.COM * the Free Software Foundation; either version 2 of the License, or
98044SWilliam.Kucharski@Sun.COM * (at your option) any later version.
108044SWilliam.Kucharski@Sun.COM *
118044SWilliam.Kucharski@Sun.COM * This program is distributed in the hope that it will be useful,
128044SWilliam.Kucharski@Sun.COM * but WITHOUT ANY WARRANTY; without even the implied warranty of
138044SWilliam.Kucharski@Sun.COM * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
148044SWilliam.Kucharski@Sun.COM * GNU General Public License for more details.
158044SWilliam.Kucharski@Sun.COM *
168044SWilliam.Kucharski@Sun.COM * You should have received a copy of the GNU General Public License
178044SWilliam.Kucharski@Sun.COM * along with this program; if not, write to the Free Software
188044SWilliam.Kucharski@Sun.COM * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
198044SWilliam.Kucharski@Sun.COM */
208044SWilliam.Kucharski@Sun.COM
218044SWilliam.Kucharski@Sun.COM /* Try to use glibc's transparant LFS support. */
228044SWilliam.Kucharski@Sun.COM #define _LARGEFILE_SOURCE 1
238044SWilliam.Kucharski@Sun.COM /* lseek becomes synonymous with lseek64. */
248044SWilliam.Kucharski@Sun.COM #define _FILE_OFFSET_BITS 64
258044SWilliam.Kucharski@Sun.COM
268044SWilliam.Kucharski@Sun.COM #include <stdio.h>
278044SWilliam.Kucharski@Sun.COM #include <stdlib.h>
288044SWilliam.Kucharski@Sun.COM #include <string.h>
298044SWilliam.Kucharski@Sun.COM #include <ctype.h>
308044SWilliam.Kucharski@Sun.COM #include <assert.h>
318044SWilliam.Kucharski@Sun.COM #include <unistd.h>
328044SWilliam.Kucharski@Sun.COM #include <sys/types.h>
338044SWilliam.Kucharski@Sun.COM #include <sys/stat.h>
348044SWilliam.Kucharski@Sun.COM #include <fcntl.h>
358044SWilliam.Kucharski@Sun.COM #include <errno.h>
368044SWilliam.Kucharski@Sun.COM #include <limits.h>
378044SWilliam.Kucharski@Sun.COM #include <stdarg.h>
388044SWilliam.Kucharski@Sun.COM
398044SWilliam.Kucharski@Sun.COM #ifdef __linux__
408044SWilliam.Kucharski@Sun.COM # if !defined(__GLIBC__) || \
418044SWilliam.Kucharski@Sun.COM ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
428044SWilliam.Kucharski@Sun.COM /* Maybe libc doesn't have large file support. */
438044SWilliam.Kucharski@Sun.COM # include <linux/unistd.h> /* _llseek */
448044SWilliam.Kucharski@Sun.COM # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
458044SWilliam.Kucharski@Sun.COM # include <sys/ioctl.h> /* ioctl */
468044SWilliam.Kucharski@Sun.COM # ifndef HDIO_GETGEO
478044SWilliam.Kucharski@Sun.COM # define HDIO_GETGEO 0x0301 /* get device geometry */
488044SWilliam.Kucharski@Sun.COM /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
498044SWilliam.Kucharski@Sun.COM defined. */
508044SWilliam.Kucharski@Sun.COM struct hd_geometry
518044SWilliam.Kucharski@Sun.COM {
528044SWilliam.Kucharski@Sun.COM unsigned char heads;
538044SWilliam.Kucharski@Sun.COM unsigned char sectors;
548044SWilliam.Kucharski@Sun.COM unsigned short cylinders;
558044SWilliam.Kucharski@Sun.COM unsigned long start;
568044SWilliam.Kucharski@Sun.COM };
578044SWilliam.Kucharski@Sun.COM # endif /* ! HDIO_GETGEO */
588044SWilliam.Kucharski@Sun.COM # ifndef FLOPPY_MAJOR
598044SWilliam.Kucharski@Sun.COM # define FLOPPY_MAJOR 2 /* the major number for floppy */
608044SWilliam.Kucharski@Sun.COM # endif /* ! FLOPPY_MAJOR */
618044SWilliam.Kucharski@Sun.COM # ifndef MAJOR
628044SWilliam.Kucharski@Sun.COM # define MAJOR(dev) \
638044SWilliam.Kucharski@Sun.COM ({ \
648044SWilliam.Kucharski@Sun.COM unsigned long long __dev = (dev); \
658044SWilliam.Kucharski@Sun.COM (unsigned) ((__dev >> 8) & 0xfff) \
668044SWilliam.Kucharski@Sun.COM | ((unsigned int) (__dev >> 32) & ~0xfff); \
678044SWilliam.Kucharski@Sun.COM })
688044SWilliam.Kucharski@Sun.COM # endif /* ! MAJOR */
698044SWilliam.Kucharski@Sun.COM # ifndef CDROM_GET_CAPABILITY
708044SWilliam.Kucharski@Sun.COM # define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
718044SWilliam.Kucharski@Sun.COM # endif /* ! CDROM_GET_CAPABILITY */
728044SWilliam.Kucharski@Sun.COM # ifndef BLKGETSIZE
738044SWilliam.Kucharski@Sun.COM # define BLKGETSIZE _IO(0x12,96) /* return device size */
748044SWilliam.Kucharski@Sun.COM # endif /* ! BLKGETSIZE */
758044SWilliam.Kucharski@Sun.COM #endif /* __linux__ */
768044SWilliam.Kucharski@Sun.COM
778044SWilliam.Kucharski@Sun.COM /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
788044SWilliam.Kucharski@Sun.COM kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */
798044SWilliam.Kucharski@Sun.COM #if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__)
808044SWilliam.Kucharski@Sun.COM # define __FreeBSD_kernel__
818044SWilliam.Kucharski@Sun.COM #endif
828044SWilliam.Kucharski@Sun.COM #ifdef __FreeBSD_kernel__
838044SWilliam.Kucharski@Sun.COM /* Obtain version of kFreeBSD headers */
848044SWilliam.Kucharski@Sun.COM # include <osreldate.h>
858044SWilliam.Kucharski@Sun.COM # ifndef __FreeBSD_kernel_version
868044SWilliam.Kucharski@Sun.COM # define __FreeBSD_kernel_version __FreeBSD_version
878044SWilliam.Kucharski@Sun.COM # endif
888044SWilliam.Kucharski@Sun.COM
898044SWilliam.Kucharski@Sun.COM /* Runtime detection of kernel */
908044SWilliam.Kucharski@Sun.COM # include <sys/utsname.h>
918044SWilliam.Kucharski@Sun.COM int
get_kfreebsd_version()928044SWilliam.Kucharski@Sun.COM get_kfreebsd_version ()
938044SWilliam.Kucharski@Sun.COM {
948044SWilliam.Kucharski@Sun.COM struct utsname uts;
958044SWilliam.Kucharski@Sun.COM int major; int minor, v[2];
968044SWilliam.Kucharski@Sun.COM
978044SWilliam.Kucharski@Sun.COM uname (&uts);
988044SWilliam.Kucharski@Sun.COM sscanf (uts.release, "%d.%d", &major, &minor);
998044SWilliam.Kucharski@Sun.COM
1008044SWilliam.Kucharski@Sun.COM if (major >= 9)
1018044SWilliam.Kucharski@Sun.COM major = 9;
1028044SWilliam.Kucharski@Sun.COM if (major >= 5)
1038044SWilliam.Kucharski@Sun.COM {
1048044SWilliam.Kucharski@Sun.COM v[0] = minor/10; v[1] = minor%10;
1058044SWilliam.Kucharski@Sun.COM }
1068044SWilliam.Kucharski@Sun.COM else
1078044SWilliam.Kucharski@Sun.COM {
1088044SWilliam.Kucharski@Sun.COM v[0] = minor%10; v[1] = minor/10;
1098044SWilliam.Kucharski@Sun.COM }
1108044SWilliam.Kucharski@Sun.COM return major*100000+v[0]*10000+v[1]*1000;
1118044SWilliam.Kucharski@Sun.COM }
1128044SWilliam.Kucharski@Sun.COM #endif /* __FreeBSD_kernel__ */
1138044SWilliam.Kucharski@Sun.COM
1148044SWilliam.Kucharski@Sun.COM #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
1158044SWilliam.Kucharski@Sun.COM # include <sys/ioctl.h> /* ioctl */
1168044SWilliam.Kucharski@Sun.COM # include <sys/disklabel.h>
1178044SWilliam.Kucharski@Sun.COM # include <sys/cdio.h> /* CDIOCCLRDEBUG */
1188044SWilliam.Kucharski@Sun.COM # if defined(__FreeBSD_kernel__)
1198044SWilliam.Kucharski@Sun.COM # include <sys/param.h>
1208044SWilliam.Kucharski@Sun.COM # if __FreeBSD_kernel_version >= 500040
1218044SWilliam.Kucharski@Sun.COM # include <sys/disk.h>
1228044SWilliam.Kucharski@Sun.COM # endif
1238044SWilliam.Kucharski@Sun.COM # endif /* __FreeBSD_kernel__ */
1248044SWilliam.Kucharski@Sun.COM #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
1258044SWilliam.Kucharski@Sun.COM
1268044SWilliam.Kucharski@Sun.COM #if defined(__sun)
1278044SWilliam.Kucharski@Sun.COM # include <sys/dkio.h>
1288044SWilliam.Kucharski@Sun.COM #endif /* __sun */
1298044SWilliam.Kucharski@Sun.COM
1308044SWilliam.Kucharski@Sun.COM #ifdef HAVE_OPENDISK
1318044SWilliam.Kucharski@Sun.COM # include <util.h>
1328044SWilliam.Kucharski@Sun.COM #endif /* HAVE_OPENDISK */
1338044SWilliam.Kucharski@Sun.COM
1348044SWilliam.Kucharski@Sun.COM #define WITHOUT_LIBC_STUBS 1
1358044SWilliam.Kucharski@Sun.COM #include <shared.h>
1368044SWilliam.Kucharski@Sun.COM #include <device.h>
1378044SWilliam.Kucharski@Sun.COM
1388044SWilliam.Kucharski@Sun.COM /* Get the geometry of a drive DRIVE. */
1398044SWilliam.Kucharski@Sun.COM void
get_drive_geometry(struct geometry * geom,char ** map,int drive)1408044SWilliam.Kucharski@Sun.COM get_drive_geometry (struct geometry *geom, char **map, int drive)
1418044SWilliam.Kucharski@Sun.COM {
1428044SWilliam.Kucharski@Sun.COM int fd;
1438044SWilliam.Kucharski@Sun.COM
1448044SWilliam.Kucharski@Sun.COM if (geom->flags == -1)
1458044SWilliam.Kucharski@Sun.COM {
1468044SWilliam.Kucharski@Sun.COM fd = open (map[drive], O_RDONLY);
1478044SWilliam.Kucharski@Sun.COM assert (fd >= 0);
1488044SWilliam.Kucharski@Sun.COM }
1498044SWilliam.Kucharski@Sun.COM else
1508044SWilliam.Kucharski@Sun.COM fd = geom->flags;
1518044SWilliam.Kucharski@Sun.COM
1528044SWilliam.Kucharski@Sun.COM /* XXX This is the default size. */
1538044SWilliam.Kucharski@Sun.COM geom->sector_size = SECTOR_SIZE;
1548044SWilliam.Kucharski@Sun.COM
1558044SWilliam.Kucharski@Sun.COM #if defined(__linux__)
1568044SWilliam.Kucharski@Sun.COM /* Linux */
1578044SWilliam.Kucharski@Sun.COM {
1588044SWilliam.Kucharski@Sun.COM struct hd_geometry hdg;
1598044SWilliam.Kucharski@Sun.COM unsigned long nr;
1608044SWilliam.Kucharski@Sun.COM
1618044SWilliam.Kucharski@Sun.COM if (ioctl (fd, HDIO_GETGEO, &hdg))
1628044SWilliam.Kucharski@Sun.COM goto fail;
1638044SWilliam.Kucharski@Sun.COM
1648044SWilliam.Kucharski@Sun.COM if (ioctl (fd, BLKGETSIZE, &nr))
1658044SWilliam.Kucharski@Sun.COM goto fail;
1668044SWilliam.Kucharski@Sun.COM
1678044SWilliam.Kucharski@Sun.COM /* Got the geometry, so save it. */
1688044SWilliam.Kucharski@Sun.COM geom->cylinders = hdg.cylinders;
1698044SWilliam.Kucharski@Sun.COM geom->heads = hdg.heads;
1708044SWilliam.Kucharski@Sun.COM geom->sectors = hdg.sectors;
1718044SWilliam.Kucharski@Sun.COM geom->total_sectors = nr;
1728044SWilliam.Kucharski@Sun.COM
1738044SWilliam.Kucharski@Sun.COM goto success;
1748044SWilliam.Kucharski@Sun.COM }
1758044SWilliam.Kucharski@Sun.COM
1768044SWilliam.Kucharski@Sun.COM #elif defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
1778044SWilliam.Kucharski@Sun.COM # if defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040
1788044SWilliam.Kucharski@Sun.COM /* kFreeBSD version 5 or later */
1798044SWilliam.Kucharski@Sun.COM if (get_kfreebsd_version () >= 500040)
1808044SWilliam.Kucharski@Sun.COM {
1818044SWilliam.Kucharski@Sun.COM unsigned int sector_size;
1828044SWilliam.Kucharski@Sun.COM off_t media_size;
1838044SWilliam.Kucharski@Sun.COM unsigned int tmp;
1848044SWilliam.Kucharski@Sun.COM
1858044SWilliam.Kucharski@Sun.COM if(ioctl (fd, DIOCGSECTORSIZE, §or_size) != 0)
1868044SWilliam.Kucharski@Sun.COM sector_size = 512;
1878044SWilliam.Kucharski@Sun.COM
1888044SWilliam.Kucharski@Sun.COM if (ioctl (fd, DIOCGMEDIASIZE, &media_size) != 0)
1898044SWilliam.Kucharski@Sun.COM goto fail;
1908044SWilliam.Kucharski@Sun.COM
1918044SWilliam.Kucharski@Sun.COM geom->total_sectors = media_size / sector_size;
1928044SWilliam.Kucharski@Sun.COM
1938044SWilliam.Kucharski@Sun.COM if (ioctl (fd, DIOCGFWSECTORS, &tmp) == 0)
1948044SWilliam.Kucharski@Sun.COM geom->sectors = tmp;
1958044SWilliam.Kucharski@Sun.COM else
1968044SWilliam.Kucharski@Sun.COM geom->sectors = 63;
1978044SWilliam.Kucharski@Sun.COM if (ioctl (fd, DIOCGFWHEADS, &tmp) == 0)
1988044SWilliam.Kucharski@Sun.COM geom->heads = tmp;
1998044SWilliam.Kucharski@Sun.COM else if (geom->total_sectors <= 63 * 1 * 1024)
2008044SWilliam.Kucharski@Sun.COM geom->heads = 1;
2018044SWilliam.Kucharski@Sun.COM else if (geom->total_sectors <= 63 * 16 * 1024)
2028044SWilliam.Kucharski@Sun.COM geom->heads = 16;
2038044SWilliam.Kucharski@Sun.COM else
2048044SWilliam.Kucharski@Sun.COM geom->heads = 255;
2058044SWilliam.Kucharski@Sun.COM
2068044SWilliam.Kucharski@Sun.COM geom->cylinders = (geom->total_sectors
2078044SWilliam.Kucharski@Sun.COM / geom->heads
2088044SWilliam.Kucharski@Sun.COM / geom->sectors);
2098044SWilliam.Kucharski@Sun.COM
2108044SWilliam.Kucharski@Sun.COM goto success;
2118044SWilliam.Kucharski@Sun.COM }
2128044SWilliam.Kucharski@Sun.COM else
2138044SWilliam.Kucharski@Sun.COM #endif /* defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040 */
2148044SWilliam.Kucharski@Sun.COM
2158044SWilliam.Kucharski@Sun.COM /* kFreeBSD < 5, NetBSD or OpenBSD */
2168044SWilliam.Kucharski@Sun.COM {
2178044SWilliam.Kucharski@Sun.COM struct disklabel hdg;
2188044SWilliam.Kucharski@Sun.COM if (ioctl (fd, DIOCGDINFO, &hdg))
2198044SWilliam.Kucharski@Sun.COM goto fail;
2208044SWilliam.Kucharski@Sun.COM
2218044SWilliam.Kucharski@Sun.COM geom->cylinders = hdg.d_ncylinders;
2228044SWilliam.Kucharski@Sun.COM geom->heads = hdg.d_ntracks;
2238044SWilliam.Kucharski@Sun.COM geom->sectors = hdg.d_nsectors;
2248044SWilliam.Kucharski@Sun.COM geom->total_sectors = hdg.d_secperunit;
2258044SWilliam.Kucharski@Sun.COM
2268044SWilliam.Kucharski@Sun.COM goto success;
2278044SWilliam.Kucharski@Sun.COM }
2288044SWilliam.Kucharski@Sun.COM
2298044SWilliam.Kucharski@Sun.COM #elif defined(__sun)
2308044SWilliam.Kucharski@Sun.COM /* Solaris */
2318044SWilliam.Kucharski@Sun.COM {
2328044SWilliam.Kucharski@Sun.COM struct dk_geom dkg;
2338044SWilliam.Kucharski@Sun.COM
2348044SWilliam.Kucharski@Sun.COM if (ioctl(fd, DKIOCG_PHYGEOM, &dkg))
2358044SWilliam.Kucharski@Sun.COM goto fail;
2368044SWilliam.Kucharski@Sun.COM geom->cylinders = dkg.dkg_ncyl;
2378044SWilliam.Kucharski@Sun.COM geom->heads = dkg.dkg_nhead;
2388044SWilliam.Kucharski@Sun.COM geom->sectors = dkg.dkg_nsect;
239*9768SShidokht.Yadegari@Sun.COM geom->total_sectors = (unsigned long long)dkg.dkg_ncyl * dkg.dkg_nhead
240*9768SShidokht.Yadegari@Sun.COM * dkg.dkg_nsect;
2418044SWilliam.Kucharski@Sun.COM
2428044SWilliam.Kucharski@Sun.COM goto success;
2438044SWilliam.Kucharski@Sun.COM }
2448044SWilliam.Kucharski@Sun.COM
2458044SWilliam.Kucharski@Sun.COM #else
2468044SWilliam.Kucharski@Sun.COM /* Notably, defined(__GNU__) */
2478044SWilliam.Kucharski@Sun.COM # warning "Automatic detection of geometries will be performed only \
2488044SWilliam.Kucharski@Sun.COM partially. This is not fatal."
2498044SWilliam.Kucharski@Sun.COM #endif
2508044SWilliam.Kucharski@Sun.COM
2518044SWilliam.Kucharski@Sun.COM fail:
2528044SWilliam.Kucharski@Sun.COM {
2538044SWilliam.Kucharski@Sun.COM struct stat st;
2548044SWilliam.Kucharski@Sun.COM
2558044SWilliam.Kucharski@Sun.COM /* FIXME: It would be nice to somehow compute fake C/H/S settings,
2568044SWilliam.Kucharski@Sun.COM given a proper st_blocks size. */
2578044SWilliam.Kucharski@Sun.COM if (drive & 0x80)
2588044SWilliam.Kucharski@Sun.COM {
2598044SWilliam.Kucharski@Sun.COM geom->cylinders = DEFAULT_HD_CYLINDERS;
2608044SWilliam.Kucharski@Sun.COM geom->heads = DEFAULT_HD_HEADS;
2618044SWilliam.Kucharski@Sun.COM geom->sectors = DEFAULT_HD_SECTORS;
2628044SWilliam.Kucharski@Sun.COM }
2638044SWilliam.Kucharski@Sun.COM else
2648044SWilliam.Kucharski@Sun.COM {
2658044SWilliam.Kucharski@Sun.COM geom->cylinders = DEFAULT_FD_CYLINDERS;
2668044SWilliam.Kucharski@Sun.COM geom->heads = DEFAULT_FD_HEADS;
2678044SWilliam.Kucharski@Sun.COM geom->sectors = DEFAULT_FD_SECTORS;
2688044SWilliam.Kucharski@Sun.COM }
2698044SWilliam.Kucharski@Sun.COM
2708044SWilliam.Kucharski@Sun.COM /* Set the total sectors properly, if we can. */
2718044SWilliam.Kucharski@Sun.COM if (! fstat (fd, &st) && st.st_blocks)
2728044SWilliam.Kucharski@Sun.COM geom->total_sectors = st.st_blocks >> SECTOR_BITS;
2738044SWilliam.Kucharski@Sun.COM else
274*9768SShidokht.Yadegari@Sun.COM geom->total_sectors = (unsigned long long)geom->cylinders *
275*9768SShidokht.Yadegari@Sun.COM geom->heads * geom->sectors;
2768044SWilliam.Kucharski@Sun.COM }
2778044SWilliam.Kucharski@Sun.COM
2788044SWilliam.Kucharski@Sun.COM success:
2798044SWilliam.Kucharski@Sun.COM if (geom->flags == -1)
2808044SWilliam.Kucharski@Sun.COM close (fd);
2818044SWilliam.Kucharski@Sun.COM }
2828044SWilliam.Kucharski@Sun.COM
2838044SWilliam.Kucharski@Sun.COM #ifdef __linux__
2848044SWilliam.Kucharski@Sun.COM /* Check if we have devfs support. */
2858044SWilliam.Kucharski@Sun.COM static int
have_devfs(void)2868044SWilliam.Kucharski@Sun.COM have_devfs (void)
2878044SWilliam.Kucharski@Sun.COM {
2888044SWilliam.Kucharski@Sun.COM static int dev_devfsd_exists = -1;
2898044SWilliam.Kucharski@Sun.COM
2908044SWilliam.Kucharski@Sun.COM if (dev_devfsd_exists < 0)
2918044SWilliam.Kucharski@Sun.COM {
2928044SWilliam.Kucharski@Sun.COM struct stat st;
2938044SWilliam.Kucharski@Sun.COM
2948044SWilliam.Kucharski@Sun.COM dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
2958044SWilliam.Kucharski@Sun.COM }
2968044SWilliam.Kucharski@Sun.COM
2978044SWilliam.Kucharski@Sun.COM return dev_devfsd_exists;
2988044SWilliam.Kucharski@Sun.COM }
2998044SWilliam.Kucharski@Sun.COM #endif /* __linux__ */
3008044SWilliam.Kucharski@Sun.COM
3018044SWilliam.Kucharski@Sun.COM /* These three functions are quite different among OSes. */
3028044SWilliam.Kucharski@Sun.COM static void
get_floppy_disk_name(char * name,int unit)3038044SWilliam.Kucharski@Sun.COM get_floppy_disk_name (char *name, int unit)
3048044SWilliam.Kucharski@Sun.COM {
3058044SWilliam.Kucharski@Sun.COM #if defined(__linux__)
3068044SWilliam.Kucharski@Sun.COM /* GNU/Linux */
3078044SWilliam.Kucharski@Sun.COM if (have_devfs ())
3088044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/floppy/%d", unit);
3098044SWilliam.Kucharski@Sun.COM else
3108044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/fd%d", unit);
3118044SWilliam.Kucharski@Sun.COM #elif defined(__GNU__)
3128044SWilliam.Kucharski@Sun.COM /* GNU/Hurd */
3138044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/fd%d", unit);
3148044SWilliam.Kucharski@Sun.COM #elif defined(__FreeBSD_kernel__)
3158044SWilliam.Kucharski@Sun.COM /* kFreeBSD */
3168044SWilliam.Kucharski@Sun.COM if (get_kfreebsd_version () >= 400000)
3178044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/fd%d", unit);
3188044SWilliam.Kucharski@Sun.COM else
3198044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rfd%d", unit);
3208044SWilliam.Kucharski@Sun.COM #elif defined(__NetBSD__)
3218044SWilliam.Kucharski@Sun.COM /* NetBSD */
3228044SWilliam.Kucharski@Sun.COM /* opendisk() doesn't work for floppies. */
3238044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rfd%da", unit);
3248044SWilliam.Kucharski@Sun.COM #elif defined(__OpenBSD__)
3258044SWilliam.Kucharski@Sun.COM /* OpenBSD */
3268044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rfd%dc", unit);
3278044SWilliam.Kucharski@Sun.COM #elif defined(__QNXNTO__)
3288044SWilliam.Kucharski@Sun.COM /* QNX RTP */
3298044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/fd%d", unit);
3308044SWilliam.Kucharski@Sun.COM #elif defined(__sun)
3318044SWilliam.Kucharski@Sun.COM /* Solaris */
3328044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rdiskette%d", unit);
3338044SWilliam.Kucharski@Sun.COM #else
3348044SWilliam.Kucharski@Sun.COM # warning "BIOS floppy drives cannot be guessed in your operating system."
3358044SWilliam.Kucharski@Sun.COM /* Set NAME to a bogus string. */
3368044SWilliam.Kucharski@Sun.COM *name = 0;
3378044SWilliam.Kucharski@Sun.COM #endif
3388044SWilliam.Kucharski@Sun.COM }
3398044SWilliam.Kucharski@Sun.COM
3408044SWilliam.Kucharski@Sun.COM static void
get_ide_disk_name(char * name,int unit)3418044SWilliam.Kucharski@Sun.COM get_ide_disk_name (char *name, int unit)
3428044SWilliam.Kucharski@Sun.COM {
3438044SWilliam.Kucharski@Sun.COM #if defined(__linux__)
3448044SWilliam.Kucharski@Sun.COM /* GNU/Linux */
3458044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/hd%c", unit + 'a');
3468044SWilliam.Kucharski@Sun.COM #elif defined(__GNU__)
3478044SWilliam.Kucharski@Sun.COM /* GNU/Hurd */
3488044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/hd%d", unit);
3498044SWilliam.Kucharski@Sun.COM #elif defined(__FreeBSD_kernel__)
3508044SWilliam.Kucharski@Sun.COM /* kFreeBSD */
3518044SWilliam.Kucharski@Sun.COM if (get_kfreebsd_version () >= 400000)
3528044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/ad%d", unit);
3538044SWilliam.Kucharski@Sun.COM else
3548044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rwd%d", unit);
3558044SWilliam.Kucharski@Sun.COM #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
3568044SWilliam.Kucharski@Sun.COM /* NetBSD */
3578044SWilliam.Kucharski@Sun.COM char shortname[16];
3588044SWilliam.Kucharski@Sun.COM int fd;
3598044SWilliam.Kucharski@Sun.COM
3608044SWilliam.Kucharski@Sun.COM sprintf (shortname, "wd%d", unit);
3618044SWilliam.Kucharski@Sun.COM fd = opendisk (shortname, O_RDONLY, name,
3628044SWilliam.Kucharski@Sun.COM 16, /* length of NAME */
3638044SWilliam.Kucharski@Sun.COM 0 /* char device */
3648044SWilliam.Kucharski@Sun.COM );
3658044SWilliam.Kucharski@Sun.COM close (fd);
3668044SWilliam.Kucharski@Sun.COM #elif defined(__OpenBSD__)
3678044SWilliam.Kucharski@Sun.COM /* OpenBSD */
3688044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rwd%dc", unit);
3698044SWilliam.Kucharski@Sun.COM #elif defined(__QNXNTO__)
3708044SWilliam.Kucharski@Sun.COM /* QNX RTP */
3718044SWilliam.Kucharski@Sun.COM /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could
3728044SWilliam.Kucharski@Sun.COM contain SCSI disks. */
3738044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/hd%d", unit);
3748044SWilliam.Kucharski@Sun.COM #elif defined(__sun)
3758044SWilliam.Kucharski@Sun.COM *name = 0; /* FIXME */
3768044SWilliam.Kucharski@Sun.COM #else
3778044SWilliam.Kucharski@Sun.COM # warning "BIOS IDE drives cannot be guessed in your operating system."
3788044SWilliam.Kucharski@Sun.COM /* Set NAME to a bogus string. */
3798044SWilliam.Kucharski@Sun.COM *name = 0;
3808044SWilliam.Kucharski@Sun.COM #endif
3818044SWilliam.Kucharski@Sun.COM }
3828044SWilliam.Kucharski@Sun.COM
3838044SWilliam.Kucharski@Sun.COM static void
get_scsi_disk_name(char * name,int unit)3848044SWilliam.Kucharski@Sun.COM get_scsi_disk_name (char *name, int unit)
3858044SWilliam.Kucharski@Sun.COM {
3868044SWilliam.Kucharski@Sun.COM #if defined(__linux__)
3878044SWilliam.Kucharski@Sun.COM /* GNU/Linux */
3888044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/sd%c", unit + 'a');
3898044SWilliam.Kucharski@Sun.COM #elif defined(__GNU__)
3908044SWilliam.Kucharski@Sun.COM /* GNU/Hurd */
3918044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/sd%d", unit);
3928044SWilliam.Kucharski@Sun.COM #elif defined(__FreeBSD_kernel__)
3938044SWilliam.Kucharski@Sun.COM /* kFreeBSD */
3948044SWilliam.Kucharski@Sun.COM if (get_kfreebsd_version () >= 400000)
3958044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/da%d", unit);
3968044SWilliam.Kucharski@Sun.COM else
3978044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rda%d", unit);
3988044SWilliam.Kucharski@Sun.COM #elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
3998044SWilliam.Kucharski@Sun.COM /* NetBSD */
4008044SWilliam.Kucharski@Sun.COM char shortname[16];
4018044SWilliam.Kucharski@Sun.COM int fd;
4028044SWilliam.Kucharski@Sun.COM
4038044SWilliam.Kucharski@Sun.COM sprintf (shortname, "sd%d", unit);
4048044SWilliam.Kucharski@Sun.COM fd = opendisk (shortname, O_RDONLY, name,
4058044SWilliam.Kucharski@Sun.COM 16, /* length of NAME */
4068044SWilliam.Kucharski@Sun.COM 0 /* char device */
4078044SWilliam.Kucharski@Sun.COM );
4088044SWilliam.Kucharski@Sun.COM close (fd);
4098044SWilliam.Kucharski@Sun.COM #elif defined(__OpenBSD__)
4108044SWilliam.Kucharski@Sun.COM /* OpenBSD */
4118044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rsd%dc", unit);
4128044SWilliam.Kucharski@Sun.COM #elif defined(__QNXNTO__)
4138044SWilliam.Kucharski@Sun.COM /* QNX RTP */
4148044SWilliam.Kucharski@Sun.COM /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to
4158044SWilliam.Kucharski@Sun.COM disable the detection of SCSI disks here. */
4168044SWilliam.Kucharski@Sun.COM *name = 0;
4178044SWilliam.Kucharski@Sun.COM #elif defined(__sun)
4188044SWilliam.Kucharski@Sun.COM *name = 0; /* FIXME */
4198044SWilliam.Kucharski@Sun.COM #else
4208044SWilliam.Kucharski@Sun.COM # warning "BIOS SCSI drives cannot be guessed in your operating system."
4218044SWilliam.Kucharski@Sun.COM /* Set NAME to a bogus string. */
4228044SWilliam.Kucharski@Sun.COM *name = 0;
4238044SWilliam.Kucharski@Sun.COM #endif
4248044SWilliam.Kucharski@Sun.COM }
4258044SWilliam.Kucharski@Sun.COM
4268044SWilliam.Kucharski@Sun.COM #ifdef __linux__
4278044SWilliam.Kucharski@Sun.COM static void
get_dac960_disk_name(char * name,int controller,int drive)4288044SWilliam.Kucharski@Sun.COM get_dac960_disk_name (char *name, int controller, int drive)
4298044SWilliam.Kucharski@Sun.COM {
4308044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/rd/c%dd%d", controller, drive);
4318044SWilliam.Kucharski@Sun.COM }
4328044SWilliam.Kucharski@Sun.COM
4338044SWilliam.Kucharski@Sun.COM static void
get_ataraid_disk_name(char * name,int unit)4348044SWilliam.Kucharski@Sun.COM get_ataraid_disk_name (char *name, int unit)
4358044SWilliam.Kucharski@Sun.COM {
4368044SWilliam.Kucharski@Sun.COM sprintf (name, "/dev/ataraid/d%c", unit + '0');
4378044SWilliam.Kucharski@Sun.COM }
4388044SWilliam.Kucharski@Sun.COM #endif
4398044SWilliam.Kucharski@Sun.COM
4408044SWilliam.Kucharski@Sun.COM /* Check if DEVICE can be read. If an error occurs, return zero,
4418044SWilliam.Kucharski@Sun.COM otherwise return non-zero. */
4428044SWilliam.Kucharski@Sun.COM int
check_device(const char * device)4438044SWilliam.Kucharski@Sun.COM check_device (const char *device)
4448044SWilliam.Kucharski@Sun.COM {
4458044SWilliam.Kucharski@Sun.COM char buf[512];
4468044SWilliam.Kucharski@Sun.COM FILE *fp;
4478044SWilliam.Kucharski@Sun.COM
4488044SWilliam.Kucharski@Sun.COM /* If DEVICE is empty, just return 1. */
4498044SWilliam.Kucharski@Sun.COM if (*device == 0)
4508044SWilliam.Kucharski@Sun.COM return 1;
4518044SWilliam.Kucharski@Sun.COM
4528044SWilliam.Kucharski@Sun.COM fp = fopen (device, "r");
4538044SWilliam.Kucharski@Sun.COM if (! fp)
4548044SWilliam.Kucharski@Sun.COM {
4558044SWilliam.Kucharski@Sun.COM switch (errno)
4568044SWilliam.Kucharski@Sun.COM {
4578044SWilliam.Kucharski@Sun.COM #ifdef ENOMEDIUM
4588044SWilliam.Kucharski@Sun.COM case ENOMEDIUM:
4598044SWilliam.Kucharski@Sun.COM # if 0
4608044SWilliam.Kucharski@Sun.COM /* At the moment, this finds only CDROMs, which can't be
4618044SWilliam.Kucharski@Sun.COM read anyway, so leave it out. Code should be
4628044SWilliam.Kucharski@Sun.COM reactivated if `removable disks' and CDROMs are
4638044SWilliam.Kucharski@Sun.COM supported. */
4648044SWilliam.Kucharski@Sun.COM /* Accept it, it may be inserted. */
4658044SWilliam.Kucharski@Sun.COM return 1;
4668044SWilliam.Kucharski@Sun.COM # endif
4678044SWilliam.Kucharski@Sun.COM break;
4688044SWilliam.Kucharski@Sun.COM #endif /* ENOMEDIUM */
4698044SWilliam.Kucharski@Sun.COM default:
4708044SWilliam.Kucharski@Sun.COM /* Break case and leave. */
4718044SWilliam.Kucharski@Sun.COM break;
4728044SWilliam.Kucharski@Sun.COM }
4738044SWilliam.Kucharski@Sun.COM /* Error opening the device. */
4748044SWilliam.Kucharski@Sun.COM return 0;
4758044SWilliam.Kucharski@Sun.COM }
4768044SWilliam.Kucharski@Sun.COM
4778044SWilliam.Kucharski@Sun.COM /* Make sure CD-ROMs don't get assigned a BIOS disk number
4788044SWilliam.Kucharski@Sun.COM before SCSI disks! */
4798044SWilliam.Kucharski@Sun.COM #ifdef __linux__
4808044SWilliam.Kucharski@Sun.COM # ifdef CDROM_GET_CAPABILITY
4818044SWilliam.Kucharski@Sun.COM if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
4828044SWilliam.Kucharski@Sun.COM return 0;
4838044SWilliam.Kucharski@Sun.COM # else /* ! CDROM_GET_CAPABILITY */
4848044SWilliam.Kucharski@Sun.COM /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
4858044SWilliam.Kucharski@Sun.COM {
4868044SWilliam.Kucharski@Sun.COM struct hd_geometry hdg;
4878044SWilliam.Kucharski@Sun.COM struct stat st;
4888044SWilliam.Kucharski@Sun.COM
4898044SWilliam.Kucharski@Sun.COM if (fstat (fileno (fp), &st))
4908044SWilliam.Kucharski@Sun.COM return 0;
4918044SWilliam.Kucharski@Sun.COM
4928044SWilliam.Kucharski@Sun.COM /* If it is a block device and isn't a floppy, check if HDIO_GETGEO
4938044SWilliam.Kucharski@Sun.COM succeeds. */
4948044SWilliam.Kucharski@Sun.COM if (S_ISBLK (st.st_mode)
4958044SWilliam.Kucharski@Sun.COM && MAJOR (st.st_rdev) != FLOPPY_MAJOR
4968044SWilliam.Kucharski@Sun.COM && ioctl (fileno (fp), HDIO_GETGEO, &hdg))
4978044SWilliam.Kucharski@Sun.COM return 0;
4988044SWilliam.Kucharski@Sun.COM }
4998044SWilliam.Kucharski@Sun.COM # endif /* ! CDROM_GET_CAPABILITY */
5008044SWilliam.Kucharski@Sun.COM #endif /* __linux__ */
5018044SWilliam.Kucharski@Sun.COM
5028044SWilliam.Kucharski@Sun.COM #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
5038044SWilliam.Kucharski@Sun.COM # ifdef CDIOCCLRDEBUG
5048044SWilliam.Kucharski@Sun.COM if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
5058044SWilliam.Kucharski@Sun.COM return 0;
5068044SWilliam.Kucharski@Sun.COM # endif /* CDIOCCLRDEBUG */
5078044SWilliam.Kucharski@Sun.COM #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */
5088044SWilliam.Kucharski@Sun.COM
5098044SWilliam.Kucharski@Sun.COM /* Attempt to read the first sector. */
5108044SWilliam.Kucharski@Sun.COM if (fread (buf, 1, 512, fp) != 512)
5118044SWilliam.Kucharski@Sun.COM {
5128044SWilliam.Kucharski@Sun.COM fclose (fp);
5138044SWilliam.Kucharski@Sun.COM return 0;
5148044SWilliam.Kucharski@Sun.COM }
5158044SWilliam.Kucharski@Sun.COM
5168044SWilliam.Kucharski@Sun.COM fclose (fp);
5178044SWilliam.Kucharski@Sun.COM return 1;
5188044SWilliam.Kucharski@Sun.COM }
5198044SWilliam.Kucharski@Sun.COM
5208044SWilliam.Kucharski@Sun.COM /* Read mapping information from FP, and write it to MAP. */
5218044SWilliam.Kucharski@Sun.COM static int
read_device_map(FILE * fp,char ** map,const char * map_file)5228044SWilliam.Kucharski@Sun.COM read_device_map (FILE *fp, char **map, const char *map_file)
5238044SWilliam.Kucharski@Sun.COM {
5248044SWilliam.Kucharski@Sun.COM auto void show_error (int no, const char *msg);
5258044SWilliam.Kucharski@Sun.COM auto void show_warning (int no, const char *msg, ...);
5268044SWilliam.Kucharski@Sun.COM
5278044SWilliam.Kucharski@Sun.COM auto void show_error (int no, const char *msg)
5288044SWilliam.Kucharski@Sun.COM {
5298044SWilliam.Kucharski@Sun.COM fprintf (stderr, "%s:%d: error: %s\n", map_file, no, msg);
5308044SWilliam.Kucharski@Sun.COM }
5318044SWilliam.Kucharski@Sun.COM
5328044SWilliam.Kucharski@Sun.COM auto void show_warning (int no, const char *msg, ...)
5338044SWilliam.Kucharski@Sun.COM {
5348044SWilliam.Kucharski@Sun.COM va_list ap;
5358044SWilliam.Kucharski@Sun.COM
5368044SWilliam.Kucharski@Sun.COM va_start (ap, msg);
5378044SWilliam.Kucharski@Sun.COM fprintf (stderr, "%s:%d: warning: ", map_file, no);
5388044SWilliam.Kucharski@Sun.COM vfprintf (stderr, msg, ap);
5398044SWilliam.Kucharski@Sun.COM va_end (ap);
5408044SWilliam.Kucharski@Sun.COM }
5418044SWilliam.Kucharski@Sun.COM
5428044SWilliam.Kucharski@Sun.COM /* If there is the device map file, use the data in it instead of
5438044SWilliam.Kucharski@Sun.COM probing devices. */
5448044SWilliam.Kucharski@Sun.COM char buf[1024]; /* XXX */
5458044SWilliam.Kucharski@Sun.COM int line_number = 0;
5468044SWilliam.Kucharski@Sun.COM
5478044SWilliam.Kucharski@Sun.COM while (fgets (buf, sizeof (buf), fp))
5488044SWilliam.Kucharski@Sun.COM {
5498044SWilliam.Kucharski@Sun.COM char *ptr, *eptr;
5508044SWilliam.Kucharski@Sun.COM int drive;
5518044SWilliam.Kucharski@Sun.COM int is_floppy = 0;
5528044SWilliam.Kucharski@Sun.COM
5538044SWilliam.Kucharski@Sun.COM /* Increase the number of lines. */
5548044SWilliam.Kucharski@Sun.COM line_number++;
5558044SWilliam.Kucharski@Sun.COM
5568044SWilliam.Kucharski@Sun.COM /* If the first character is '#', skip it. */
5578044SWilliam.Kucharski@Sun.COM if (buf[0] == '#')
5588044SWilliam.Kucharski@Sun.COM continue;
5598044SWilliam.Kucharski@Sun.COM
5608044SWilliam.Kucharski@Sun.COM ptr = buf;
5618044SWilliam.Kucharski@Sun.COM /* Skip leading spaces. */
5628044SWilliam.Kucharski@Sun.COM while (*ptr && isspace (*ptr))
5638044SWilliam.Kucharski@Sun.COM ptr++;
5648044SWilliam.Kucharski@Sun.COM
5658044SWilliam.Kucharski@Sun.COM /* Skip empty lines. */
5668044SWilliam.Kucharski@Sun.COM if (! *ptr)
5678044SWilliam.Kucharski@Sun.COM continue;
5688044SWilliam.Kucharski@Sun.COM
5698044SWilliam.Kucharski@Sun.COM if (*ptr != '(')
5708044SWilliam.Kucharski@Sun.COM {
5718044SWilliam.Kucharski@Sun.COM show_error (line_number, "No open parenthesis found");
5728044SWilliam.Kucharski@Sun.COM return 0;
5738044SWilliam.Kucharski@Sun.COM }
5748044SWilliam.Kucharski@Sun.COM
5758044SWilliam.Kucharski@Sun.COM ptr++;
5768044SWilliam.Kucharski@Sun.COM if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd')
5778044SWilliam.Kucharski@Sun.COM {
5788044SWilliam.Kucharski@Sun.COM show_error (line_number, "Bad drive name");
5798044SWilliam.Kucharski@Sun.COM return 0;
5808044SWilliam.Kucharski@Sun.COM }
5818044SWilliam.Kucharski@Sun.COM
5828044SWilliam.Kucharski@Sun.COM if (*ptr == 'f')
5838044SWilliam.Kucharski@Sun.COM is_floppy = 1;
5848044SWilliam.Kucharski@Sun.COM
5858044SWilliam.Kucharski@Sun.COM ptr += 2;
5868044SWilliam.Kucharski@Sun.COM drive = strtoul (ptr, &ptr, 10);
5878044SWilliam.Kucharski@Sun.COM if (drive < 0)
5888044SWilliam.Kucharski@Sun.COM {
5898044SWilliam.Kucharski@Sun.COM show_error (line_number, "Bad device number");
5908044SWilliam.Kucharski@Sun.COM return 0;
5918044SWilliam.Kucharski@Sun.COM }
5928044SWilliam.Kucharski@Sun.COM else if (drive > 127)
5938044SWilliam.Kucharski@Sun.COM {
5948044SWilliam.Kucharski@Sun.COM show_warning (line_number,
5958044SWilliam.Kucharski@Sun.COM "Ignoring %cd%d due to a BIOS limitation",
5968044SWilliam.Kucharski@Sun.COM is_floppy ? 'f' : 'h', drive);
5978044SWilliam.Kucharski@Sun.COM continue;
5988044SWilliam.Kucharski@Sun.COM }
5998044SWilliam.Kucharski@Sun.COM
6008044SWilliam.Kucharski@Sun.COM if (! is_floppy)
6018044SWilliam.Kucharski@Sun.COM drive += 0x80;
6028044SWilliam.Kucharski@Sun.COM
6038044SWilliam.Kucharski@Sun.COM if (*ptr != ')')
6048044SWilliam.Kucharski@Sun.COM {
6058044SWilliam.Kucharski@Sun.COM show_error (line_number, "No close parenthesis found");
6068044SWilliam.Kucharski@Sun.COM return 0;
6078044SWilliam.Kucharski@Sun.COM }
6088044SWilliam.Kucharski@Sun.COM
6098044SWilliam.Kucharski@Sun.COM ptr++;
6108044SWilliam.Kucharski@Sun.COM /* Skip spaces. */
6118044SWilliam.Kucharski@Sun.COM while (*ptr && isspace (*ptr))
6128044SWilliam.Kucharski@Sun.COM ptr++;
6138044SWilliam.Kucharski@Sun.COM
6148044SWilliam.Kucharski@Sun.COM if (! *ptr)
6158044SWilliam.Kucharski@Sun.COM {
6168044SWilliam.Kucharski@Sun.COM show_error (line_number, "No filename found");
6178044SWilliam.Kucharski@Sun.COM return 0;
6188044SWilliam.Kucharski@Sun.COM }
6198044SWilliam.Kucharski@Sun.COM
6208044SWilliam.Kucharski@Sun.COM /* Terminate the filename. */
6218044SWilliam.Kucharski@Sun.COM eptr = ptr;
6228044SWilliam.Kucharski@Sun.COM while (*eptr && ! isspace (*eptr))
6238044SWilliam.Kucharski@Sun.COM eptr++;
6248044SWilliam.Kucharski@Sun.COM *eptr = 0;
6258044SWilliam.Kucharski@Sun.COM
6268044SWilliam.Kucharski@Sun.COM /* Multiple entries for a given drive is not allowed. */
6278044SWilliam.Kucharski@Sun.COM if (map[drive])
6288044SWilliam.Kucharski@Sun.COM {
6298044SWilliam.Kucharski@Sun.COM show_error (line_number, "Duplicated entry found");
6308044SWilliam.Kucharski@Sun.COM return 0;
6318044SWilliam.Kucharski@Sun.COM }
6328044SWilliam.Kucharski@Sun.COM
6338044SWilliam.Kucharski@Sun.COM map[drive] = strdup (ptr);
6348044SWilliam.Kucharski@Sun.COM assert (map[drive]);
6358044SWilliam.Kucharski@Sun.COM }
6368044SWilliam.Kucharski@Sun.COM
6378044SWilliam.Kucharski@Sun.COM return 1;
6388044SWilliam.Kucharski@Sun.COM }
6398044SWilliam.Kucharski@Sun.COM
6408044SWilliam.Kucharski@Sun.COM /* Initialize the device map MAP. *MAP will be allocated from the heap
6418044SWilliam.Kucharski@Sun.COM space. If MAP_FILE is not NULL, then read mappings from the file
6428044SWilliam.Kucharski@Sun.COM MAP_FILE if it exists, otherwise, write guessed mappings to the file.
6438044SWilliam.Kucharski@Sun.COM FLOPPY_DISKS is the number of floppy disk drives which will be probed.
6448044SWilliam.Kucharski@Sun.COM If it is zero, don't probe any floppy at all. If it is one, probe one
6458044SWilliam.Kucharski@Sun.COM floppy. If it is two, probe two floppies. And so on. */
6468044SWilliam.Kucharski@Sun.COM int
init_device_map(char *** map,const char * map_file,int floppy_disks)6478044SWilliam.Kucharski@Sun.COM init_device_map (char ***map, const char *map_file, int floppy_disks)
6488044SWilliam.Kucharski@Sun.COM {
6498044SWilliam.Kucharski@Sun.COM int i;
6508044SWilliam.Kucharski@Sun.COM int num_hd = 0;
6518044SWilliam.Kucharski@Sun.COM FILE *fp = 0;
6528044SWilliam.Kucharski@Sun.COM
6538044SWilliam.Kucharski@Sun.COM assert (map);
6548044SWilliam.Kucharski@Sun.COM assert (*map == 0);
6558044SWilliam.Kucharski@Sun.COM *map = malloc (NUM_DISKS * sizeof (char *));
6568044SWilliam.Kucharski@Sun.COM assert (*map);
6578044SWilliam.Kucharski@Sun.COM
6588044SWilliam.Kucharski@Sun.COM /* Probe devices for creating the device map. */
6598044SWilliam.Kucharski@Sun.COM
6608044SWilliam.Kucharski@Sun.COM /* Initialize DEVICE_MAP. */
6618044SWilliam.Kucharski@Sun.COM for (i = 0; i < NUM_DISKS; i++)
6628044SWilliam.Kucharski@Sun.COM (*map)[i] = 0;
6638044SWilliam.Kucharski@Sun.COM
6648044SWilliam.Kucharski@Sun.COM if (map_file)
6658044SWilliam.Kucharski@Sun.COM {
6668044SWilliam.Kucharski@Sun.COM /* Open the device map file. */
6678044SWilliam.Kucharski@Sun.COM fp = fopen (map_file, "r");
6688044SWilliam.Kucharski@Sun.COM if (fp)
6698044SWilliam.Kucharski@Sun.COM {
6708044SWilliam.Kucharski@Sun.COM int ret;
6718044SWilliam.Kucharski@Sun.COM
6728044SWilliam.Kucharski@Sun.COM ret = read_device_map (fp, *map, map_file);
6738044SWilliam.Kucharski@Sun.COM fclose (fp);
6748044SWilliam.Kucharski@Sun.COM return ret;
6758044SWilliam.Kucharski@Sun.COM }
6768044SWilliam.Kucharski@Sun.COM }
6778044SWilliam.Kucharski@Sun.COM
6788044SWilliam.Kucharski@Sun.COM /* Print something so that the user does not think GRUB has been
6798044SWilliam.Kucharski@Sun.COM crashed. */
6808044SWilliam.Kucharski@Sun.COM fprintf (stderr,
6818044SWilliam.Kucharski@Sun.COM "Probing devices to guess BIOS drives. "
6828044SWilliam.Kucharski@Sun.COM "This may take a long time.\n");
6838044SWilliam.Kucharski@Sun.COM
6848044SWilliam.Kucharski@Sun.COM if (map_file)
6858044SWilliam.Kucharski@Sun.COM /* Try to open the device map file to write the probed data. */
6868044SWilliam.Kucharski@Sun.COM fp = fopen (map_file, "w");
6878044SWilliam.Kucharski@Sun.COM
6888044SWilliam.Kucharski@Sun.COM /* Floppies. */
6898044SWilliam.Kucharski@Sun.COM for (i = 0; i < floppy_disks; i++)
6908044SWilliam.Kucharski@Sun.COM {
6918044SWilliam.Kucharski@Sun.COM char name[16];
6928044SWilliam.Kucharski@Sun.COM
6938044SWilliam.Kucharski@Sun.COM get_floppy_disk_name (name, i);
6948044SWilliam.Kucharski@Sun.COM /* In floppies, write the map, whether check_device succeeds
6958044SWilliam.Kucharski@Sun.COM or not, because the user just does not insert floppies. */
6968044SWilliam.Kucharski@Sun.COM if (fp)
6978044SWilliam.Kucharski@Sun.COM fprintf (fp, "(fd%d)\t%s\n", i, name);
6988044SWilliam.Kucharski@Sun.COM
6998044SWilliam.Kucharski@Sun.COM if (check_device (name))
7008044SWilliam.Kucharski@Sun.COM {
7018044SWilliam.Kucharski@Sun.COM (*map)[i] = strdup (name);
7028044SWilliam.Kucharski@Sun.COM assert ((*map)[i]);
7038044SWilliam.Kucharski@Sun.COM }
7048044SWilliam.Kucharski@Sun.COM }
7058044SWilliam.Kucharski@Sun.COM
7068044SWilliam.Kucharski@Sun.COM #ifdef __linux__
7078044SWilliam.Kucharski@Sun.COM if (have_devfs ())
7088044SWilliam.Kucharski@Sun.COM {
7098044SWilliam.Kucharski@Sun.COM while (1)
7108044SWilliam.Kucharski@Sun.COM {
7118044SWilliam.Kucharski@Sun.COM char discn[32];
7128044SWilliam.Kucharski@Sun.COM char name[PATH_MAX];
7138044SWilliam.Kucharski@Sun.COM struct stat st;
7148044SWilliam.Kucharski@Sun.COM
7158044SWilliam.Kucharski@Sun.COM /* Linux creates symlinks "/dev/discs/discN" for convenience.
7168044SWilliam.Kucharski@Sun.COM The way to number disks is the same as GRUB's. */
7178044SWilliam.Kucharski@Sun.COM sprintf (discn, "/dev/discs/disc%d", num_hd);
7188044SWilliam.Kucharski@Sun.COM if (stat (discn, &st) < 0)
7198044SWilliam.Kucharski@Sun.COM break;
7208044SWilliam.Kucharski@Sun.COM
7218044SWilliam.Kucharski@Sun.COM if (realpath (discn, name))
7228044SWilliam.Kucharski@Sun.COM {
7238044SWilliam.Kucharski@Sun.COM strcat (name, "/disc");
7248044SWilliam.Kucharski@Sun.COM (*map)[num_hd + 0x80] = strdup (name);
7258044SWilliam.Kucharski@Sun.COM assert ((*map)[num_hd + 0x80]);
7268044SWilliam.Kucharski@Sun.COM
7278044SWilliam.Kucharski@Sun.COM /* If the device map file is opened, write the map. */
7288044SWilliam.Kucharski@Sun.COM if (fp)
7298044SWilliam.Kucharski@Sun.COM fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7308044SWilliam.Kucharski@Sun.COM }
7318044SWilliam.Kucharski@Sun.COM
7328044SWilliam.Kucharski@Sun.COM num_hd++;
7338044SWilliam.Kucharski@Sun.COM }
7348044SWilliam.Kucharski@Sun.COM
7358044SWilliam.Kucharski@Sun.COM /* OK, close the device map file if opened. */
7368044SWilliam.Kucharski@Sun.COM if (fp)
7378044SWilliam.Kucharski@Sun.COM fclose (fp);
7388044SWilliam.Kucharski@Sun.COM
7398044SWilliam.Kucharski@Sun.COM return 1;
7408044SWilliam.Kucharski@Sun.COM }
7418044SWilliam.Kucharski@Sun.COM #endif /* __linux__ */
7428044SWilliam.Kucharski@Sun.COM
7438044SWilliam.Kucharski@Sun.COM /* IDE disks. */
7448044SWilliam.Kucharski@Sun.COM for (i = 0; i < 8; i++)
7458044SWilliam.Kucharski@Sun.COM {
7468044SWilliam.Kucharski@Sun.COM char name[16];
7478044SWilliam.Kucharski@Sun.COM
7488044SWilliam.Kucharski@Sun.COM get_ide_disk_name (name, i);
7498044SWilliam.Kucharski@Sun.COM if (check_device (name))
7508044SWilliam.Kucharski@Sun.COM {
7518044SWilliam.Kucharski@Sun.COM (*map)[num_hd + 0x80] = strdup (name);
7528044SWilliam.Kucharski@Sun.COM assert ((*map)[num_hd + 0x80]);
7538044SWilliam.Kucharski@Sun.COM
7548044SWilliam.Kucharski@Sun.COM /* If the device map file is opened, write the map. */
7558044SWilliam.Kucharski@Sun.COM if (fp)
7568044SWilliam.Kucharski@Sun.COM fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7578044SWilliam.Kucharski@Sun.COM
7588044SWilliam.Kucharski@Sun.COM num_hd++;
7598044SWilliam.Kucharski@Sun.COM }
7608044SWilliam.Kucharski@Sun.COM }
7618044SWilliam.Kucharski@Sun.COM
7628044SWilliam.Kucharski@Sun.COM #ifdef __linux__
7638044SWilliam.Kucharski@Sun.COM /* ATARAID disks. */
7648044SWilliam.Kucharski@Sun.COM for (i = 0; i < 8; i++)
7658044SWilliam.Kucharski@Sun.COM {
7668044SWilliam.Kucharski@Sun.COM char name[20];
7678044SWilliam.Kucharski@Sun.COM
7688044SWilliam.Kucharski@Sun.COM get_ataraid_disk_name (name, i);
7698044SWilliam.Kucharski@Sun.COM if (check_device (name))
7708044SWilliam.Kucharski@Sun.COM {
7718044SWilliam.Kucharski@Sun.COM (*map)[num_hd + 0x80] = strdup (name);
7728044SWilliam.Kucharski@Sun.COM assert ((*map)[num_hd + 0x80]);
7738044SWilliam.Kucharski@Sun.COM
7748044SWilliam.Kucharski@Sun.COM /* If the device map file is opened, write the map. */
7758044SWilliam.Kucharski@Sun.COM if (fp)
7768044SWilliam.Kucharski@Sun.COM fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7778044SWilliam.Kucharski@Sun.COM
7788044SWilliam.Kucharski@Sun.COM num_hd++;
7798044SWilliam.Kucharski@Sun.COM }
7808044SWilliam.Kucharski@Sun.COM }
7818044SWilliam.Kucharski@Sun.COM #endif /* __linux__ */
7828044SWilliam.Kucharski@Sun.COM
7838044SWilliam.Kucharski@Sun.COM /* The rest is SCSI disks. */
7848044SWilliam.Kucharski@Sun.COM for (i = 0; i < 16; i++)
7858044SWilliam.Kucharski@Sun.COM {
7868044SWilliam.Kucharski@Sun.COM char name[16];
7878044SWilliam.Kucharski@Sun.COM
7888044SWilliam.Kucharski@Sun.COM get_scsi_disk_name (name, i);
7898044SWilliam.Kucharski@Sun.COM if (check_device (name))
7908044SWilliam.Kucharski@Sun.COM {
7918044SWilliam.Kucharski@Sun.COM (*map)[num_hd + 0x80] = strdup (name);
7928044SWilliam.Kucharski@Sun.COM assert ((*map)[num_hd + 0x80]);
7938044SWilliam.Kucharski@Sun.COM
7948044SWilliam.Kucharski@Sun.COM /* If the device map file is opened, write the map. */
7958044SWilliam.Kucharski@Sun.COM if (fp)
7968044SWilliam.Kucharski@Sun.COM fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
7978044SWilliam.Kucharski@Sun.COM
7988044SWilliam.Kucharski@Sun.COM num_hd++;
7998044SWilliam.Kucharski@Sun.COM }
8008044SWilliam.Kucharski@Sun.COM }
8018044SWilliam.Kucharski@Sun.COM
8028044SWilliam.Kucharski@Sun.COM #ifdef __linux__
8038044SWilliam.Kucharski@Sun.COM /* This is for DAC960 - we have
8048044SWilliam.Kucharski@Sun.COM /dev/rd/c<controller>d<logical drive>p<partition>.
8058044SWilliam.Kucharski@Sun.COM
8068044SWilliam.Kucharski@Sun.COM DAC960 driver currently supports up to 8 controllers, 32 logical
8078044SWilliam.Kucharski@Sun.COM drives, and 7 partitions. */
8088044SWilliam.Kucharski@Sun.COM {
8098044SWilliam.Kucharski@Sun.COM int controller, drive;
8108044SWilliam.Kucharski@Sun.COM
8118044SWilliam.Kucharski@Sun.COM for (controller = 0; controller < 8; controller++)
8128044SWilliam.Kucharski@Sun.COM {
8138044SWilliam.Kucharski@Sun.COM for (drive = 0; drive < 15; drive++)
8148044SWilliam.Kucharski@Sun.COM {
8158044SWilliam.Kucharski@Sun.COM char name[24];
8168044SWilliam.Kucharski@Sun.COM
8178044SWilliam.Kucharski@Sun.COM get_dac960_disk_name (name, controller, drive);
8188044SWilliam.Kucharski@Sun.COM if (check_device (name))
8198044SWilliam.Kucharski@Sun.COM {
8208044SWilliam.Kucharski@Sun.COM (*map)[num_hd + 0x80] = strdup (name);
8218044SWilliam.Kucharski@Sun.COM assert ((*map)[num_hd + 0x80]);
8228044SWilliam.Kucharski@Sun.COM
8238044SWilliam.Kucharski@Sun.COM /* If the device map file is opened, write the map. */
8248044SWilliam.Kucharski@Sun.COM if (fp)
8258044SWilliam.Kucharski@Sun.COM fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
8268044SWilliam.Kucharski@Sun.COM
8278044SWilliam.Kucharski@Sun.COM num_hd++;
8288044SWilliam.Kucharski@Sun.COM }
8298044SWilliam.Kucharski@Sun.COM }
8308044SWilliam.Kucharski@Sun.COM }
8318044SWilliam.Kucharski@Sun.COM }
8328044SWilliam.Kucharski@Sun.COM #endif /* __linux__ */
8338044SWilliam.Kucharski@Sun.COM
8348044SWilliam.Kucharski@Sun.COM /* OK, close the device map file if opened. */
8358044SWilliam.Kucharski@Sun.COM if (fp)
8368044SWilliam.Kucharski@Sun.COM fclose (fp);
8378044SWilliam.Kucharski@Sun.COM
8388044SWilliam.Kucharski@Sun.COM return 1;
8398044SWilliam.Kucharski@Sun.COM }
8408044SWilliam.Kucharski@Sun.COM
8418044SWilliam.Kucharski@Sun.COM /* Restore the memory consumed for MAP. */
8428044SWilliam.Kucharski@Sun.COM void
restore_device_map(char ** map)8438044SWilliam.Kucharski@Sun.COM restore_device_map (char **map)
8448044SWilliam.Kucharski@Sun.COM {
8458044SWilliam.Kucharski@Sun.COM int i;
8468044SWilliam.Kucharski@Sun.COM
8478044SWilliam.Kucharski@Sun.COM for (i = 0; i < NUM_DISKS; i++)
8488044SWilliam.Kucharski@Sun.COM if (map[i])
8498044SWilliam.Kucharski@Sun.COM free (map[i]);
8508044SWilliam.Kucharski@Sun.COM
8518044SWilliam.Kucharski@Sun.COM free (map);
8528044SWilliam.Kucharski@Sun.COM }
8538044SWilliam.Kucharski@Sun.COM
8548044SWilliam.Kucharski@Sun.COM #ifdef __linux__
8558044SWilliam.Kucharski@Sun.COM /* Linux-only functions, because Linux has a bug that the disk cache for
8568044SWilliam.Kucharski@Sun.COM a whole disk is not consistent with the one for a partition of the
8578044SWilliam.Kucharski@Sun.COM disk. */
8588044SWilliam.Kucharski@Sun.COM int
is_disk_device(char ** map,int drive)8598044SWilliam.Kucharski@Sun.COM is_disk_device (char **map, int drive)
8608044SWilliam.Kucharski@Sun.COM {
8618044SWilliam.Kucharski@Sun.COM struct stat st;
8628044SWilliam.Kucharski@Sun.COM
8638044SWilliam.Kucharski@Sun.COM assert (map[drive] != 0);
8648044SWilliam.Kucharski@Sun.COM assert (stat (map[drive], &st) == 0);
8658044SWilliam.Kucharski@Sun.COM /* For now, disk devices under Linux are all block devices. */
8668044SWilliam.Kucharski@Sun.COM return S_ISBLK (st.st_mode);
8678044SWilliam.Kucharski@Sun.COM }
8688044SWilliam.Kucharski@Sun.COM
8698044SWilliam.Kucharski@Sun.COM int
write_to_partition(char ** map,int drive,int partition,int sector,int size,const char * buf)8708044SWilliam.Kucharski@Sun.COM write_to_partition (char **map, int drive, int partition,
8718044SWilliam.Kucharski@Sun.COM int sector, int size, const char *buf)
8728044SWilliam.Kucharski@Sun.COM {
8738044SWilliam.Kucharski@Sun.COM char dev[PATH_MAX]; /* XXX */
8748044SWilliam.Kucharski@Sun.COM int fd;
8758044SWilliam.Kucharski@Sun.COM
8768044SWilliam.Kucharski@Sun.COM if ((partition & 0x00FF00) != 0x00FF00)
8778044SWilliam.Kucharski@Sun.COM {
8788044SWilliam.Kucharski@Sun.COM /* If the partition is a BSD partition, it is difficult to
8798044SWilliam.Kucharski@Sun.COM obtain the representation in Linux. So don't support that. */
8808044SWilliam.Kucharski@Sun.COM errnum = ERR_DEV_VALUES;
8818044SWilliam.Kucharski@Sun.COM return 1;
8828044SWilliam.Kucharski@Sun.COM }
8838044SWilliam.Kucharski@Sun.COM
8848044SWilliam.Kucharski@Sun.COM assert (map[drive] != 0);
8858044SWilliam.Kucharski@Sun.COM
8868044SWilliam.Kucharski@Sun.COM strcpy (dev, map[drive]);
8878044SWilliam.Kucharski@Sun.COM if (have_devfs ())
8888044SWilliam.Kucharski@Sun.COM {
8898044SWilliam.Kucharski@Sun.COM if (strcmp (dev + strlen(dev) - 5, "/disc") == 0)
8908044SWilliam.Kucharski@Sun.COM strcpy (dev + strlen(dev) - 5, "/part");
8918044SWilliam.Kucharski@Sun.COM }
8928044SWilliam.Kucharski@Sun.COM sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1);
8938044SWilliam.Kucharski@Sun.COM
8948044SWilliam.Kucharski@Sun.COM /* Open the partition. */
8958044SWilliam.Kucharski@Sun.COM fd = open (dev, O_RDWR);
8968044SWilliam.Kucharski@Sun.COM if (fd < 0)
8978044SWilliam.Kucharski@Sun.COM {
8988044SWilliam.Kucharski@Sun.COM errnum = ERR_NO_PART;
8998044SWilliam.Kucharski@Sun.COM return 0;
9008044SWilliam.Kucharski@Sun.COM }
9018044SWilliam.Kucharski@Sun.COM
9028044SWilliam.Kucharski@Sun.COM #if defined(__linux__) && (!defined(__GLIBC__) || \
9038044SWilliam.Kucharski@Sun.COM ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
9048044SWilliam.Kucharski@Sun.COM /* Maybe libc doesn't have large file support. */
9058044SWilliam.Kucharski@Sun.COM {
9068044SWilliam.Kucharski@Sun.COM loff_t offset, result;
9078044SWilliam.Kucharski@Sun.COM static int _llseek (uint filedes, ulong hi, ulong lo,
9088044SWilliam.Kucharski@Sun.COM loff_t *res, uint wh);
9098044SWilliam.Kucharski@Sun.COM _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
9108044SWilliam.Kucharski@Sun.COM loff_t *, res, uint, wh);
9118044SWilliam.Kucharski@Sun.COM
9128044SWilliam.Kucharski@Sun.COM offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
9138044SWilliam.Kucharski@Sun.COM if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
9148044SWilliam.Kucharski@Sun.COM {
9158044SWilliam.Kucharski@Sun.COM errnum = ERR_DEV_VALUES;
9168044SWilliam.Kucharski@Sun.COM return 0;
9178044SWilliam.Kucharski@Sun.COM }
9188044SWilliam.Kucharski@Sun.COM }
9198044SWilliam.Kucharski@Sun.COM #else
9208044SWilliam.Kucharski@Sun.COM {
9218044SWilliam.Kucharski@Sun.COM off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
9228044SWilliam.Kucharski@Sun.COM
9238044SWilliam.Kucharski@Sun.COM if (lseek (fd, offset, SEEK_SET) != offset)
9248044SWilliam.Kucharski@Sun.COM {
9258044SWilliam.Kucharski@Sun.COM errnum = ERR_DEV_VALUES;
9268044SWilliam.Kucharski@Sun.COM return 0;
9278044SWilliam.Kucharski@Sun.COM }
9288044SWilliam.Kucharski@Sun.COM }
9298044SWilliam.Kucharski@Sun.COM #endif
9308044SWilliam.Kucharski@Sun.COM
9318044SWilliam.Kucharski@Sun.COM if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE))
9328044SWilliam.Kucharski@Sun.COM {
9338044SWilliam.Kucharski@Sun.COM close (fd);
9348044SWilliam.Kucharski@Sun.COM errnum = ERR_WRITE;
9358044SWilliam.Kucharski@Sun.COM return 0;
9368044SWilliam.Kucharski@Sun.COM }
9378044SWilliam.Kucharski@Sun.COM
9388044SWilliam.Kucharski@Sun.COM sync (); /* Paranoia. */
9398044SWilliam.Kucharski@Sun.COM close (fd);
9408044SWilliam.Kucharski@Sun.COM
9418044SWilliam.Kucharski@Sun.COM return 1;
9428044SWilliam.Kucharski@Sun.COM }
9438044SWilliam.Kucharski@Sun.COM #endif /* __linux__ */
944