segreate os-specific helper functions from asmstub.c.

This commit is contained in:
okuji 2000-07-11 16:13:46 +00:00
parent c13d2ca24e
commit 05581f3233
10 changed files with 614 additions and 464 deletions

View file

@ -1,3 +1,39 @@
2000-07-12 OKUJI Yoshinori <okuji@gnu.org>
Segreate OS-specific helper functions from asmstub.c.
* grub/asmstub.c [__linux__]: Don't include linux/hdreg.h,
linux/major.h, linux/kdev_t.h, or linux/cdrom.h.
[__FreeBSD__ || __NetBSD__ || __OpenBSD__]: Don't include
sys/ioctl.h, sys/disklabel.h, or sys/ioctl.h.
[HAVE_OPENDISK]: Don't include util.h.
Include device.h.
(DEFAULT_FD_CYLINDERS): Removed.
(DEFAULT_FD_HEADS): Likewise.
(DEFAULT_FD_SECTORS): Likewise.
(DEFAULT_HD_CYLINDERS): Likewise.
(DEFAULT_HD_HEADS): Likewise.
(DEFAULT_HD_SECTORS): Likewise.
(NUM_DISKS): Likewise.
(init_device_map): Likewise.
(get_floppy_disk_name): Likewise.
(get_ide_disk_name): Likewise.
(get_scsi_disk_name): Likewise.
(check_device): Likewise.
(get_drive_geometry): Likewise.
* grub/main.c (no_floppy): Removed.
(probe_second_floppy): Likewise.
(floppy_disks): New global variable.
(main): Set FLOPPY_DISKS to zero, if OPT_NO_FLOPPY. Set
FLOPPY_DISKS to two, if OPT_PROBE_SECOND_FLOPPY.
* lib/Makefile.am (AM_CFLAGS): New variable.
* lib/device.h: New file.
* lib/device.c: Likewise.
* stage2/shared.h (no_floppy): Removed.
(probe_second_floppy): Likewise.
(check_device): Likewise.
(floppy_disks): Declared.
2000-07-02 OKUJI Yoshinori <okuji@gnu.org>
* grub/main.c (usage): Enclose the mail address with parentheses

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.020.
.TH GRUB-INSTALL "8" "June 2000" "grub-install (GNU GRUB 0.5.96)" FSF
.TH GRUB-INSTALL "8" "July 2000" "grub-install (GNU GRUB 0.5.96)" FSF
.SH NAME
grub-install \- install GRUB on your drive
.SH SYNOPSIS

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.020.
.TH MBCHK "1" "June 2000" "mbchk (GNU GRUB 0.5.96)" FSF
.TH MBCHK "1" "July 2000" "mbchk (GNU GRUB 0.5.96)" FSF
.SH NAME
mbchk \- check the format of a Multiboot kernel
.SH SYNOPSIS

View file

@ -42,10 +42,6 @@ int grub_stage2 (void);
#ifdef __linux__
# include <sys/ioctl.h> /* ioctl */
# include <linux/hdreg.h> /* HDIO_GETGEO */
# include <linux/major.h> /* FLOPPY_MAJOR */
# include <linux/kdev_t.h> /* MAJOR */
# include <linux/cdrom.h> /* CDROM_GET_CAPABILITY */
# if (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))
/* Maybe libc doesn't have large file support. */
# include <linux/unistd.h> /* _llseek */
@ -56,33 +52,16 @@ int grub_stage2 (void);
# endif /* ! BLKFLSBUF */
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/ioctl.h> /* ioctl */
# include <sys/disklabel.h>
# include <sys/cdio.h> /* CDIOCCLRDEBUG */
#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ */
#ifdef HAVE_OPENDISK
# include <util.h>
#endif /* HAVE_OPENDISK */
/* We want to prevent any circularararity in our stubs, as well as
libc name clashes. */
#define WITHOUT_LIBC_STUBS 1
#include "shared.h"
#include <shared.h>
#include <device.h>
/* Simulated memory sizes. */
#define EXTENDED_MEMSIZE (3 * 1024 * 1024) /* 3MB */
#define CONVENTIONAL_MEMSIZE (640 * 1024) /* 640kB */
/* Simulated disk sizes. */
#define DEFAULT_FD_CYLINDERS 80
#define DEFAULT_FD_HEADS 2
#define DEFAULT_FD_SECTORS 18
#define DEFAULT_HD_CYLINDERS 620
#define DEFAULT_HD_HEADS 128
#define DEFAULT_HD_SECTORS 63
unsigned long install_partition = 0x20000;
unsigned long boot_drive = 0;
char version_string[] = VERSION;
@ -91,7 +70,6 @@ char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */
/* Emulation requirements. */
char *grub_scratch_mem = 0;
#define NUM_DISKS 256
struct geometry *disks = 0;
/* The map between BIOS drives and UNIX device file names. */
@ -100,12 +78,6 @@ char **device_map = 0;
/* The jump buffer for exiting correctly. */
static jmp_buf env_for_exit;
/* Forward declarations. */
static void get_floppy_disk_name (char *name, int unit);
static void get_ide_disk_name (char *name, int unit);
static void get_scsi_disk_name (char *name, int unit);
static void init_device_map (void);
/* The main entry point into this mess. */
int
grub_stage2 (void)
@ -156,8 +128,9 @@ grub_stage2 (void)
for (i = 0; i < NUM_DISKS; i++)
disks[i].flags = -1;
init_device_map ();
if (! init_device_map (&device_map, device_map_file, floppy_disks))
return 1;
/* Check some invariants. */
assert ((SCRATCHSEG << 4) == SCRATCHADDR);
assert ((BUFFERSEG << 4) == BUFFERADDR);
@ -209,9 +182,7 @@ grub_stage2 (void)
}
/* Release memory. */
for (i = 0; i < NUM_DISKS; i++)
free (device_map[i]);
free (device_map[i]);
restore_device_map (device_map);
device_map = 0;
free (disks);
disks = 0;
@ -222,350 +193,6 @@ grub_stage2 (void)
return status;
}
static void
init_device_map (void)
{
int i;
int num_hd = 0;
FILE *fp = 0;
static void print_error (int no, const char *msg)
{
fprintf (stderr, "%s:%d: error: %s\n", device_map_file, no, msg);
}
assert (device_map == 0);
device_map = malloc (NUM_DISKS * sizeof (char *));
assert (device_map);
/* Probe devices for creating the device map. */
/* Initialize DEVICE_MAP. */
for (i = 0; i < NUM_DISKS; i++)
device_map[i] = 0;
if (device_map_file)
{
/* Open the device map file. */
fp = fopen (device_map_file, "r");
if (fp)
{
/* If there is the device map file, use the data in it instead of
probing devices. */
char buf[1024]; /* XXX */
int line_number = 0;
while (fgets (buf, sizeof (buf), fp))
{
char *ptr, *eptr;
int drive;
int is_floppy = 0;
/* Increase the number of lines. */
line_number++;
/* If the first character is '#', skip it. */
if (buf[0] == '#')
continue;
ptr = buf;
/* Skip leading spaces. */
while (*ptr && isspace (*ptr))
ptr++;
if (*ptr != '(')
{
print_error (line_number, "No open parenthesis found");
stop ();
}
ptr++;
if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd')
{
print_error (line_number, "Bad drive name");
stop ();
}
if (*ptr == 'f')
is_floppy = 1;
ptr += 2;
drive = strtoul (ptr, &ptr, 10);
if (drive < 0 || drive > 8)
{
print_error (line_number, "Bad device number");
stop ();
}
if (! is_floppy)
drive += 0x80;
if (*ptr != ')')
{
print_error (line_number, "No close parenthesis found");
stop ();
}
ptr++;
/* Skip spaces. */
while (*ptr && isspace (*ptr))
ptr++;
if (! *ptr)
{
print_error (line_number, "No filename found");
stop ();
}
/* Terminate the filename. */
eptr = ptr;
while (*eptr && ! isspace (*eptr))
eptr++;
*eptr = 0;
assign_device_name (drive, ptr);
}
fclose (fp);
return;
}
}
/* Print something as the user does not think GRUB has been crashed. */
fprintf (stderr,
"Probing devices to guess BIOS drives. "
"This may take a long time.\n");
if (device_map_file)
/* Try to open the device map file to write the probed data. */
fp = fopen (device_map_file, "w");
/* Floppies. */
if (! no_floppy)
for (i = 0; i < 2; i++)
{
char name[16];
if (i == 1 && ! probe_second_floppy)
break;
get_floppy_disk_name (name, i);
/* In floppies, write the map, whether check_device succeeds
or not, because the user just does not insert floppies. */
if (fp)
fprintf (fp, "(fd%d)\t%s\n", i, name);
if (check_device (name))
assign_device_name (i, name);
}
/* IDE disks. */
for (i = 0; i < 8; i++)
{
char name[16];
get_ide_disk_name (name, i);
if (check_device (name))
{
assign_device_name (num_hd + 0x80, name);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
/* The rest is SCSI disks. */
for (i = 0; i < 16; i++)
{
char name[16];
get_scsi_disk_name (name, i);
if (check_device (name))
{
assign_device_name (num_hd + 0x80, name);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
/* OK, close the device map file if opened. */
if (fp)
fclose (fp);
}
/* These three functions are quite different among OSes. */
static void
get_floppy_disk_name (char *name, int unit)
{
#if defined(__linux__) || defined(__GNU__)
/* GNU/Linux and GNU/Hurd */
sprintf (name, "/dev/fd%d", unit);
#elif defined(__FreeBSD__)
/* FreeBSD */
sprintf (name, "/dev/rfd%d", unit);
#elif defined(__NetBSD__)
/* NetBSD */
/* opendisk() doesn't work for floppies. */
sprintf (name, "/dev/rfd%da", unit);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rfd%dc", unit);
#else
# warning "BIOS floppy drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
static void
get_ide_disk_name (char *name, int unit)
{
#if defined(__linux__)
/* GNU/Linux */
sprintf (name, "/dev/hd%c", unit + 'a');
#elif defined(__GNU__)
/* GNU/Hurd */
sprintf (name, "/dev/hd%d", unit);
#elif defined(__FreeBSD__)
/* FreeBSD */
sprintf (name, "/dev/rwd%d", unit);
#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
/* NetBSD */
char shortname[16];
int fd;
sprintf (shortname, "wd%d", unit);
fd = opendisk (shortname, O_RDONLY, name,
16, /* length of NAME */
0 /* char device */
);
close (fd);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rwd%dc", unit);
#else
# warning "BIOS IDE drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
static void
get_scsi_disk_name (char *name, int unit)
{
#if defined(__linux__)
/* GNU/Linux */
sprintf (name, "/dev/sd%c", unit + 'a');
#elif defined(__GNU__)
/* GNU/Hurd */
sprintf (name, "/dev/sd%d", unit);
#elif defined(__FreeBSD__)
/* FreeBSD */
sprintf (name, "/dev/rda%d", unit);
#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
/* NetBSD */
char shortname[16];
int fd;
sprintf (shortname, "sd%d", unit);
fd = opendisk (shortname, O_RDONLY, name,
16, /* length of NAME */
0 /* char device */
);
close (fd);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rsd%dc", unit);
#else
# warning "BIOS SCSI drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
/* Check if DEVICE can be read. If an error occurs, return zero,
otherwise return non-zero. */
int
check_device (const char *device)
{
char buf[512];
FILE *fp;
fp = fopen (device, "r");
if (! fp)
{
switch (errno)
{
#ifdef ENOMEDIUM
case ENOMEDIUM:
# if 0
/* At the moment, this finds only CDROMs, which can't be
read anyway, so leave it out. Code should be
reactivated if `removable disks' and CDROMs are
supported. */
/* Accept it, it may be inserted. */
return 1;
# endif
break;
#endif /* ENOMEDIUM */
default:
/* Break case and leave. */
break;
}
/* Error opening the device. */
return 0;
}
/* Make sure CD-ROMs don't get assigned a BIOS disk number
before SCSI disks! */
#ifdef __linux__
# ifdef CDROM_GET_CAPABILITY
if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
return 0;
# else /* ! CDROM_GET_CAPABILITY */
/* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
{
struct hd_geometry hdg;
struct stat st;
if (fstat (fileno (fp), &st))
return 0;
/* If it is a block device and isn't a floppy, check if HDIO_GETGEO
succeeds. */
if (S_ISBLK (st.st_mode)
&& MAJOR (st.st_rdev) != FLOPPY_MAJOR
&& ioctl (fileno (fp), HDIO_GETGEO, &hdg))
return 0;
}
# endif /* ! CDROM_GET_CAPABILITY */
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# ifdef CDIOCCLRDEBUG
if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
return 0;
# endif /* CDIOCCLRDEBUG */
#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ */
/* Attempt to read the first sector. */
if (fread (buf, 1, 512, fp) != 512)
{
fclose (fp);
return 0;
}
fclose (fp);
return 1;
}
/* Assign DRIVE to a device name DEVICE. */
void
assign_device_name (int drive, const char *device)
@ -929,48 +556,6 @@ set_attrib (int attr)
#endif
}
/* Get the geometry of a drive DRIVE. If an error occurs, return zero,
otherwise non-zero. */
static int
get_drive_geometry (int drive)
{
struct geometry *geom = &disks[drive];
#if defined(__linux__)
/* Linux */
struct hd_geometry hdg;
if (ioctl (geom->flags, HDIO_GETGEO, &hdg))
return 0;
/* Got the geometry, so save it. */
geom->cylinders = hdg.cylinders;
geom->heads = hdg.heads;
geom->sectors = hdg.sectors;
/* FIXME: Should get the real number of sectors. */
geom->total_sectors = hdg.cylinders * hdg.heads * hdg.sectors;
return 1;
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
/* FreeBSD */
struct disklabel hdg;
if (ioctl (disks[drive].flags, DIOCGDINFO, &hdg))
return 0;
disks[drive].cylinders = hdg.d_ncylinders;
disks[drive].heads = hdg.d_ntracks;
disks[drive].sectors = hdg.d_nsectors;
disks[drive].total_sectors = hdg.d_secperunit;
return 1;
#else
# warning "In your operating system, automatic detection of geometries \
will not be performed."
return 0;
#endif
}
/* Low-level disk I/O. Our stubbed version just returns a file
descriptor, not the actual geometry. */
int
@ -1027,32 +612,7 @@ get_diskinfo (int drive, struct geometry *geometry)
}
if (disks[drive].flags != -1)
{
if (! get_drive_geometry (drive))
{
/* Set some arbitrary defaults. */
if (drive & 0x80)
{
/* Hard drive. */
disks[drive].cylinders = DEFAULT_HD_CYLINDERS;
disks[drive].heads = DEFAULT_HD_HEADS;
disks[drive].sectors = DEFAULT_HD_SECTORS;
disks[drive].total_sectors = (DEFAULT_HD_CYLINDERS
* DEFAULT_HD_HEADS
* DEFAULT_HD_SECTORS);
}
else
{
/* Floppy. */
disks[drive].cylinders = DEFAULT_FD_CYLINDERS;
disks[drive].heads = DEFAULT_FD_HEADS;
disks[drive].sectors = DEFAULT_FD_SECTORS;
disks[drive].total_sectors = (DEFAULT_FD_CYLINDERS
* DEFAULT_FD_HEADS
* DEFAULT_FD_SECTORS);
}
}
}
get_drive_geometry (&disks[drive], device_map, drive);
}
if (disks[drive].flags == -1)

View file

@ -37,8 +37,7 @@ int use_config_file = 1;
int use_curses = 1;
int verbose = 0;
int read_only = 0;
int no_floppy = 0;
int probe_second_floppy = 0;
int floppy_disks = 1;
char *device_map_file = 0;
static int default_boot_drive;
static int default_install_partition;
@ -203,11 +202,11 @@ main (int argc, char **argv)
break;
case OPT_NO_FLOPPY:
no_floppy = 1;
floppy_disks = 0;
break;
case OPT_PROBE_SECOND_FLOPPY:
probe_second_floppy = 1;
floppy_disks = 2;
break;
case OPT_DEVICE_MAP:

View file

@ -1,3 +1,6 @@
noinst_LIBRARIES = libcommon.a
libcommon_a_SOURCES = getopt.c getopt1.c getopt.h
AM_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/stage2 \
-I$(top_srcdir)/stage1
libcommon_a_SOURCES = getopt.c getopt1.c getopt.h device.c device.h

View file

@ -89,7 +89,11 @@ install_sh = @install_sh@
noinst_LIBRARIES = libcommon.a
libcommon_a_SOURCES = getopt.c getopt1.c getopt.h
AM_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/stage2 \
-I$(top_srcdir)/stage1
libcommon_a_SOURCES = getopt.c getopt1.c getopt.h device.c device.h
subdir = lib
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = ../config.h
@ -103,7 +107,7 @@ LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
libcommon_a_AR = $(AR) cru
libcommon_a_LIBADD =
am_libcommon_a_OBJECTS = getopt.o getopt1.o
am_libcommon_a_OBJECTS = getopt.o getopt1.o device.o
libcommon_a_OBJECTS = $(am_libcommon_a_OBJECTS)
AR = ar
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@ -112,7 +116,8 @@ CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
DIST_SOURCES = $(libcommon_a_SOURCES)
depcomp = $(SHELL) $(top_srcdir)/depcomp
DEP_FILES = @AMDEP@ $(DEPDIR)/getopt.Po $(DEPDIR)/getopt1.Po
DEP_FILES = @AMDEP@ $(DEPDIR)/device.Po $(DEPDIR)/getopt.Po \
$(DEPDIR)/getopt1.Po
DIST_COMMON = Makefile.am Makefile.in
@ -190,6 +195,7 @@ distclean-tags:
maintainer-clean-tags:
@AMDEP@include $(DEPDIR)/device.Po
@AMDEP@include $(DEPDIR)/getopt.Po
@AMDEP@include $(DEPDIR)/getopt1.Po

509
lib/device.c Normal file
View file

@ -0,0 +1,509 @@
/* device.c - Some helper functions for OS devices and BIOS drives */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef __linux__
# include <sys/ioctl.h> /* ioctl */
# include <linux/hdreg.h> /* HDIO_GETGEO */
# include <linux/major.h> /* FLOPPY_MAJOR */
# include <linux/kdev_t.h> /* MAJOR */
# include <linux/cdrom.h> /* CDROM_GET_CAPABILITY */
# include <linux/fs.h> /* BLKGETSIZE */
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# include <sys/ioctl.h> /* ioctl */
# include <sys/disklabel.h>
# include <sys/cdio.h> /* CDIOCCLRDEBUG */
#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ */
#ifdef HAVE_OPENDISK
# include <util.h>
#endif /* HAVE_OPENDISK */
#define WITHOUT_LIBC_STUBS 1
#include <shared.h>
#include <device.h>
/* Get the geometry of a drive DRIVE. */
void
get_drive_geometry (struct geometry *geom, char **map, int drive)
{
int fd;
fd = open (map[drive], O_RDONLY);
assert (fd >= 0);
#if defined(__linux__)
/* Linux */
{
struct hd_geometry hdg;
unsigned long nr;
if (ioctl (fd, HDIO_GETGEO, &hdg))
goto fail;
if (ioctl (fd, BLKGETSIZE, &nr))
goto fail;
/* Got the geometry, so save it. */
geom->cylinders = hdg.cylinders;
geom->heads = hdg.heads;
geom->sectors = hdg.sectors;
geom->total_sectors = nr;
close (fd);
return;
}
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
/* FreeBSD, NetBSD or OpenBSD */
{
struct disklabel hdg;
if (ioctl (disks[drive].flags, DIOCGDINFO, &hdg))
goto fail;
geom->cylinders = hdg.d_ncylinders;
geom->heads = hdg.d_ntracks;
geom->sectors = hdg.d_nsectors;
geom->total_sectors = hdg.d_secperunit;
close (fd);
return;
}
#else
# warning "In your operating system, automatic detection of geometries \
will not be performed."
#endif
fail:
/* Set some arbitrary defaults. */
if (drive & 0x80)
{
/* Hard drive. */
geom->cylinders = DEFAULT_HD_CYLINDERS;
geom->heads = DEFAULT_HD_HEADS;
geom->sectors = DEFAULT_HD_SECTORS;
geom->total_sectors = (DEFAULT_HD_CYLINDERS
* DEFAULT_HD_HEADS
* DEFAULT_HD_SECTORS);
}
else
{
/* Floppy. */
geom->cylinders = DEFAULT_FD_CYLINDERS;
geom->heads = DEFAULT_FD_HEADS;
geom->sectors = DEFAULT_FD_SECTORS;
geom->total_sectors = (DEFAULT_FD_CYLINDERS
* DEFAULT_FD_HEADS
* DEFAULT_FD_SECTORS);
}
close (fd);
}
/* These three functions are quite different among OSes. */
static void
get_floppy_disk_name (char *name, int unit)
{
#if defined(__linux__) || defined(__GNU__)
/* GNU/Linux and GNU/Hurd */
sprintf (name, "/dev/fd%d", unit);
#elif defined(__FreeBSD__)
/* FreeBSD */
sprintf (name, "/dev/rfd%d", unit);
#elif defined(__NetBSD__)
/* NetBSD */
/* opendisk() doesn't work for floppies. */
sprintf (name, "/dev/rfd%da", unit);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rfd%dc", unit);
#else
# warning "BIOS floppy drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
static void
get_ide_disk_name (char *name, int unit)
{
#if defined(__linux__)
/* GNU/Linux */
sprintf (name, "/dev/hd%c", unit + 'a');
#elif defined(__GNU__)
/* GNU/Hurd */
sprintf (name, "/dev/hd%d", unit);
#elif defined(__FreeBSD__)
/* FreeBSD */
sprintf (name, "/dev/rwd%d", unit);
#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
/* NetBSD */
char shortname[16];
int fd;
sprintf (shortname, "wd%d", unit);
fd = opendisk (shortname, O_RDONLY, name,
16, /* length of NAME */
0 /* char device */
);
close (fd);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rwd%dc", unit);
#else
# warning "BIOS IDE drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
static void
get_scsi_disk_name (char *name, int unit)
{
#if defined(__linux__)
/* GNU/Linux */
sprintf (name, "/dev/sd%c", unit + 'a');
#elif defined(__GNU__)
/* GNU/Hurd */
sprintf (name, "/dev/sd%d", unit);
#elif defined(__FreeBSD__)
/* FreeBSD */
sprintf (name, "/dev/rda%d", unit);
#elif defined(__NetBSD__) && defined(HAVE_OPENDISK)
/* NetBSD */
char shortname[16];
int fd;
sprintf (shortname, "sd%d", unit);
fd = opendisk (shortname, O_RDONLY, name,
16, /* length of NAME */
0 /* char device */
);
close (fd);
#elif defined(__OpenBSD__)
/* OpenBSD */
sprintf (name, "/dev/rsd%dc", unit);
#else
# warning "BIOS SCSI drives cannot be guessed in your operating system."
/* Set NAME to a bogus string. */
*name = 0;
#endif
}
/* Check if DEVICE can be read. If an error occurs, return zero,
otherwise return non-zero. */
int
check_device (const char *device)
{
char buf[512];
FILE *fp;
fp = fopen (device, "r");
if (! fp)
{
switch (errno)
{
#ifdef ENOMEDIUM
case ENOMEDIUM:
# if 0
/* At the moment, this finds only CDROMs, which can't be
read anyway, so leave it out. Code should be
reactivated if `removable disks' and CDROMs are
supported. */
/* Accept it, it may be inserted. */
return 1;
# endif
break;
#endif /* ENOMEDIUM */
default:
/* Break case and leave. */
break;
}
/* Error opening the device. */
return 0;
}
/* Make sure CD-ROMs don't get assigned a BIOS disk number
before SCSI disks! */
#ifdef __linux__
# ifdef CDROM_GET_CAPABILITY
if (ioctl (fileno (fp), CDROM_GET_CAPABILITY, 0) >= 0)
return 0;
# else /* ! CDROM_GET_CAPABILITY */
/* Check if DEVICE is a CD-ROM drive by the HDIO_GETGEO ioctl. */
{
struct hd_geometry hdg;
struct stat st;
if (fstat (fileno (fp), &st))
return 0;
/* If it is a block device and isn't a floppy, check if HDIO_GETGEO
succeeds. */
if (S_ISBLK (st.st_mode)
&& MAJOR (st.st_rdev) != FLOPPY_MAJOR
&& ioctl (fileno (fp), HDIO_GETGEO, &hdg))
return 0;
}
# endif /* ! CDROM_GET_CAPABILITY */
#endif /* __linux__ */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# ifdef CDIOCCLRDEBUG
if (ioctl (fileno (fp), CDIOCCLRDEBUG, 0) >= 0)
return 0;
# endif /* CDIOCCLRDEBUG */
#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ */
/* Attempt to read the first sector. */
if (fread (buf, 1, 512, fp) != 512)
{
fclose (fp);
return 0;
}
fclose (fp);
return 1;
}
/* Read mapping information from FP, and write it to MAP. */
static int
read_device_map (FILE *fp, char **map, const char *map_file)
{
static void print_error (int no, const char *msg)
{
fprintf (stderr, "%s:%d: error: %s\n", map_file, no, msg);
}
/* If there is the device map file, use the data in it instead of
probing devices. */
char buf[1024]; /* XXX */
int line_number = 0;
while (fgets (buf, sizeof (buf), fp))
{
char *ptr, *eptr;
int drive;
int is_floppy = 0;
/* Increase the number of lines. */
line_number++;
/* If the first character is '#', skip it. */
if (buf[0] == '#')
continue;
ptr = buf;
/* Skip leading spaces. */
while (*ptr && isspace (*ptr))
ptr++;
if (*ptr != '(')
{
print_error (line_number, "No open parenthesis found");
return 0;
}
ptr++;
if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd')
{
print_error (line_number, "Bad drive name");
return 0;
}
if (*ptr == 'f')
is_floppy = 1;
ptr += 2;
drive = strtoul (ptr, &ptr, 10);
if (drive < 0 || drive > 8)
{
print_error (line_number, "Bad device number");
return 0;
}
if (! is_floppy)
drive += 0x80;
if (*ptr != ')')
{
print_error (line_number, "No close parenthesis found");
return 0;
}
ptr++;
/* Skip spaces. */
while (*ptr && isspace (*ptr))
ptr++;
if (! *ptr)
{
print_error (line_number, "No filename found");
return 0;
}
/* Terminate the filename. */
eptr = ptr;
while (*eptr && ! isspace (*eptr))
eptr++;
*eptr = 0;
map[drive] = strdup (ptr);
assert (map[drive]);
}
return 1;
}
/* Initialize the device map MAP. *MAP will be allocated from the heap
space. If MAP_FILE is not NULL, then read mappings from the file
MAP_FILE if it exists, otherwise, write guessed mappings to the file.
FLOPPY_DISKS is the number of floppy disk drives which will be probed.
If it is zero, don't probe any floppy at all. If it is one, probe one
floppy. If it is two, probe two floppies. And so on. */
int
init_device_map (char ***map, const char *map_file, int floppy_disks)
{
int i;
int num_hd = 0;
FILE *fp = 0;
assert (map);
assert (*map == 0);
*map = malloc (NUM_DISKS * sizeof (char *));
assert (*map);
/* Probe devices for creating the device map. */
/* Initialize DEVICE_MAP. */
for (i = 0; i < NUM_DISKS; i++)
(*map)[i] = 0;
if (map_file)
{
/* Open the device map file. */
fp = fopen (map_file, "r");
if (fp)
{
int ret;
ret = read_device_map (fp, *map, map_file);
fclose (fp);
return ret;
}
}
/* Print something so that the user does not think GRUB has been
crashed. */
fprintf (stderr,
"Probing devices to guess BIOS drives. "
"This may take a long time.\n");
if (map_file)
/* Try to open the device map file to write the probed data. */
fp = fopen (map_file, "w");
/* Floppies. */
for (i = 0; i < floppy_disks; i++)
{
char name[16];
get_floppy_disk_name (name, i);
/* In floppies, write the map, whether check_device succeeds
or not, because the user just does not insert floppies. */
if (fp)
fprintf (fp, "(fd%d)\t%s\n", i, name);
if (check_device (name))
{
(*map)[i] = strdup (name);
assert ((*map)[i]);
}
}
/* IDE disks. */
for (i = 0; i < 8; i++)
{
char name[16];
get_ide_disk_name (name, i);
if (check_device (name))
{
(*map)[num_hd + 0x80] = strdup (name);
assert ((*map)[num_hd + 0x80]);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
/* The rest is SCSI disks. */
for (i = 0; i < 16; i++)
{
char name[16];
get_scsi_disk_name (name, i);
if (check_device (name))
{
(*map)[num_hd + 0x80] = strdup (name);
assert ((*map)[num_hd + 0x80]);
/* If the device map file is opened, write the map. */
if (fp)
fprintf (fp, "(hd%d)\t%s\n", num_hd, name);
num_hd++;
}
}
/* OK, close the device map file if opened. */
if (fp)
fclose (fp);
return 1;
}
/* Restore the memory consumed for MAP. */
void
restore_device_map (char **map)
{
int i;
for (i = 0; i < NUM_DISKS; i++)
if (map[i])
free (map[i]);
free (map);
}

42
lib/device.h Normal file
View file

@ -0,0 +1,42 @@
/* device.h - Define macros and declare prototypes for device.c */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999, 2000 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef DEVICE_MAP_HEADER
#define DEVICE_MAP_HEADER 1
/* The maximum number of BIOS disks. */
#define NUM_DISKS 256
/* Simulated disk sizes. */
#define DEFAULT_FD_CYLINDERS 80
#define DEFAULT_FD_HEADS 2
#define DEFAULT_FD_SECTORS 18
#define DEFAULT_HD_CYLINDERS 620
#define DEFAULT_HD_HEADS 128
#define DEFAULT_HD_SECTORS 63
/* Function prototypes. */
extern void get_drive_geometry (struct geometry *geom, char **map, int drive);
extern int check_device (const char *device);
extern int init_device_map (char ***map, const char *map_file,
int floppy_disks);
extern void restore_device_map (char **map);
#endif /* DEVICE_MAP_HEADER */

View file

@ -440,19 +440,14 @@ extern int use_curses;
extern int verbose;
/* The flag for read-only. */
extern int read_only;
/* If this flag is true, assume that there is no floppy. */
extern int no_floppy;
/* If this flag is true, probe the second floppy drive. */
extern int probe_second_floppy;
/* The number of floppies to be probed. */
extern int floppy_disks;
/* The map between BIOS drives and UNIX device file names. */
extern char **device_map;
/* The filename which stores the information about a device map. */
extern char *device_map_file;
/* The array of geometries. */
extern struct geometry *disks;
/* Check if DEVICE can be read. If an error occurs, return zero,
otherwise return non-zero. */
extern int check_device (const char *device);
/* Assign DRIVE to a device name DEVICE. */
extern void assign_device_name (int drive, const char *device);
#endif