add a workaround for the bug in Linux into the grub shell.

This commit is contained in:
okuji 2000-08-08 16:41:56 +00:00
parent 028049bbd4
commit 7ab4e9c240
9 changed files with 350 additions and 51 deletions

View file

@ -1,3 +1,36 @@
2000-08-09 OKUJI Yoshinori <okuji@gnu.org>
* stage2/builtins.c [GRUB_UTIL]: Include stdio.h.
(embed_func) [GRUB_UTIL && __linux__]: When embedding a Stage
1.5 into a partition, call write_to_partition instead of
biosdisk.
(install_func): Set DEST_PARTITION to the partition where Stage
1 resides.
Set SRC_PART_START to the starting address of the partition
where Stage 2 resides.
(install_func) [GRUB_UTIL]: Set STAGE2_OS_FILE to the file name
of Stage 2 under an OS, if the new option "--stage2" is
specified. Otherwise, set it to null.
If STAGE2_OS_FILE is not null, modify the Stage 2 via the
filesystem serviced by the OS.
(install_func) [GRUB_UTIL && __linux__]: If STAGE2_OS_FILE is
null but the Stage2 resides in a partition, use
write_to_partition.
If DEST_PARTITION is not 0xFFFFFF, use write_to_partition, to
embed Stage 1.
(setup_func) [GRUB_UTIL]: If --stage2 is specified, set
STAGE2_ARG to the string pointing to the option. Otherwise, set
it to null.
(setup_func) [!GRUB_UTIL]: Set STAGE2_ARG to null.
(setup_func): If STAGE2_ARG is not null, add STAGE2_ARG and a
space character into CMD_ARG.
* lib/device.c (_LARGEFILE_SOURCE): Defined.
(_FILE_OFFSET_BITS): Likewise.
[__linux__] (write_to_partition): New function.
* lib/device.h [__linux__] (write_to_partition): Declared.
* util/grub-install.in: Specify the option "--stage2" for the
command "setup".
2000-08-04 Jochen Hoenicke <jochen@gnu.org>
* stage2/fsys_fat.c (fat_superblock): clust_eof_marker added.

8
NEWS
View file

@ -9,6 +9,14 @@ New in 0.5.96 - XXXX-XX-XX:
* Now GRUB is compliant with the Linux/i386 boot protocol version 2.02.
* The network support is updated to Etherboot-4.6.4.
* Symlinks in ReiserFS are supported.
* Add a workaround into the grub shell, so that it works fine even under
Linux 2.4.
* Add a new option `--stage2' into the commands "install" and "setup",
to let the grub shell know what the file name of Stage 2 is under your
operating system. You must specify the option correctly, if you cannot
unmount the partition where GRUB images reside. We'd recommend _not_
using those commands directly, but using the utility "grub-install"
instead, because this is safer.
New in 0.5.95 - 2000-06-27:
* NetBSD ELF kernel support is added. You have to specify the new option

View file

@ -1,5 +1,5 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.020.
.TH GRUB-INSTALL "8" "July 2000" "grub-install (GNU GRUB 0.5.96)" FSF
.TH GRUB-INSTALL "8" "August 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 GRUB "8" "July 2000" "GNU GRUB 0.5.96" FSF
.TH GRUB "8" "August 2000" "GNU GRUB 0.5.96" FSF
.SH NAME
GRUB \- the grub shell
.SH SYNOPSIS

View file

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

View file

@ -18,6 +18,11 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Try to use glibc's transparant LFS support. */
#define _LARGEFILE_SOURCE 1
/* lseek becomes synonymous with lseek64. */
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -30,6 +35,11 @@
#include <errno.h>
#ifdef __linux__
# if !defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
/* Maybe libc doesn't have large file support. */
# include <linux/unistd.h> /* _llseek */
# endif /* (GLIBC < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR < 1)) */
# include <sys/ioctl.h> /* ioctl */
# include <linux/hdreg.h> /* HDIO_GETGEO */
# include <linux/major.h> /* FLOPPY_MAJOR */
@ -508,3 +518,76 @@ restore_device_map (char **map)
free (map);
}
#ifdef __linux__
/* Linux-only function, because Linux has a bug that the disk cache for
a whole disk is not consistent with the one for a partition of the
disk. */
int
write_to_partition (char **map, int drive, int partition,
int sector, int size, const char *buf)
{
char dev[64]; /* XXX */
int fd;
if ((partition & 0x00FF00) != 0x00FF00)
{
/* If the partition is a BSD partition, it is difficult to
obtain the representation in Linux. So don't support that. */
errnum = ERR_DEV_VALUES;
return 1;
}
assert (map[drive] != 0);
sprintf (dev, "%s%d", map[drive], ((partition >> 16) & 0xFF) + 1);
/* Open the partition. */
fd = open (dev, O_RDONLY);
if (fd < 0)
{
errnum = ERR_NO_PART;
return 0;
}
#if defined(__linux__) && (!defined(__GLIBC__) || \
((__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))))
/* Maybe libc doesn't have large file support. */
{
loff_t offset, result;
static int _llseek (uint filedes, ulong hi, ulong lo,
loff_t *res, uint wh);
_syscall5 (int, _llseek, uint, filedes, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
offset = (loff_t) sector * (loff_t) SECTOR_SIZE;
if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
{
errnum = ERR_DEV_VALUES;
return 0;
}
}
#else
{
off_t offset = (off_t) sector * (off_t) SECTOR_SIZE;
if (lseek (fd, offset, SEEK_SET) != offset)
{
errnum = ERR_DEV_VALUES;
return 0;
}
}
#endif
if (write (fd, buf, size * SECTOR_SIZE) != (size * SECTOR_SIZE))
{
close (fd);
errnum = ERR_WRITE;
return 0;
}
sync (); /* Paranoia. */
close (fd);
return 1;
}
#endif /* __linux__ */

View file

@ -39,4 +39,9 @@ extern int init_device_map (char ***map, const char *map_file,
int no_floppies);
extern void restore_device_map (char **map);
#ifdef __linux__
extern int write_to_partition (char **map, int drive, int partition,
int offset, int size, const char *buf);
#endif /* __linux__ */
#endif /* DEVICE_MAP_HEADER */

View file

@ -27,6 +27,7 @@
#endif
#ifdef GRUB_UTIL
# include <stdio.h>
# include <device.h>
#else /* ! GRUB_UTIL */
# include <apic.h>
@ -851,7 +852,6 @@ embed_func (char *arg, int flags)
char *stage1_5_buffer = (char *) RAW_ADDR (0x100000);
int len, size;
int sector;
int i;
stage1_5 = arg;
device = skip_to (0, stage1_5);
@ -931,9 +931,27 @@ embed_func (char *arg, int flags)
buf_track = -1;
/* Now perform the embedding. */
#if defined(GRUB_UTIL) && defined(__linux__)
if (current_partition != 0xFFFFFF)
{
/* If the grub shell is running under Linux and the user wants to
embed a Stage 1.5 into a partition instead of a MBR, use system
calls directly instead of biosdisk, because of the bug in
Linux. *sigh* */
if (! write_to_partition (device_map, current_drive, current_partition,
sector - part_start, size, stage1_5_buffer))
return 1;
}
else
#endif /* GRUB_UTIL && __linux__ */
{
int i;
for (i = 0; i < size; i++)
{
grub_memmove ((char *) SCRATCHADDR, stage1_5_buffer + i * SECTOR_SIZE,
grub_memmove ((char *) SCRATCHADDR,
stage1_5_buffer + i * SECTOR_SIZE,
SECTOR_SIZE);
if (biosdisk (BIOSDISK_WRITE, current_drive, &buf_geom,
sector + i, 1, SCRATCHSEG))
@ -942,6 +960,7 @@ embed_func (char *arg, int flags)
return 1;
}
}
}
grub_printf (" %d sectors are embedded.\n", size);
return 0;
@ -1452,8 +1471,8 @@ install_func (char *arg, int flags)
char *config_filename = stage2_second_buffer + SECTOR_SIZE;
char *dummy = config_filename + SECTOR_SIZE;
int new_drive = 0xFF;
int dest_drive, dest_sector;
int src_drive, src_partition;
int dest_drive, dest_partition, dest_sector;
int src_drive, src_partition, src_part_start;
int i;
struct geometry dest_geom, src_geom;
int saved_sector;
@ -1471,6 +1490,12 @@ install_func (char *arg, int flags)
/* Was the last sector full? */
int last_length = SECTOR_SIZE;
#ifdef GRUB_UTIL
/* If the Stage 2 is in a partition mounted by an OS, this will store
the filename under the OS. */
char *stage2_os_file = 0;
#endif /* GRUB_UTIL */
/* Save the first sector of Stage2 in STAGE2_SECT. */
static void disk_read_savesect_func (int sector, int offset, int length)
{
@ -1522,11 +1547,24 @@ install_func (char *arg, int flags)
}
/* First, check the GNU-style long option. */
if (grub_memcmp ("--force-lba", arg, 11) == 0)
while (1)
{
if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
{
is_force_lba = 1;
arg = skip_to (0, arg);
}
#ifdef GRUB_UTIL
else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
{
stage2_os_file = arg + sizeof ("--stage2=") - 1;
arg = skip_to (0, arg);
nul_terminate (stage2_os_file);
}
#endif /* GRUB_UTIL */
else
break;
}
stage1_file = arg;
dest_dev = skip_to (0, stage1_file);
@ -1568,6 +1606,7 @@ install_func (char *arg, int flags)
/* Store the information for the destination device. */
dest_drive = current_drive;
dest_partition = current_partition;
dest_geom = buf_geom;
dest_sector = part_start;
@ -1612,6 +1651,7 @@ install_func (char *arg, int flags)
src_drive = current_drive;
src_partition = current_partition;
src_part_start = part_start;
src_geom = buf_geom;
if (! new_drive)
@ -1810,11 +1850,59 @@ install_func (char *arg, int flags)
/* Copy the name. */
grub_strcpy (location, real_config_filename);
}
/* Write it to the disk. */
buf_track = -1;
#ifdef GRUB_UTIL
/* In the grub shell, access the Stage 2 via the OS filesystem
service, if possible. */
if (stage2_os_file)
{
FILE *fp;
fp = fopen (stage2_os_file, "r");
if (! fp)
{
errnum = ERR_FILE_NOT_FOUND;
goto fail;
}
if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
{
fclose (fp);
errnum = ERR_BAD_VERSION;
goto fail;
}
if (fwrite ((const void *) SCRATCHADDR, 1, SECTOR_SIZE, fp)
!= SECTOR_SIZE)
{
fclose (fp);
errnum = ERR_WRITE;
goto fail;
}
fclose (fp);
}
else
# ifdef __linux__
/* Avoid the bug in Linux, which makes the disk cache for
the whole disk inconsistent with the one for the partition. */
if (current_partition != 0xFFFFFF)
{
if (! write_to_partition (device_map, current_drive,
current_partition,
saved_sector - part_start,
1,
(const char *) SCRATCHADDR))
goto fail;
}
else
# endif /* __linux__ */
#endif /* GRUB_UTIL */
{
if (biosdisk (BIOSDISK_WRITE, current_drive, &buf_geom,
saved_sector, 1, SCRATCHSEG))
{
@ -1823,11 +1911,59 @@ install_func (char *arg, int flags)
}
}
}
}
/* Clear the cache. */
buf_track = -1;
/* Write the modified first sector of Stage2 to the disk. */
/* Write the modified sectors of Stage2 to the disk. */
#ifdef GRUB_UTIL
if (! is_stage1_5 && stage2_os_file)
{
FILE *fp;
fp = fopen (stage2_os_file, "r");
if (! fp)
{
errnum = ERR_FILE_NOT_FOUND;
goto fail;
}
if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
{
fclose (fp);
errnum = ERR_WRITE;
goto fail;
}
if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
{
fclose (fp);
errnum = ERR_WRITE;
goto fail;
}
fclose (fp);
}
else
# ifdef __linux__
if (src_partition != 0xFFFFFF)
{
if (! write_to_partition (device_map, src_drive, src_partition,
stage2_first_sector - src_part_start,
1, stage2_first_buffer))
goto fail;
if (! write_to_partition (device_map, src_drive, src_partition,
stage2_second_sector - src_part_start,
1, stage2_second_buffer))
goto fail;
}
else
# endif /* __linux__ */
#endif /* GRUB_UTIL */
{
/* The first. */
grub_memmove ((char *) SCRATCHADDR, stage2_first_buffer, SECTOR_SIZE);
if (biosdisk (BIOSDISK_WRITE, src_drive, &src_geom,
stage2_first_sector, 1, SCRATCHSEG))
@ -1836,7 +1972,7 @@ install_func (char *arg, int flags)
goto fail;
}
/* Write the modified second sector of Stage2 to the disk. */
/* The second. */
grub_memmove ((char *) SCRATCHADDR, stage2_second_buffer, SECTOR_SIZE);
if (biosdisk (BIOSDISK_WRITE, src_drive, &src_geom,
stage2_second_sector, 1, SCRATCHSEG))
@ -1844,8 +1980,19 @@ install_func (char *arg, int flags)
errnum = ERR_WRITE;
goto fail;
}
}
/* Write the modified sector of Stage 1 to the disk. */
#if defined(GRUB_UTIL) && defined(__linux__)
if (dest_partition != 0xFFFFFF)
{
if (! write_to_partition (device_map, dest_drive, dest_partition,
0, 1, stage1_buffer))
goto fail;
}
else
#endif /* GRUB_UTIL && __linux__ */
{
grub_memmove ((char *) SCRATCHADDR, stage1_buffer, SECTOR_SIZE);
if (biosdisk (BIOSDISK_WRITE, dest_drive, &dest_geom,
dest_sector, 1, SCRATCHSEG))
@ -1853,6 +2000,7 @@ install_func (char *arg, int flags)
errnum = ERR_WRITE;
goto fail;
}
}
fail:
if (is_open)
@ -1872,7 +2020,7 @@ static struct builtin builtin_install =
"install",
install_func,
BUILTIN_CMDLINE,
"install [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
"install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
"Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2"
" as a Stage 2. If the option `d' is present, the Stage 1 will always"
" look for the disk where STAGE2 was installed, rather than using"
@ -1885,7 +2033,8 @@ static struct builtin builtin_install =
" 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
" patched with the configuration filename REAL_CONFIG_FILE."
" If the option `--force-lba' is specified, disable some sanity checks"
" for LBA mode."
" for LBA mode. If the option `--stage2' is specified, rewrite the Stage"
" 2 via your OS's filesystem instead of the raw device."
};
@ -2729,6 +2878,7 @@ setup_func (char *arg, int flags)
char device[16];
char *buffer = (char *) RAW_ADDR (0x100000);
int is_force_lba = 0;
char *stage2_arg = 0;
static void sprint_device (int drive, int partition)
{
@ -2772,11 +2922,24 @@ setup_func (char *arg, int flags)
tmp_partition = saved_partition;
/* Check if the user specifies --force-lba. */
if (grub_memcmp ("--force-lba", arg, 11) == 0)
while (1)
{
if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
{
is_force_lba = 1;
arg = skip_to (0, arg);
}
#ifdef GRUB_UTIL
else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
{
stage2_arg = arg;
arg = skip_to (0, arg);
nul_terminate (stage2_arg);
}
#endif /* GRUB_UTIL */
else
break;
}
install_ptr = arg;
image_ptr = skip_to (0, install_ptr);
@ -2889,8 +3052,10 @@ setup_func (char *arg, int flags)
#ifdef NO_BUGGY_BIOS_IN_THE_WORLD
/* I prefer this, but... */
grub_sprintf (cmd_arg, "%s%s %s%s %s p %s",
grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s",
is_force_lba? "--force-lba" : "",
stage2_arg? stage2_arg : "",
stage2_arg? " " : "",
stage1,
(installed_drive != image_drive) ? "d " : "",
device,
@ -2901,8 +3066,10 @@ setup_func (char *arg, int flags)
may not expect that your BIOS will pass a booting drive to stage1
correctly. Thus, always specify the option `d', whether
INSTALLED_DRIVE is identical with IMAGE_DRIVE or not. *sigh* */
grub_sprintf (cmd_arg, "%s%s d %s %s p %s",
grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s",
is_force_lba? "--force-lba " : "",
stage2_arg? stage2_arg : "",
stage2_arg? " " : "",
stage1,
device,
stage2,
@ -2932,7 +3099,7 @@ static struct builtin builtin_setup =
"setup",
setup_func,
BUILTIN_CMDLINE,
"setup [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
"setup [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
"Set up the installation of GRUB automatically. This command uses"
" the more flexible command \"install\" in the backend and installs"
" GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified,"
@ -2940,6 +3107,9 @@ static struct builtin builtin_setup =
" use the current \"root device\", which can be set by the command"
" \"root\". If you know that your BIOS should support LBA but GRUB"
" doesn't work in LBA mode, specify the option `--force-lba'."
" If you install GRUB under the grub shell and you cannot unmount the"
" partition where GRUB images reside, specify the option `--stage2'"
" to tell GRUB the file name under your OS."
};

View file

@ -262,7 +262,7 @@ test -x /bin/tempfile && log_file=`tempfile --prefix=grub`
# Now perform the installation.
$grub_shell --batch --device-map=$device_map <<EOF >$log_file
root $root_drive
setup $force_lba $install_drive
setup $force_lba --stage2=$grub_dir/stage2 $install_drive
quit
EOF