From 05581f32338ceb6693ef5c90ff082ebbc776a6f2 Mon Sep 17 00:00:00 2001 From: okuji Date: Tue, 11 Jul 2000 16:13:46 +0000 Subject: [PATCH] segreate os-specific helper functions from asmstub.c. --- ChangeLog | 36 ++++ docs/grub-install.8 | 2 +- docs/mbchk.1 | 2 +- grub/asmstub.c | 454 +-------------------------------------- grub/main.c | 7 +- lib/Makefile.am | 5 +- lib/Makefile.in | 12 +- lib/device.c | 509 ++++++++++++++++++++++++++++++++++++++++++++ lib/device.h | 42 ++++ stage2/shared.h | 9 +- 10 files changed, 614 insertions(+), 464 deletions(-) create mode 100644 lib/device.c create mode 100644 lib/device.h diff --git a/ChangeLog b/ChangeLog index 3c0074fec..99cdede98 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2000-07-12 OKUJI Yoshinori + + 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 * grub/main.c (usage): Enclose the mail address with parentheses diff --git a/docs/grub-install.8 b/docs/grub-install.8 index d50c8e3cd..d5163b755 100644 --- a/docs/grub-install.8 +++ b/docs/grub-install.8 @@ -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 diff --git a/docs/mbchk.1 b/docs/mbchk.1 index e971c358b..8a72c28c1 100644 --- a/docs/mbchk.1 +++ b/docs/mbchk.1 @@ -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 diff --git a/grub/asmstub.c b/grub/asmstub.c index 8d3386f5d..d75adbe30 100644 --- a/grub/asmstub.c +++ b/grub/asmstub.c @@ -42,10 +42,6 @@ int grub_stage2 (void); #ifdef __linux__ # include /* ioctl */ -# include /* HDIO_GETGEO */ -# include /* FLOPPY_MAJOR */ -# include /* MAJOR */ -# include /* CDROM_GET_CAPABILITY */ # if (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)) /* Maybe libc doesn't have large file support. */ # include /* _llseek */ @@ -56,33 +52,16 @@ int grub_stage2 (void); # endif /* ! BLKFLSBUF */ #endif /* __linux__ */ -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) -# include /* ioctl */ -# include -# include /* CDIOCCLRDEBUG */ -#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ */ - -#ifdef HAVE_OPENDISK -# include -#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 +#include /* 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) diff --git a/grub/main.c b/grub/main.c index 4cbb13bae..4018b3eaf 100644 --- a/grub/main.c +++ b/grub/main.c @@ -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: diff --git a/lib/Makefile.am b/lib/Makefile.am index 6a60d065e..645a03f46 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -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 diff --git a/lib/Makefile.in b/lib/Makefile.in index a8e9918ea..beb80b565 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -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 diff --git a/lib/device.c b/lib/device.c new file mode 100644 index 000000000..b2d7cf201 --- /dev/null +++ b/lib/device.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +# include /* ioctl */ +# include /* HDIO_GETGEO */ +# include /* FLOPPY_MAJOR */ +# include /* MAJOR */ +# include /* CDROM_GET_CAPABILITY */ +# include /* BLKGETSIZE */ +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +# include /* ioctl */ +# include +# include /* CDIOCCLRDEBUG */ +#endif /* __FreeBSD__ || __NetBSD__ || __OpenBSD__ */ + +#ifdef HAVE_OPENDISK +# include +#endif /* HAVE_OPENDISK */ + +#define WITHOUT_LIBC_STUBS 1 +#include +#include + +/* 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); +} diff --git a/lib/device.h b/lib/device.h new file mode 100644 index 000000000..7385c60de --- /dev/null +++ b/lib/device.h @@ -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 */ diff --git a/stage2/shared.h b/stage2/shared.h index 2b52e12d0..3cb854846 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -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