1*1b8adde7SWilliam Kucharski /* device.c - Some helper functions for OS devices and BIOS drives */ 2*1b8adde7SWilliam Kucharski /* 3*1b8adde7SWilliam Kucharski * GRUB -- GRand Unified Bootloader 4*1b8adde7SWilliam Kucharski * Copyright (C) 1999,2000,2001,2002,2003,2004,2005 Free Software Foundation, Inc. 5*1b8adde7SWilliam Kucharski * 6*1b8adde7SWilliam Kucharski * This program is free software; you can redistribute it and/or modify 7*1b8adde7SWilliam Kucharski * it under the terms of the GNU General Public License as published by 8*1b8adde7SWilliam Kucharski * the Free Software Foundation; either version 2 of the License, or 9*1b8adde7SWilliam Kucharski * (at your option) any later version. 10*1b8adde7SWilliam Kucharski * 11*1b8adde7SWilliam Kucharski * This program is distributed in the hope that it will be useful, 12*1b8adde7SWilliam Kucharski * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*1b8adde7SWilliam Kucharski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*1b8adde7SWilliam Kucharski * GNU General Public License for more details. 15*1b8adde7SWilliam Kucharski * 16*1b8adde7SWilliam Kucharski * You should have received a copy of the GNU General Public License 17*1b8adde7SWilliam Kucharski * along with this program; if not, write to the Free Software 18*1b8adde7SWilliam Kucharski * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*1b8adde7SWilliam Kucharski */ 20*1b8adde7SWilliam Kucharski 21*1b8adde7SWilliam Kucharski /* Try to use glibc's transparant LFS support. */ 22*1b8adde7SWilliam Kucharski #define _LARGEFILE_SOURCE 1 23*1b8adde7SWilliam Kucharski /* lseek becomes synonymous with lseek64. */ 24*1b8adde7SWilliam Kucharski #define _FILE_OFFSET_BITS 64 25*1b8adde7SWilliam Kucharski 26*1b8adde7SWilliam Kucharski #include <stdio.h> 27*1b8adde7SWilliam Kucharski #include <stdlib.h> 28*1b8adde7SWilliam Kucharski #include <string.h> 29*1b8adde7SWilliam Kucharski #include <ctype.h> 30*1b8adde7SWilliam Kucharski #include <assert.h> 31*1b8adde7SWilliam Kucharski #include <unistd.h> 32*1b8adde7SWilliam Kucharski #include <sys/types.h> 33*1b8adde7SWilliam Kucharski #include <sys/stat.h> 34*1b8adde7SWilliam Kucharski #include <fcntl.h> 35*1b8adde7SWilliam Kucharski #include <errno.h> 36*1b8adde7SWilliam Kucharski #include <limits.h> 37*1b8adde7SWilliam Kucharski #include <stdarg.h> 38*1b8adde7SWilliam Kucharski 39*1b8adde7SWilliam Kucharski #ifdef __linux__ 40*1b8adde7SWilliam Kucharski # if !defined(__GLIBC__) || \ 41*1b8adde7SWilliam Kucharski ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) 42*1b8adde7SWilliam Kucharski /* Maybe libc doesn't have large file support. */ 43*1b8adde7SWilliam Kucharski # include <linux/unistd.h> /* _llseek */ 44*1b8adde7SWilliam Kucharski # endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */ 45*1b8adde7SWilliam Kucharski # include <sys/ioctl.h> /* ioctl */ 46*1b8adde7SWilliam Kucharski # ifndef HDIO_GETGEO 47*1b8adde7SWilliam Kucharski # define HDIO_GETGEO 0x0301 /* get device geometry */ 48*1b8adde7SWilliam Kucharski /* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is 49*1b8adde7SWilliam Kucharski defined. */ 50*1b8adde7SWilliam Kucharski struct hd_geometry 51*1b8adde7SWilliam Kucharski { 52*1b8adde7SWilliam Kucharski unsigned char heads; 53*1b8adde7SWilliam Kucharski unsigned char sectors; 54*1b8adde7SWilliam Kucharski unsigned short cylinders; 55*1b8adde7SWilliam Kucharski unsigned long start; 56*1b8adde7SWilliam Kucharski }; 57*1b8adde7SWilliam Kucharski # endif /* ! HDIO_GETGEO */ 58*1b8adde7SWilliam Kucharski # ifndef FLOPPY_MAJOR 59*1b8adde7SWilliam Kucharski # define FLOPPY_MAJOR 2 /* the major number for floppy */ 60*1b8adde7SWilliam Kucharski # endif /* ! FLOPPY_MAJOR */ 61*1b8adde7SWilliam Kucharski # ifndef MAJOR 62*1b8adde7SWilliam Kucharski # define MAJOR(dev) \ 63*1b8adde7SWilliam Kucharski ({ \ 64*1b8adde7SWilliam Kucharski unsigned long long __dev = (dev); \ 65*1b8adde7SWilliam Kucharski (unsigned) ((__dev >> 8) & 0xfff) \ 66*1b8adde7SWilliam Kucharski | ((unsigned int) (__dev >> 32) & ~0xfff); \ 67*1b8adde7SWilliam Kucharski }) 68*1b8adde7SWilliam Kucharski # endif /* ! MAJOR */ 69*1b8adde7SWilliam Kucharski # ifndef CDROM_GET_CAPABILITY 70*1b8adde7SWilliam Kucharski # define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ 71*1b8adde7SWilliam Kucharski # endif /* ! CDROM_GET_CAPABILITY */ 72*1b8adde7SWilliam Kucharski # ifndef BLKGETSIZE 73*1b8adde7SWilliam Kucharski # define BLKGETSIZE _IO(0x12,96) /* return device size */ 74*1b8adde7SWilliam Kucharski # endif /* ! BLKGETSIZE */ 75*1b8adde7SWilliam Kucharski #endif /* __linux__ */ 76*1b8adde7SWilliam Kucharski 77*1b8adde7SWilliam Kucharski /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with 78*1b8adde7SWilliam Kucharski kFreeBSD-based non-FreeBSD systems (e.g. GNU/kFreeBSD) */ 79*1b8adde7SWilliam Kucharski #if defined(__FreeBSD__) && ! defined(__FreeBSD_kernel__) 80*1b8adde7SWilliam Kucharski # define __FreeBSD_kernel__ 81*1b8adde7SWilliam Kucharski #endif 82*1b8adde7SWilliam Kucharski #ifdef __FreeBSD_kernel__ 83*1b8adde7SWilliam Kucharski /* Obtain version of kFreeBSD headers */ 84*1b8adde7SWilliam Kucharski # include <osreldate.h> 85*1b8adde7SWilliam Kucharski # ifndef __FreeBSD_kernel_version 86*1b8adde7SWilliam Kucharski # define __FreeBSD_kernel_version __FreeBSD_version 87*1b8adde7SWilliam Kucharski # endif 88*1b8adde7SWilliam Kucharski 89*1b8adde7SWilliam Kucharski /* Runtime detection of kernel */ 90*1b8adde7SWilliam Kucharski # include <sys/utsname.h> 91*1b8adde7SWilliam Kucharski int 92*1b8adde7SWilliam Kucharski get_kfreebsd_version () 93*1b8adde7SWilliam Kucharski { 94*1b8adde7SWilliam Kucharski struct utsname uts; 95*1b8adde7SWilliam Kucharski int major; int minor, v[2]; 96*1b8adde7SWilliam Kucharski 97*1b8adde7SWilliam Kucharski uname (&uts); 98*1b8adde7SWilliam Kucharski sscanf (uts.release, "%d.%d", &major, &minor); 99*1b8adde7SWilliam Kucharski 100*1b8adde7SWilliam Kucharski if (major >= 9) 101*1b8adde7SWilliam Kucharski major = 9; 102*1b8adde7SWilliam Kucharski if (major >= 5) 103*1b8adde7SWilliam Kucharski { 104*1b8adde7SWilliam Kucharski v[0] = minor/10; v[1] = minor%10; 105*1b8adde7SWilliam Kucharski } 106*1b8adde7SWilliam Kucharski else 107*1b8adde7SWilliam Kucharski { 108*1b8adde7SWilliam Kucharski v[0] = minor%10; v[1] = minor/10; 109*1b8adde7SWilliam Kucharski } 110*1b8adde7SWilliam Kucharski return major*100000+v[0]*10000+v[1]*1000; 111*1b8adde7SWilliam Kucharski } 112*1b8adde7SWilliam Kucharski #endif /* __FreeBSD_kernel__ */ 113*1b8adde7SWilliam Kucharski 114*1b8adde7SWilliam Kucharski #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) 115*1b8adde7SWilliam Kucharski # include <sys/ioctl.h> /* ioctl */ 116*1b8adde7SWilliam Kucharski # include <sys/disklabel.h> 117*1b8adde7SWilliam Kucharski # include <sys/cdio.h> /* CDIOCCLRDEBUG */ 118*1b8adde7SWilliam Kucharski # if defined(__FreeBSD_kernel__) 119*1b8adde7SWilliam Kucharski # include <sys/param.h> 120*1b8adde7SWilliam Kucharski # if __FreeBSD_kernel_version >= 500040 121*1b8adde7SWilliam Kucharski # include <sys/disk.h> 122*1b8adde7SWilliam Kucharski # endif 123*1b8adde7SWilliam Kucharski # endif /* __FreeBSD_kernel__ */ 124*1b8adde7SWilliam Kucharski #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */ 125*1b8adde7SWilliam Kucharski 126*1b8adde7SWilliam Kucharski #if defined(__sun) 127*1b8adde7SWilliam Kucharski # include <sys/dkio.h> 128*1b8adde7SWilliam Kucharski #endif /* __sun */ 129*1b8adde7SWilliam Kucharski 130*1b8adde7SWilliam Kucharski #ifdef HAVE_OPENDISK 131*1b8adde7SWilliam Kucharski # include <util.h> 132*1b8adde7SWilliam Kucharski #endif /* HAVE_OPENDISK */ 133*1b8adde7SWilliam Kucharski 134*1b8adde7SWilliam Kucharski #define WITHOUT_LIBC_STUBS 1 135*1b8adde7SWilliam Kucharski #include <shared.h> 136*1b8adde7SWilliam Kucharski #include <device.h> 137*1b8adde7SWilliam Kucharski 138*1b8adde7SWilliam Kucharski /* Get the geometry of a drive DRIVE. */ 139*1b8adde7SWilliam Kucharski void 140*1b8adde7SWilliam Kucharski get_drive_geometry (struct geometry *geom, char **map, int drive) 141*1b8adde7SWilliam Kucharski { 142*1b8adde7SWilliam Kucharski int fd; 143*1b8adde7SWilliam Kucharski 144*1b8adde7SWilliam Kucharski if (geom->flags == -1) 145*1b8adde7SWilliam Kucharski { 146*1b8adde7SWilliam Kucharski fd = open (map[drive], O_RDONLY); 147*1b8adde7SWilliam Kucharski assert (fd >= 0); 148*1b8adde7SWilliam Kucharski } 149*1b8adde7SWilliam Kucharski else 150*1b8adde7SWilliam Kucharski fd = geom->flags; 151*1b8adde7SWilliam Kucharski 152*1b8adde7SWilliam Kucharski /* XXX This is the default size. */ 153*1b8adde7SWilliam Kucharski geom->sector_size = SECTOR_SIZE; 154*1b8adde7SWilliam Kucharski 155*1b8adde7SWilliam Kucharski #if defined(__linux__) 156*1b8adde7SWilliam Kucharski /* Linux */ 157*1b8adde7SWilliam Kucharski { 158*1b8adde7SWilliam Kucharski struct hd_geometry hdg; 159*1b8adde7SWilliam Kucharski unsigned long nr; 160*1b8adde7SWilliam Kucharski 161*1b8adde7SWilliam Kucharski if (ioctl (fd, HDIO_GETGEO, &hdg)) 162*1b8adde7SWilliam Kucharski goto fail; 163*1b8adde7SWilliam Kucharski 164*1b8adde7SWilliam Kucharski if (ioctl (fd, BLKGETSIZE, &nr)) 165*1b8adde7SWilliam Kucharski goto fail; 166*1b8adde7SWilliam Kucharski 167*1b8adde7SWilliam Kucharski /* Got the geometry, so save it. */ 168*1b8adde7SWilliam Kucharski geom->cylinders = hdg.cylinders; 169*1b8adde7SWilliam Kucharski geom->heads = hdg.heads; 170*1b8adde7SWilliam Kucharski geom->sectors = hdg.sectors; 171*1b8adde7SWilliam Kucharski geom->total_sectors = nr; 172*1b8adde7SWilliam Kucharski 173*1b8adde7SWilliam Kucharski goto success; 174*1b8adde7SWilliam Kucharski } 175*1b8adde7SWilliam Kucharski 176*1b8adde7SWilliam Kucharski #elif defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) 177*1b8adde7SWilliam Kucharski # if defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040 178*1b8adde7SWilliam Kucharski /* kFreeBSD version 5 or later */ 179*1b8adde7SWilliam Kucharski if (get_kfreebsd_version () >= 500040) 180*1b8adde7SWilliam Kucharski { 181*1b8adde7SWilliam Kucharski unsigned int sector_size; 182*1b8adde7SWilliam Kucharski off_t media_size; 183*1b8adde7SWilliam Kucharski unsigned int tmp; 184*1b8adde7SWilliam Kucharski 185*1b8adde7SWilliam Kucharski if(ioctl (fd, DIOCGSECTORSIZE, §or_size) != 0) 186*1b8adde7SWilliam Kucharski sector_size = 512; 187*1b8adde7SWilliam Kucharski 188*1b8adde7SWilliam Kucharski if (ioctl (fd, DIOCGMEDIASIZE, &media_size) != 0) 189*1b8adde7SWilliam Kucharski goto fail; 190*1b8adde7SWilliam Kucharski 191*1b8adde7SWilliam Kucharski geom->total_sectors = media_size / sector_size; 192*1b8adde7SWilliam Kucharski 193*1b8adde7SWilliam Kucharski if (ioctl (fd, DIOCGFWSECTORS, &tmp) == 0) 194*1b8adde7SWilliam Kucharski geom->sectors = tmp; 195*1b8adde7SWilliam Kucharski else 196*1b8adde7SWilliam Kucharski geom->sectors = 63; 197*1b8adde7SWilliam Kucharski if (ioctl (fd, DIOCGFWHEADS, &tmp) == 0) 198*1b8adde7SWilliam Kucharski geom->heads = tmp; 199*1b8adde7SWilliam Kucharski else if (geom->total_sectors <= 63 * 1 * 1024) 200*1b8adde7SWilliam Kucharski geom->heads = 1; 201*1b8adde7SWilliam Kucharski else if (geom->total_sectors <= 63 * 16 * 1024) 202*1b8adde7SWilliam Kucharski geom->heads = 16; 203*1b8adde7SWilliam Kucharski else 204*1b8adde7SWilliam Kucharski geom->heads = 255; 205*1b8adde7SWilliam Kucharski 206*1b8adde7SWilliam Kucharski geom->cylinders = (geom->total_sectors 207*1b8adde7SWilliam Kucharski / geom->heads 208*1b8adde7SWilliam Kucharski / geom->sectors); 209*1b8adde7SWilliam Kucharski 210*1b8adde7SWilliam Kucharski goto success; 211*1b8adde7SWilliam Kucharski } 212*1b8adde7SWilliam Kucharski else 213*1b8adde7SWilliam Kucharski #endif /* defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version >= 500040 */ 214*1b8adde7SWilliam Kucharski 215*1b8adde7SWilliam Kucharski /* kFreeBSD < 5, NetBSD or OpenBSD */ 216*1b8adde7SWilliam Kucharski { 217*1b8adde7SWilliam Kucharski struct disklabel hdg; 218*1b8adde7SWilliam Kucharski if (ioctl (fd, DIOCGDINFO, &hdg)) 219*1b8adde7SWilliam Kucharski goto fail; 220*1b8adde7SWilliam Kucharski 221*1b8adde7SWilliam Kucharski geom->cylinders = hdg.d_ncylinders; 222*1b8adde7SWilliam Kucharski geom->heads = hdg.d_ntracks; 223*1b8adde7SWilliam Kucharski geom->sectors = hdg.d_nsectors; 224*1b8adde7SWilliam Kucharski geom->total_sectors = hdg.d_secperunit; 225*1b8adde7SWilliam Kucharski 226*1b8adde7SWilliam Kucharski goto success; 227*1b8adde7SWilliam Kucharski } 228*1b8adde7SWilliam Kucharski 229*1b8adde7SWilliam Kucharski #elif defined(__sun) 230*1b8adde7SWilliam Kucharski /* Solaris */ 231*1b8adde7SWilliam Kucharski { 232*1b8adde7SWilliam Kucharski struct dk_geom dkg; 233*1b8adde7SWilliam Kucharski 234*1b8adde7SWilliam Kucharski if (ioctl(fd, DKIOCG_PHYGEOM, &dkg)) 235*1b8adde7SWilliam Kucharski goto fail; 236*1b8adde7SWilliam Kucharski geom->cylinders = dkg.dkg_ncyl; 237*1b8adde7SWilliam Kucharski geom->heads = dkg.dkg_nhead; 238*1b8adde7SWilliam Kucharski geom->sectors = dkg.dkg_nsect; 239*1b8adde7SWilliam Kucharski geom->total_sectors = dkg.dkg_ncyl * dkg.dkg_nhead * dkg.dkg_nsect; 240*1b8adde7SWilliam Kucharski 241*1b8adde7SWilliam Kucharski goto success; 242*1b8adde7SWilliam Kucharski } 243*1b8adde7SWilliam Kucharski 244*1b8adde7SWilliam Kucharski #else 245*1b8adde7SWilliam Kucharski /* Notably, defined(__GNU__) */ 246*1b8adde7SWilliam Kucharski # warning "Automatic detection of geometries will be performed only \ 247*1b8adde7SWilliam Kucharski partially. This is not fatal." 248*1b8adde7SWilliam Kucharski #endif 249*1b8adde7SWilliam Kucharski 250*1b8adde7SWilliam Kucharski fail: 251*1b8adde7SWilliam Kucharski { 252*1b8adde7SWilliam Kucharski struct stat st; 253*1b8adde7SWilliam Kucharski 254*1b8adde7SWilliam Kucharski /* FIXME: It would be nice to somehow compute fake C/H/S settings, 255*1b8adde7SWilliam Kucharski given a proper st_blocks size. */ 256*1b8adde7SWilliam Kucharski if (drive & 0x80) 257*1b8adde7SWilliam Kucharski { 258*1b8adde7SWilliam Kucharski geom->cylinders = DEFAULT_HD_CYLINDERS; 259*1b8adde7SWilliam Kucharski geom->heads = DEFAULT_HD_HEADS; 260*1b8adde7SWilliam Kucharski geom->sectors = DEFAULT_HD_SECTORS; 261*1b8adde7SWilliam Kucharski } 262*1b8adde7SWilliam Kucharski else 263*1b8adde7SWilliam Kucharski { 264*1b8adde7SWilliam Kucharski geom->cylinders = DEFAULT_FD_CYLINDERS; 265*1b8adde7SWilliam Kucharski geom->heads = DEFAULT_FD_HEADS; 266*1b8adde7SWilliam Kucharski geom->sectors = DEFAULT_FD_SECTORS; 267*1b8adde7SWilliam Kucharski } 268*1b8adde7SWilliam Kucharski 269*1b8adde7SWilliam Kucharski /* Set the total sectors properly, if we can. */ 270*1b8adde7SWilliam Kucharski if (! fstat (fd, &st) && st.st_blocks) 271*1b8adde7SWilliam Kucharski geom->total_sectors = st.st_blocks >> SECTOR_BITS; 272*1b8adde7SWilliam Kucharski else 273*1b8adde7SWilliam Kucharski geom->total_sectors = geom->cylinders * geom->heads * geom->sectors; 274*1b8adde7SWilliam Kucharski } 275*1b8adde7SWilliam Kucharski 276*1b8adde7SWilliam Kucharski success: 277*1b8adde7SWilliam Kucharski if (geom->flags == -1) 278*1b8adde7SWilliam Kucharski close (fd); 279*1b8adde7SWilliam Kucharski } 280*1b8adde7SWilliam Kucharski 281*1b8adde7SWilliam Kucharski #ifdef __linux__ 282*1b8adde7SWilliam Kucharski /* Check if we have devfs support. */ 283*1b8adde7SWilliam Kucharski static int 284*1b8adde7SWilliam Kucharski have_devfs (void) 285*1b8adde7SWilliam Kucharski { 286*1b8adde7SWilliam Kucharski static int dev_devfsd_exists = -1; 287*1b8adde7SWilliam Kucharski 288*1b8adde7SWilliam Kucharski if (dev_devfsd_exists < 0) 289*1b8adde7SWilliam Kucharski { 290*1b8adde7SWilliam Kucharski struct stat st; 291*1b8adde7SWilliam Kucharski 292*1b8adde7SWilliam Kucharski dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0; 293*1b8adde7SWilliam Kucharski } 294*1b8adde7SWilliam Kucharski 295*1b8adde7SWilliam Kucharski return dev_devfsd_exists; 296*1b8adde7SWilliam Kucharski } 297*1b8adde7SWilliam Kucharski #endif /* __linux__ */ 298*1b8adde7SWilliam Kucharski 299*1b8adde7SWilliam Kucharski /* These three functions are quite different among OSes. */ 300*1b8adde7SWilliam Kucharski static void 301*1b8adde7SWilliam Kucharski get_floppy_disk_name (char *name, int unit) 302*1b8adde7SWilliam Kucharski { 303*1b8adde7SWilliam Kucharski #if defined(__linux__) 304*1b8adde7SWilliam Kucharski /* GNU/Linux */ 305*1b8adde7SWilliam Kucharski if (have_devfs ()) 306*1b8adde7SWilliam Kucharski sprintf (name, "/dev/floppy/%d", unit); 307*1b8adde7SWilliam Kucharski else 308*1b8adde7SWilliam Kucharski sprintf (name, "/dev/fd%d", unit); 309*1b8adde7SWilliam Kucharski #elif defined(__GNU__) 310*1b8adde7SWilliam Kucharski /* GNU/Hurd */ 311*1b8adde7SWilliam Kucharski sprintf (name, "/dev/fd%d", unit); 312*1b8adde7SWilliam Kucharski #elif defined(__FreeBSD_kernel__) 313*1b8adde7SWilliam Kucharski /* kFreeBSD */ 314*1b8adde7SWilliam Kucharski if (get_kfreebsd_version () >= 400000) 315*1b8adde7SWilliam Kucharski sprintf (name, "/dev/fd%d", unit); 316*1b8adde7SWilliam Kucharski else 317*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rfd%d", unit); 318*1b8adde7SWilliam Kucharski #elif defined(__NetBSD__) 319*1b8adde7SWilliam Kucharski /* NetBSD */ 320*1b8adde7SWilliam Kucharski /* opendisk() doesn't work for floppies. */ 321*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rfd%da", unit); 322*1b8adde7SWilliam Kucharski #elif defined(__OpenBSD__) 323*1b8adde7SWilliam Kucharski /* OpenBSD */ 324*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rfd%dc", unit); 325*1b8adde7SWilliam Kucharski #elif defined(__QNXNTO__) 326*1b8adde7SWilliam Kucharski /* QNX RTP */ 327*1b8adde7SWilliam Kucharski sprintf (name, "/dev/fd%d", unit); 328*1b8adde7SWilliam Kucharski #elif defined(__sun) 329*1b8adde7SWilliam Kucharski /* Solaris */ 330*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rdiskette%d", unit); 331*1b8adde7SWilliam Kucharski #else 332*1b8adde7SWilliam Kucharski # warning "BIOS floppy drives cannot be guessed in your operating system." 333*1b8adde7SWilliam Kucharski /* Set NAME to a bogus string. */ 334*1b8adde7SWilliam Kucharski *name = 0; 335*1b8adde7SWilliam Kucharski #endif 336*1b8adde7SWilliam Kucharski } 337*1b8adde7SWilliam Kucharski 338*1b8adde7SWilliam Kucharski static void 339*1b8adde7SWilliam Kucharski get_ide_disk_name (char *name, int unit) 340*1b8adde7SWilliam Kucharski { 341*1b8adde7SWilliam Kucharski #if defined(__linux__) 342*1b8adde7SWilliam Kucharski /* GNU/Linux */ 343*1b8adde7SWilliam Kucharski sprintf (name, "/dev/hd%c", unit + 'a'); 344*1b8adde7SWilliam Kucharski #elif defined(__GNU__) 345*1b8adde7SWilliam Kucharski /* GNU/Hurd */ 346*1b8adde7SWilliam Kucharski sprintf (name, "/dev/hd%d", unit); 347*1b8adde7SWilliam Kucharski #elif defined(__FreeBSD_kernel__) 348*1b8adde7SWilliam Kucharski /* kFreeBSD */ 349*1b8adde7SWilliam Kucharski if (get_kfreebsd_version () >= 400000) 350*1b8adde7SWilliam Kucharski sprintf (name, "/dev/ad%d", unit); 351*1b8adde7SWilliam Kucharski else 352*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rwd%d", unit); 353*1b8adde7SWilliam Kucharski #elif defined(__NetBSD__) && defined(HAVE_OPENDISK) 354*1b8adde7SWilliam Kucharski /* NetBSD */ 355*1b8adde7SWilliam Kucharski char shortname[16]; 356*1b8adde7SWilliam Kucharski int fd; 357*1b8adde7SWilliam Kucharski 358*1b8adde7SWilliam Kucharski sprintf (shortname, "wd%d", unit); 359*1b8adde7SWilliam Kucharski fd = opendisk (shortname, O_RDONLY, name, 360*1b8adde7SWilliam Kucharski 16, /* length of NAME */ 361*1b8adde7SWilliam Kucharski 0 /* char device */ 362*1b8adde7SWilliam Kucharski ); 363*1b8adde7SWilliam Kucharski close (fd); 364*1b8adde7SWilliam Kucharski #elif defined(__OpenBSD__) 365*1b8adde7SWilliam Kucharski /* OpenBSD */ 366*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rwd%dc", unit); 367*1b8adde7SWilliam Kucharski #elif defined(__QNXNTO__) 368*1b8adde7SWilliam Kucharski /* QNX RTP */ 369*1b8adde7SWilliam Kucharski /* Actually, QNX RTP doesn't distinguish IDE from SCSI, so this could 370*1b8adde7SWilliam Kucharski contain SCSI disks. */ 371*1b8adde7SWilliam Kucharski sprintf (name, "/dev/hd%d", unit); 372*1b8adde7SWilliam Kucharski #elif defined(__sun) 373*1b8adde7SWilliam Kucharski *name = 0; /* FIXME */ 374*1b8adde7SWilliam Kucharski #else 375*1b8adde7SWilliam Kucharski # warning "BIOS IDE drives cannot be guessed in your operating system." 376*1b8adde7SWilliam Kucharski /* Set NAME to a bogus string. */ 377*1b8adde7SWilliam Kucharski *name = 0; 378*1b8adde7SWilliam Kucharski #endif 379*1b8adde7SWilliam Kucharski } 380*1b8adde7SWilliam Kucharski 381*1b8adde7SWilliam Kucharski static void 382*1b8adde7SWilliam Kucharski get_scsi_disk_name (char *name, int unit) 383*1b8adde7SWilliam Kucharski { 384*1b8adde7SWilliam Kucharski #if defined(__linux__) 385*1b8adde7SWilliam Kucharski /* GNU/Linux */ 386*1b8adde7SWilliam Kucharski sprintf (name, "/dev/sd%c", unit + 'a'); 387*1b8adde7SWilliam Kucharski #elif defined(__GNU__) 388*1b8adde7SWilliam Kucharski /* GNU/Hurd */ 389*1b8adde7SWilliam Kucharski sprintf (name, "/dev/sd%d", unit); 390*1b8adde7SWilliam Kucharski #elif defined(__FreeBSD_kernel__) 391*1b8adde7SWilliam Kucharski /* kFreeBSD */ 392*1b8adde7SWilliam Kucharski if (get_kfreebsd_version () >= 400000) 393*1b8adde7SWilliam Kucharski sprintf (name, "/dev/da%d", unit); 394*1b8adde7SWilliam Kucharski else 395*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rda%d", unit); 396*1b8adde7SWilliam Kucharski #elif defined(__NetBSD__) && defined(HAVE_OPENDISK) 397*1b8adde7SWilliam Kucharski /* NetBSD */ 398*1b8adde7SWilliam Kucharski char shortname[16]; 399*1b8adde7SWilliam Kucharski int fd; 400*1b8adde7SWilliam Kucharski 401*1b8adde7SWilliam Kucharski sprintf (shortname, "sd%d", unit); 402*1b8adde7SWilliam Kucharski fd = opendisk (shortname, O_RDONLY, name, 403*1b8adde7SWilliam Kucharski 16, /* length of NAME */ 404*1b8adde7SWilliam Kucharski 0 /* char device */ 405*1b8adde7SWilliam Kucharski ); 406*1b8adde7SWilliam Kucharski close (fd); 407*1b8adde7SWilliam Kucharski #elif defined(__OpenBSD__) 408*1b8adde7SWilliam Kucharski /* OpenBSD */ 409*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rsd%dc", unit); 410*1b8adde7SWilliam Kucharski #elif defined(__QNXNTO__) 411*1b8adde7SWilliam Kucharski /* QNX RTP */ 412*1b8adde7SWilliam Kucharski /* QNX RTP doesn't distinguish SCSI from IDE, so it is better to 413*1b8adde7SWilliam Kucharski disable the detection of SCSI disks here. */ 414*1b8adde7SWilliam Kucharski *name = 0; 415*1b8adde7SWilliam Kucharski #elif defined(__sun) 416*1b8adde7SWilliam Kucharski *name = 0; /* FIXME */ 417*1b8adde7SWilliam Kucharski #else 418*1b8adde7SWilliam Kucharski # warning "BIOS SCSI drives cannot be guessed in your operating system." 419*1b8adde7SWilliam Kucharski /* Set NAME to a bogus string. */ 420*1b8adde7SWilliam Kucharski *name = 0; 421*1b8adde7SWilliam Kucharski #endif 422*1b8adde7SWilliam Kucharski } 423*1b8adde7SWilliam Kucharski 424*1b8adde7SWilliam Kucharski #ifdef __linux__ 425*1b8adde7SWilliam Kucharski static void 426*1b8adde7SWilliam Kucharski get_dac960_disk_name (char *name, int controller, int drive) 427*1b8adde7SWilliam Kucharski { 428*1b8adde7SWilliam Kucharski sprintf (name, "/dev/rd/c%dd%d", controller, drive); 429*1b8adde7SWilliam Kucharski } 430*1b8adde7SWilliam Kucharski 431*1b8adde7SWilliam Kucharski static void 432*1b8adde7SWilliam Kucharski get_ataraid_disk_name (char *name, int unit) 433*1b8adde7SWilliam Kucharski { 434*1b8adde7SWilliam Kucharski sprintf (name, "/dev/ataraid/d%c", unit + '0'); 435*1b8adde7SWilliam Kucharski } 436*1b8adde7SWilliam Kucharski #endif 437*1b8adde7SWilliam Kucharski 438*1b8adde7SWilliam Kucharski /* Check if DEVICE can be read. If an error occurs, return zero, 439*1b8adde7SWilliam Kucharski otherwise return non-zero. */ 440*1b8adde7SWilliam Kucharski int 441*1b8adde7SWilliam Kucharski check_device (const char *device) 442*1b8adde7SWilliam Kucharski { 443*1b8adde7SWilliam Kucharski char buf[512]; 444*1b8adde7SWilliam Kucharski FILE *fp; 445*1b8adde7SWilliam Kucharski 446*1b8adde7SWilliam Kucharski /* If DEVICE is empty, just return 1. */ 447*1b8adde7SWilliam Kucharski if (*device == 0) 448*1b8adde7SWilliam Kucharski return 1; 449*1b8adde7SWilliam Kucharski 450*1b8adde7SWilliam Kucharski fp = fopen (device, "r"); 451*1b8adde7SWilliam Kucharski if (! fp) 452*1b8adde7SWilliam Kucharski { 453*1b8adde7SWilliam Kucharski switch (errno) 454*1b8adde7SWilliam Kucharski { 455*1b8adde7SWilliam Kucharski #ifdef ENOMEDIUM 456*1b8adde7SWilliam Kucharski case ENOMEDIUM: 457*1b8adde7SWilliam Kucharski # if 0 458*1b8adde7SWilliam Kucharski /* At the moment, this finds only CDROMs, which can't be 459*1b8adde7SWilliam Kucharski read anyway, so leave it out. Code should be 460*1b8adde7SWilliam Kucharski reactivated if `removable disks' and CDROMs are 461*1b8adde7SWilliam Kucharski supported. */ 462*1b8adde7SWilliam Kucharski /* Accept it, it may be inserted. */ 463*1b8adde7SWilliam Kucharski return 1; 464*1b8adde7SWilliam Kucharski # endif 465*1b8adde7SWilliam Kucharski break; 466*1b8adde7SWilliam Kucharski #endif /* ENOMEDIUM */ 467*1b8adde7SWilliam Kucharski default: 468*1b8adde7SWilliam Kucharski /* Break case and leave. */ 469*1b8adde7SWilliam Kucharski break; 470*1b8adde7SWilliam Kucharski } 471*1b8adde7SWilliam Kucharski /* Error opening the device. */ 472*1b8adde7SWilliam Kucharski return 0; 473*1b8adde7SWilliam Kucharski } 474*1b8adde7SWilliam Kucharski 475*1b8adde7SWilliam Kucharski /* Make sure CD-ROMs don't get assigned a BIOS disk number 476*1b8adde7SWilliam Kucharski before SCSI disks! */ 477*1b8adde7SWilliam Kucharski #ifdef __linux__ 478*1b8adde7SWilliam Kucharski # ifdef CDROM_GET_CAPABILITY 479*1b8adde7SWilliam Kucharski if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0) 480*1b8adde7SWilliam Kucharski return 0; 481*1b8adde7SWilliam Kucharski # else /* ! CDROM_GET_CAPABILITY */ 482*1b8adde7SWilliam Kucharski /* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */ 483*1b8adde7SWilliam Kucharski { 484*1b8adde7SWilliam Kucharski struct hd_geometry hdg; 485*1b8adde7SWilliam Kucharski struct stat st; 486*1b8adde7SWilliam Kucharski 487*1b8adde7SWilliam Kucharski if (fstat (fileno (fp), &st)) 488*1b8adde7SWilliam Kucharski return 0; 489*1b8adde7SWilliam Kucharski 490*1b8adde7SWilliam Kucharski /* If it is a block device and isn't a floppy, check if HDIO_GETGEO 491*1b8adde7SWilliam Kucharski succeeds. */ 492*1b8adde7SWilliam Kucharski if (S_ISBLK (st.st_mode) 493*1b8adde7SWilliam Kucharski && MAJOR (st.st_rdev) != FLOPPY_MAJOR 494*1b8adde7SWilliam Kucharski && ioctl (fileno (fp), HDIO_GETGEO, &hdg)) 495*1b8adde7SWilliam Kucharski return 0; 496*1b8adde7SWilliam Kucharski } 497*1b8adde7SWilliam Kucharski # endif /* ! CDROM_GET_CAPABILITY */ 498*1b8adde7SWilliam Kucharski #endif /* __linux__ */ 499*1b8adde7SWilliam Kucharski 500*1b8adde7SWilliam Kucharski #if defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) 501*1b8adde7SWilliam Kucharski # ifdef CDIOCCLRDEBUG 502*1b8adde7SWilliam Kucharski if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0) 503*1b8adde7SWilliam Kucharski return 0; 504*1b8adde7SWilliam Kucharski # endif /* CDIOCCLRDEBUG */ 505*1b8adde7SWilliam Kucharski #endif /* __FreeBSD_kernel__ || __NetBSD__ || __OpenBSD__ */ 506*1b8adde7SWilliam Kucharski 507*1b8adde7SWilliam Kucharski /* Attempt to read the first sector. */ 508*1b8adde7SWilliam Kucharski if (fread (buf, 1, 512, fp) != 512) 509*1b8adde7SWilliam Kucharski { 510*1b8adde7SWilliam Kucharski fclose (fp); 511*1b8adde7SWilliam Kucharski return 0; 512*1b8adde7SWilliam Kucharski } 513*1b8adde7SWilliam Kucharski 514*1b8adde7SWilliam Kucharski fclose (fp); 515*1b8adde7SWilliam Kucharski return 1; 516*1b8adde7SWilliam Kucharski } 517*1b8adde7SWilliam Kucharski 518*1b8adde7SWilliam Kucharski /* Read mapping information from FP, and write it to MAP. */ 519*1b8adde7SWilliam Kucharski static int 520*1b8adde7SWilliam Kucharski read_device_map (FILE *fp, char **map, const char *map_file) 521*1b8adde7SWilliam Kucharski { 522*1b8adde7SWilliam Kucharski auto void show_error (int no, const char *msg); 523*1b8adde7SWilliam Kucharski auto void show_warning (int no, const char *msg, ...); 524*1b8adde7SWilliam Kucharski 525*1b8adde7SWilliam Kucharski auto void show_error (int no, const char *msg) 526*1b8adde7SWilliam Kucharski { 527*1b8adde7SWilliam Kucharski fprintf (stderr, "%s:%d: error: %s\n", map_file, no, msg); 528*1b8adde7SWilliam Kucharski } 529*1b8adde7SWilliam Kucharski 530*1b8adde7SWilliam Kucharski auto void show_warning (int no, const char *msg, ...) 531*1b8adde7SWilliam Kucharski { 532*1b8adde7SWilliam Kucharski va_list ap; 533*1b8adde7SWilliam Kucharski 534*1b8adde7SWilliam Kucharski va_start (ap, msg); 535*1b8adde7SWilliam Kucharski fprintf (stderr, "%s:%d: warning: ", map_file, no); 536*1b8adde7SWilliam Kucharski vfprintf (stderr, msg, ap); 537*1b8adde7SWilliam Kucharski va_end (ap); 538*1b8adde7SWilliam Kucharski } 539*1b8adde7SWilliam Kucharski 540*1b8adde7SWilliam Kucharski /* If there is the device map file, use the data in it instead of 541*1b8adde7SWilliam Kucharski probing devices. */ 542*1b8adde7SWilliam Kucharski char buf[1024]; /* XXX */ 543*1b8adde7SWilliam Kucharski int line_number = 0; 544*1b8adde7SWilliam Kucharski 545*1b8adde7SWilliam Kucharski while (fgets (buf, sizeof (buf), fp)) 546*1b8adde7SWilliam Kucharski { 547*1b8adde7SWilliam Kucharski char *ptr, *eptr; 548*1b8adde7SWilliam Kucharski int drive; 549*1b8adde7SWilliam Kucharski int is_floppy = 0; 550*1b8adde7SWilliam Kucharski 551*1b8adde7SWilliam Kucharski /* Increase the number of lines. */ 552*1b8adde7SWilliam Kucharski line_number++; 553*1b8adde7SWilliam Kucharski 554*1b8adde7SWilliam Kucharski /* If the first character is '#', skip it. */ 555*1b8adde7SWilliam Kucharski if (buf[0] == '#') 556*1b8adde7SWilliam Kucharski continue; 557*1b8adde7SWilliam Kucharski 558*1b8adde7SWilliam Kucharski ptr = buf; 559*1b8adde7SWilliam Kucharski /* Skip leading spaces. */ 560*1b8adde7SWilliam Kucharski while (*ptr && isspace (*ptr)) 561*1b8adde7SWilliam Kucharski ptr++; 562*1b8adde7SWilliam Kucharski 563*1b8adde7SWilliam Kucharski /* Skip empty lines. */ 564*1b8adde7SWilliam Kucharski if (! *ptr) 565*1b8adde7SWilliam Kucharski continue; 566*1b8adde7SWilliam Kucharski 567*1b8adde7SWilliam Kucharski if (*ptr != '(') 568*1b8adde7SWilliam Kucharski { 569*1b8adde7SWilliam Kucharski show_error (line_number, "No open parenthesis found"); 570*1b8adde7SWilliam Kucharski return 0; 571*1b8adde7SWilliam Kucharski } 572*1b8adde7SWilliam Kucharski 573*1b8adde7SWilliam Kucharski ptr++; 574*1b8adde7SWilliam Kucharski if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd') 575*1b8adde7SWilliam Kucharski { 576*1b8adde7SWilliam Kucharski show_error (line_number, "Bad drive name"); 577*1b8adde7SWilliam Kucharski return 0; 578*1b8adde7SWilliam Kucharski } 579*1b8adde7SWilliam Kucharski 580*1b8adde7SWilliam Kucharski if (*ptr == 'f') 581*1b8adde7SWilliam Kucharski is_floppy = 1; 582*1b8adde7SWilliam Kucharski 583*1b8adde7SWilliam Kucharski ptr += 2; 584*1b8adde7SWilliam Kucharski drive = strtoul (ptr, &ptr, 10); 585*1b8adde7SWilliam Kucharski if (drive < 0) 586*1b8adde7SWilliam Kucharski { 587*1b8adde7SWilliam Kucharski show_error (line_number, "Bad device number"); 588*1b8adde7SWilliam Kucharski return 0; 589*1b8adde7SWilliam Kucharski } 590*1b8adde7SWilliam Kucharski else if (drive > 127) 591*1b8adde7SWilliam Kucharski { 592*1b8adde7SWilliam Kucharski show_warning (line_number, 593*1b8adde7SWilliam Kucharski "Ignoring %cd%d due to a BIOS limitation", 594*1b8adde7SWilliam Kucharski is_floppy ? 'f' : 'h', drive); 595*1b8adde7SWilliam Kucharski continue; 596*1b8adde7SWilliam Kucharski } 597*1b8adde7SWilliam Kucharski 598*1b8adde7SWilliam Kucharski if (! is_floppy) 599*1b8adde7SWilliam Kucharski drive += 0x80; 600*1b8adde7SWilliam Kucharski 601*1b8adde7SWilliam Kucharski if (*ptr != ')') 602*1b8adde7SWilliam Kucharski { 603*1b8adde7SWilliam Kucharski show_error (line_number, "No close parenthesis found"); 604*1b8adde7SWilliam Kucharski return 0; 605*1b8adde7SWilliam Kucharski } 606*1b8adde7SWilliam Kucharski 607*1b8adde7SWilliam Kucharski ptr++; 608*1b8adde7SWilliam Kucharski /* Skip spaces. */ 609*1b8adde7SWilliam Kucharski while (*ptr && isspace (*ptr)) 610*1b8adde7SWilliam Kucharski ptr++; 611*1b8adde7SWilliam Kucharski 612*1b8adde7SWilliam Kucharski if (! *ptr) 613*1b8adde7SWilliam Kucharski { 614*1b8adde7SWilliam Kucharski show_error (line_number, "No filename found"); 615*1b8adde7SWilliam Kucharski return 0; 616*1b8adde7SWilliam Kucharski } 617*1b8adde7SWilliam Kucharski 618*1b8adde7SWilliam Kucharski /* Terminate the filename. */ 619*1b8adde7SWilliam Kucharski eptr = ptr; 620*1b8adde7SWilliam Kucharski while (*eptr && ! isspace (*eptr)) 621*1b8adde7SWilliam Kucharski eptr++; 622*1b8adde7SWilliam Kucharski *eptr = 0; 623*1b8adde7SWilliam Kucharski 624*1b8adde7SWilliam Kucharski /* Multiple entries for a given drive is not allowed. */ 625*1b8adde7SWilliam Kucharski if (map[drive]) 626*1b8adde7SWilliam Kucharski { 627*1b8adde7SWilliam Kucharski show_error (line_number, "Duplicated entry found"); 628*1b8adde7SWilliam Kucharski return 0; 629*1b8adde7SWilliam Kucharski } 630*1b8adde7SWilliam Kucharski 631*1b8adde7SWilliam Kucharski map[drive] = strdup (ptr); 632*1b8adde7SWilliam Kucharski assert (map[drive]); 633*1b8adde7SWilliam Kucharski } 634*1b8adde7SWilliam Kucharski 635*1b8adde7SWilliam Kucharski return 1; 636*1b8adde7SWilliam Kucharski } 637*1b8adde7SWilliam Kucharski 638*1b8adde7SWilliam Kucharski /* Initialize the device map MAP. *MAP will be allocated from the heap 639*1b8adde7SWilliam Kucharski space. If MAP_FILE is not NULL, then read mappings from the file 640*1b8adde7SWilliam Kucharski MAP_FILE if it exists, otherwise, write guessed mappings to the file. 641*1b8adde7SWilliam Kucharski FLOPPY_DISKS is the number of floppy disk drives which will be probed. 642*1b8adde7SWilliam Kucharski If it is zero, don't probe any floppy at all. If it is one, probe one 643*1b8adde7SWilliam Kucharski floppy. If it is two, probe two floppies. And so on. */ 644*1b8adde7SWilliam Kucharski int 645*1b8adde7SWilliam Kucharski init_device_map (char ***map, const char *map_file, int floppy_disks) 646*1b8adde7SWilliam Kucharski { 647*1b8adde7SWilliam Kucharski int i; 648*1b8adde7SWilliam Kucharski int num_hd = 0; 649*1b8adde7SWilliam Kucharski FILE *fp = 0; 650*1b8adde7SWilliam Kucharski 651*1b8adde7SWilliam Kucharski assert (map); 652*1b8adde7SWilliam Kucharski assert (*map == 0); 653*1b8adde7SWilliam Kucharski *map = malloc (NUM_DISKS * sizeof (char *)); 654*1b8adde7SWilliam Kucharski assert (*map); 655*1b8adde7SWilliam Kucharski 656*1b8adde7SWilliam Kucharski /* Probe devices for creating the device map. */ 657*1b8adde7SWilliam Kucharski 658*1b8adde7SWilliam Kucharski /* Initialize DEVICE_MAP. */ 659*1b8adde7SWilliam Kucharski for (i = 0; i < NUM_DISKS; i++) 660*1b8adde7SWilliam Kucharski (*map)[i] = 0; 661*1b8adde7SWilliam Kucharski 662*1b8adde7SWilliam Kucharski if (map_file) 663*1b8adde7SWilliam Kucharski { 664*1b8adde7SWilliam Kucharski /* Open the device map file. */ 665*1b8adde7SWilliam Kucharski fp = fopen (map_file, "r"); 666*1b8adde7SWilliam Kucharski if (fp) 667*1b8adde7SWilliam Kucharski { 668*1b8adde7SWilliam Kucharski int ret; 669*1b8adde7SWilliam Kucharski 670*1b8adde7SWilliam Kucharski ret = read_device_map (fp, *map, map_file); 671*1b8adde7SWilliam Kucharski fclose (fp); 672*1b8adde7SWilliam Kucharski return ret; 673*1b8adde7SWilliam Kucharski } 674*1b8adde7SWilliam Kucharski } 675*1b8adde7SWilliam Kucharski 676*1b8adde7SWilliam Kucharski /* Print something so that the user does not think GRUB has been 677*1b8adde7SWilliam Kucharski crashed. */ 678*1b8adde7SWilliam Kucharski fprintf (stderr, 679*1b8adde7SWilliam Kucharski "Probing devices to guess BIOS drives. " 680*1b8adde7SWilliam Kucharski "This may take a long time.\n"); 681*1b8adde7SWilliam Kucharski 682*1b8adde7SWilliam Kucharski if (map_file) 683*1b8adde7SWilliam Kucharski /* Try to open the device map file to write the probed data. */ 684*1b8adde7SWilliam Kucharski fp = fopen (map_file, "w"); 685*1b8adde7SWilliam Kucharski 686*1b8adde7SWilliam Kucharski /* Floppies. */ 687*1b8adde7SWilliam Kucharski for (i = 0; i < floppy_disks; i++) 688*1b8adde7SWilliam Kucharski { 689*1b8adde7SWilliam Kucharski char name[16]; 690*1b8adde7SWilliam Kucharski 691*1b8adde7SWilliam Kucharski get_floppy_disk_name (name, i); 692*1b8adde7SWilliam Kucharski /* In floppies, write the map, whether check_device succeeds 693*1b8adde7SWilliam Kucharski or not, because the user just does not insert floppies. */ 694*1b8adde7SWilliam Kucharski if (fp) 695*1b8adde7SWilliam Kucharski fprintf (fp, "(fd%d)\t%s\n", i, name); 696*1b8adde7SWilliam Kucharski 697*1b8adde7SWilliam Kucharski if (check_device (name)) 698*1b8adde7SWilliam Kucharski { 699*1b8adde7SWilliam Kucharski (*map)[i] = strdup (name); 700*1b8adde7SWilliam Kucharski assert ((*map)[i]); 701*1b8adde7SWilliam Kucharski } 702*1b8adde7SWilliam Kucharski } 703*1b8adde7SWilliam Kucharski 704*1b8adde7SWilliam Kucharski #ifdef __linux__ 705*1b8adde7SWilliam Kucharski if (have_devfs ()) 706*1b8adde7SWilliam Kucharski { 707*1b8adde7SWilliam Kucharski while (1) 708*1b8adde7SWilliam Kucharski { 709*1b8adde7SWilliam Kucharski char discn[32]; 710*1b8adde7SWilliam Kucharski char name[PATH_MAX]; 711*1b8adde7SWilliam Kucharski struct stat st; 712*1b8adde7SWilliam Kucharski 713*1b8adde7SWilliam Kucharski /* Linux creates symlinks "/dev/discs/discN" for convenience. 714*1b8adde7SWilliam Kucharski The way to number disks is the same as GRUB's. */ 715*1b8adde7SWilliam Kucharski sprintf (discn, "/dev/discs/disc%d", num_hd); 716*1b8adde7SWilliam Kucharski if (stat (discn, &st) < 0) 717*1b8adde7SWilliam Kucharski break; 718*1b8adde7SWilliam Kucharski 719*1b8adde7SWilliam Kucharski if (realpath (discn, name)) 720*1b8adde7SWilliam Kucharski { 721*1b8adde7SWilliam Kucharski strcat (name, "/disc"); 722*1b8adde7SWilliam Kucharski (*map)[num_hd + 0x80] = strdup (name); 723*1b8adde7SWilliam Kucharski assert ((*map)[num_hd + 0x80]); 724*1b8adde7SWilliam Kucharski 725*1b8adde7SWilliam Kucharski /* If the device map file is opened, write the map. */ 726*1b8adde7SWilliam Kucharski if (fp) 727*1b8adde7SWilliam Kucharski fprintf (fp, "(hd%d)\t%s\n", num_hd, name); 728*1b8adde7SWilliam Kucharski } 729*1b8adde7SWilliam Kucharski 730*1b8adde7SWilliam Kucharski num_hd++; 731*1b8adde7SWilliam Kucharski } 732*1b8adde7SWilliam Kucharski 733*1b8adde7SWilliam Kucharski /* OK, close the device map file if opened. */ 734*1b8adde7SWilliam Kucharski if (fp) 735*1b8adde7SWilliam Kucharski fclose (fp); 736*1b8adde7SWilliam Kucharski 737*1b8adde7SWilliam Kucharski return 1; 738*1b8adde7SWilliam Kucharski } 739*1b8adde7SWilliam Kucharski #endif /* __linux__ */ 740*1b8adde7SWilliam Kucharski 741*1b8adde7SWilliam Kucharski /* IDE disks. */ 742*1b8adde7SWilliam Kucharski for (i = 0; i < 8; i++) 743*1b8adde7SWilliam Kucharski { 744*1b8adde7SWilliam Kucharski char name[16]; 745*1b8adde7SWilliam Kucharski 746*1b8adde7SWilliam Kucharski get_ide_disk_name (name, i); 747*1b8adde7SWilliam Kucharski if (check_device (name)) 748*1b8adde7SWilliam Kucharski { 749*1b8adde7SWilliam Kucharski (*map)[num_hd + 0x80] = strdup (name); 750*1b8adde7SWilliam Kucharski assert ((*map)[num_hd + 0x80]); 751*1b8adde7SWilliam Kucharski 752*1b8adde7SWilliam Kucharski /* If the device map file is opened, write the map. */ 753*1b8adde7SWilliam Kucharski if (fp) 754*1b8adde7SWilliam Kucharski fprintf (fp, "(hd%d)\t%s\n", num_hd, name); 755*1b8adde7SWilliam Kucharski 756*1b8adde7SWilliam Kucharski num_hd++; 757*1b8adde7SWilliam Kucharski } 758*1b8adde7SWilliam Kucharski } 759*1b8adde7SWilliam Kucharski 760*1b8adde7SWilliam Kucharski #ifdef __linux__ 761*1b8adde7SWilliam Kucharski /* ATARAID disks. */ 762*1b8adde7SWilliam Kucharski for (i = 0; i < 8; i++) 763*1b8adde7SWilliam Kucharski { 764*1b8adde7SWilliam Kucharski char name[20]; 765*1b8adde7SWilliam Kucharski 766*1b8adde7SWilliam Kucharski get_ataraid_disk_name (name, i); 767*1b8adde7SWilliam Kucharski if (check_device (name)) 768*1b8adde7SWilliam Kucharski { 769*1b8adde7SWilliam Kucharski (*map)[num_hd + 0x80] = strdup (name); 770*1b8adde7SWilliam Kucharski assert ((*map)[num_hd + 0x80]); 771*1b8adde7SWilliam Kucharski 772*1b8adde7SWilliam Kucharski /* If the device map file is opened, write the map. */ 773*1b8adde7SWilliam Kucharski if (fp) 774*1b8adde7SWilliam Kucharski fprintf (fp, "(hd%d)\t%s\n", num_hd, name); 775*1b8adde7SWilliam Kucharski 776*1b8adde7SWilliam Kucharski num_hd++; 777*1b8adde7SWilliam Kucharski } 778*1b8adde7SWilliam Kucharski } 779*1b8adde7SWilliam Kucharski #endif /* __linux__ */ 780*1b8adde7SWilliam Kucharski 781*1b8adde7SWilliam Kucharski /* The rest is SCSI disks. */ 782*1b8adde7SWilliam Kucharski for (i = 0; i < 16; i++) 783*1b8adde7SWilliam Kucharski { 784*1b8adde7SWilliam Kucharski char name[16]; 785*1b8adde7SWilliam Kucharski 786*1b8adde7SWilliam Kucharski get_scsi_disk_name (name, i); 787*1b8adde7SWilliam Kucharski if (check_device (name)) 788*1b8adde7SWilliam Kucharski { 789*1b8adde7SWilliam Kucharski (*map)[num_hd + 0x80] = strdup (name); 790*1b8adde7SWilliam Kucharski assert ((*map)[num_hd + 0x80]); 791*1b8adde7SWilliam Kucharski 792*1b8adde7SWilliam Kucharski /* If the device map file is opened, write the map. */ 793*1b8adde7SWilliam Kucharski if (fp) 794*1b8adde7SWilliam Kucharski fprintf (fp, "(hd%d)\t%s\n", num_hd, name); 795*1b8adde7SWilliam Kucharski 796*1b8adde7SWilliam Kucharski num_hd++; 797*1b8adde7SWilliam Kucharski } 798*1b8adde7SWilliam Kucharski } 799*1b8adde7SWilliam Kucharski 800*1b8adde7SWilliam Kucharski #ifdef __linux__ 801*1b8adde7SWilliam Kucharski /* This is for DAC960 - we have 802*1b8adde7SWilliam Kucharski /dev/rd/c<controller>d<logical drive>p<partition>. 803*1b8adde7SWilliam Kucharski 804*1b8adde7SWilliam Kucharski DAC960 driver currently supports up to 8 controllers, 32 logical 805*1b8adde7SWilliam Kucharski drives, and 7 partitions. */ 806*1b8adde7SWilliam Kucharski { 807*1b8adde7SWilliam Kucharski int controller, drive; 808*1b8adde7SWilliam Kucharski 809*1b8adde7SWilliam Kucharski for (controller = 0; controller < 8; controller++) 810*1b8adde7SWilliam Kucharski { 811*1b8adde7SWilliam Kucharski for (drive = 0; drive < 15; drive++) 812*1b8adde7SWilliam Kucharski { 813*1b8adde7SWilliam Kucharski char name[24]; 814*1b8adde7SWilliam Kucharski 815*1b8adde7SWilliam Kucharski get_dac960_disk_name (name, controller, drive); 816*1b8adde7SWilliam Kucharski if (check_device (name)) 817*1b8adde7SWilliam Kucharski { 818*1b8adde7SWilliam Kucharski (*map)[num_hd + 0x80] = strdup (name); 819*1b8adde7SWilliam Kucharski assert ((*map)[num_hd + 0x80]); 820*1b8adde7SWilliam Kucharski 821*1b8adde7SWilliam Kucharski /* If the device map file is opened, write the map. */ 822*1b8adde7SWilliam Kucharski if (fp) 823*1b8adde7SWilliam Kucharski fprintf (fp, "(hd%d)\t%s\n", num_hd, name); 824*1b8adde7SWilliam Kucharski 825*1b8adde7SWilliam Kucharski num_hd++; 826*1b8adde7SWilliam Kucharski } 827*1b8adde7SWilliam Kucharski } 828*1b8adde7SWilliam Kucharski } 829*1b8adde7SWilliam Kucharski } 830*1b8adde7SWilliam Kucharski #endif /* __linux__ */ 831*1b8adde7SWilliam Kucharski 832*1b8adde7SWilliam Kucharski /* OK, close the device map file if opened. */ 833*1b8adde7SWilliam Kucharski if (fp) 834*1b8adde7SWilliam Kucharski fclose (fp); 835*1b8adde7SWilliam Kucharski 836*1b8adde7SWilliam Kucharski return 1; 837*1b8adde7SWilliam Kucharski } 838*1b8adde7SWilliam Kucharski 839*1b8adde7SWilliam Kucharski /* Restore the memory consumed for MAP. */ 840*1b8adde7SWilliam Kucharski void 841*1b8adde7SWilliam Kucharski restore_device_map (char **map) 842*1b8adde7SWilliam Kucharski { 843*1b8adde7SWilliam Kucharski int i; 844*1b8adde7SWilliam Kucharski 845*1b8adde7SWilliam Kucharski for (i = 0; i < NUM_DISKS; i++) 846*1b8adde7SWilliam Kucharski if (map[i]) 847*1b8adde7SWilliam Kucharski free (map[i]); 848*1b8adde7SWilliam Kucharski 849*1b8adde7SWilliam Kucharski free (map); 850*1b8adde7SWilliam Kucharski } 851*1b8adde7SWilliam Kucharski 852*1b8adde7SWilliam Kucharski #ifdef __linux__ 853*1b8adde7SWilliam Kucharski /* Linux-only functions, because Linux has a bug that the disk cache for 854*1b8adde7SWilliam Kucharski a whole disk is not consistent with the one for a partition of the 855*1b8adde7SWilliam Kucharski disk. */ 856*1b8adde7SWilliam Kucharski int 857*1b8adde7SWilliam Kucharski is_disk_device (char **map, int drive) 858*1b8adde7SWilliam Kucharski { 859*1b8adde7SWilliam Kucharski struct stat st; 860*1b8adde7SWilliam Kucharski 861*1b8adde7SWilliam Kucharski assert (map[drive] != 0); 862*1b8adde7SWilliam Kucharski assert (stat (map[drive], &st) == 0); 863*1b8adde7SWilliam Kucharski /* For now, disk devices under Linux are all block devices. */ 864*1b8adde7SWilliam Kucharski return S_ISBLK (st.st_mode); 865*1b8adde7SWilliam Kucharski } 866*1b8adde7SWilliam Kucharski 867*1b8adde7SWilliam Kucharski int 868*1b8adde7SWilliam Kucharski write_to_partition (char **map, int drive, int partition, 869*1b8adde7SWilliam Kucharski int sector, int size, const char *buf) 870*1b8adde7SWilliam Kucharski { 871*1b8adde7SWilliam Kucharski char dev[PATH_MAX]; /* XXX */ 872*1b8adde7SWilliam Kucharski int fd; 873*1b8adde7SWilliam Kucharski 874*1b8adde7SWilliam Kucharski if ((partition & 0x00FF00) != 0x00FF00) 875*1b8adde7SWilliam Kucharski { 876*1b8adde7SWilliam Kucharski /* If the partition is a BSD partition, it is difficult to 877*1b8adde7SWilliam Kucharski obtain the representation in Linux. So don't support that. */ 878*1b8adde7SWilliam Kucharski errnum = ERR_DEV_VALUES; 879*1b8adde7SWilliam Kucharski return 1; 880*1b8adde7SWilliam Kucharski } 881*1b8adde7SWilliam Kucharski 882*1b8adde7SWilliam Kucharski assert (map[drive] != 0); 883*1b8adde7SWilliam Kucharski 884*1b8adde7SWilliam Kucharski strcpy (dev, map[drive]); 885*1b8adde7SWilliam Kucharski if (have_devfs ()) 886*1b8adde7SWilliam Kucharski { 887*1b8adde7SWilliam Kucharski if (strcmp (dev + strlen(dev) - 5, "/disc") == 0) 888*1b8adde7SWilliam Kucharski strcpy (dev + strlen(dev) - 5, "/part"); 889*1b8adde7SWilliam Kucharski } 890*1b8adde7SWilliam Kucharski sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1); 891*1b8adde7SWilliam Kucharski 892*1b8adde7SWilliam Kucharski /* Open the partition. */ 893*1b8adde7SWilliam Kucharski fd = open (dev, O_RDWR); 894*1b8adde7SWilliam Kucharski if (fd < 0) 895*1b8adde7SWilliam Kucharski { 896*1b8adde7SWilliam Kucharski errnum = ERR_NO_PART; 897*1b8adde7SWilliam Kucharski return 0; 898*1b8adde7SWilliam Kucharski } 899*1b8adde7SWilliam Kucharski 900*1b8adde7SWilliam Kucharski #if defined(__linux__) && (!defined(__GLIBC__) || \ 901*1b8adde7SWilliam Kucharski ((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))) 902*1b8adde7SWilliam Kucharski /* Maybe libc doesn't have large file support. */ 903*1b8adde7SWilliam Kucharski { 904*1b8adde7SWilliam Kucharski loff_t offset, result; 905*1b8adde7SWilliam Kucharski static int _llseek (uint filedes, ulong hi, ulong lo, 906*1b8adde7SWilliam Kucharski loff_t *res, uint wh); 907*1b8adde7SWilliam Kucharski _syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo, 908*1b8adde7SWilliam Kucharski loff_t *, res, uint, wh); 909*1b8adde7SWilliam Kucharski 910*1b8adde7SWilliam Kucharski offset = (loff_t) sector * (loff_t) SECTOR_SIZE; 911*1b8adde7SWilliam Kucharski if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET)) 912*1b8adde7SWilliam Kucharski { 913*1b8adde7SWilliam Kucharski errnum = ERR_DEV_VALUES; 914*1b8adde7SWilliam Kucharski return 0; 915*1b8adde7SWilliam Kucharski } 916*1b8adde7SWilliam Kucharski } 917*1b8adde7SWilliam Kucharski #else 918*1b8adde7SWilliam Kucharski { 919*1b8adde7SWilliam Kucharski off_t offset = (off_t) sector * (off_t) SECTOR_SIZE; 920*1b8adde7SWilliam Kucharski 921*1b8adde7SWilliam Kucharski if (lseek (fd, offset, SEEK_SET) != offset) 922*1b8adde7SWilliam Kucharski { 923*1b8adde7SWilliam Kucharski errnum = ERR_DEV_VALUES; 924*1b8adde7SWilliam Kucharski return 0; 925*1b8adde7SWilliam Kucharski } 926*1b8adde7SWilliam Kucharski } 927*1b8adde7SWilliam Kucharski #endif 928*1b8adde7SWilliam Kucharski 929*1b8adde7SWilliam Kucharski if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE)) 930*1b8adde7SWilliam Kucharski { 931*1b8adde7SWilliam Kucharski close (fd); 932*1b8adde7SWilliam Kucharski errnum = ERR_WRITE; 933*1b8adde7SWilliam Kucharski return 0; 934*1b8adde7SWilliam Kucharski } 935*1b8adde7SWilliam Kucharski 936*1b8adde7SWilliam Kucharski sync (); /* Paranoia. */ 937*1b8adde7SWilliam Kucharski close (fd); 938*1b8adde7SWilliam Kucharski 939*1b8adde7SWilliam Kucharski return 1; 940*1b8adde7SWilliam Kucharski } 941*1b8adde7SWilliam Kucharski #endif /* __linux__ */ 942