xref: /titanic_53/usr/src/grub/grub-0.97/lib/device.c (revision 1b8adde7ba7d5e04395c141c5400dc2cffd7d809)
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, &sector_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