From 8d19545f6be224be4c04f9f63989a1b1e600090d Mon Sep 17 00:00:00 2001 From: okuji Date: Wed, 13 Oct 1999 02:45:01 +0000 Subject: [PATCH] add an experimental version of setup and embed. --- ChangeLog | 15 +++ NEWS | 3 + stage2/Makefile.am | 2 +- stage2/Makefile.in | 4 +- stage2/builtins.c | 274 +++++++++++++++++++++++++++++++++++++++++++++ stage2/char_io.c | 11 +- stage2/shared.h | 1 + 7 files changed, 302 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index cf6bc3912..3cb5958e2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +1999-10-13 OKUJI Yoshinori + + * stage2/char_io.c [!STAGE1_5] (get_cmdline): If C is a newline + or a return, then set LPOS to LLEN and call the function + cl_setcpos. + * stage2/builtins.c (embed_func): New function. + (builtin_embed): New varilable. + (setup_func): New function. + (builtin_setup): New varilable. + (builtin_table): Added a pointer to BUILTIN_EMBED and a pointer + to BUILTIN_SETUP. + + * stage2/Makefile.am (stage2_size.h): ../stage2/stage2 -> + pre_stage2. Reported by Pavel Roskin. + 1999-10-12 OKUJI Yoshinori From Pavel Roskin: diff --git a/NEWS b/NEWS index fa03b99c4..8e9a2e836 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,9 @@ NEWS - list of user-visible changes between releases of GRUB New in 0.5.94: * Stage 1 supports both the LBA mode and the CHS mode. * The NetBSD and OpenBSD boot bug is fixed. +* The more automatic installation command "setup" is added. +* The command "embed" embeds a Stage 1.5 in the sectors after a MBR or + in the "bootloader" area in a FFS partition. New in 0.5.93: * ELF format of FreeBSD kernel is supported. diff --git a/stage2/Makefile.am b/stage2/Makefile.am index f4f60303d..ad922bc13 100644 --- a/stage2/Makefile.am +++ b/stage2/Makefile.am @@ -52,7 +52,7 @@ CLEANFILES = $(nodist_pkgdata_DATA) $(noinst_DATA) $(BUILT_SOURCES) stage2_size.h: pre_stage2 -rm -f stage2_size.h - set dummy `ls -l ../stage2/stage2`; \ + set dummy `ls -l pre_stage2`; \ echo "#define STAGE2_SIZE $$6" > stage2_size.h start_exec_SOURCES = start.S diff --git a/stage2/Makefile.in b/stage2/Makefile.in index 85e1c3ec4..d41af8b95 100644 --- a/stage2/Makefile.in +++ b/stage2/Makefile.in @@ -111,7 +111,6 @@ nodist_pkgdata_DATA = stage2 e2fs_stage1_5 fat_stage1_5 ffs_stage1_5 \ minix_stage1_5 noinst_DATA = pre_stage2 start -CLEANFILES = $(BUILT_SOURCES) noinst_PROGRAMS = pre_stage2.exec start.exec \ e2fs_stage1_5.exec fat_stage1_5.exec \ ffs_stage1_5.exec minix_stage1_5.exec @@ -136,6 +135,7 @@ pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK) @NETBOOT_SUPPORT_TRUE@pre_stage2_exec_LDADD = @NETBOOT_SUPPORT_TRUE@../netboot/libdrivers.a BUILT_SOURCES = stage2_size.h +CLEANFILES = $(nodist_pkgdata_DATA) $(noinst_DATA) $(BUILT_SOURCES) start_exec_SOURCES = start.S start_exec_CFLAGS = $(STAGE2_COMPILE) @@ -1602,7 +1602,7 @@ maintainer-clean-generic clean mostlyclean distclean maintainer-clean stage2_size.h: pre_stage2 -rm -f stage2_size.h - set dummy `ls -l ../stage2/stage2`; \ + set dummy `ls -l pre_stage2`; \ echo "#define STAGE2_SIZE $$6" > stage2_size.h stage2: pre_stage2 start diff --git a/stage2/builtins.c b/stage2/builtins.c index d48e8e562..d9c11ae15 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -20,6 +20,7 @@ */ #include +#include #ifndef GRUB_UTIL # include "apic.h" @@ -404,6 +405,133 @@ static struct builtin builtin_displaymem = " machine is, including all regions of physical RAM installed." }; + +/* embed */ +/* Embed a Stage 1.5 in the first cylinder after MBR or in the + bootloader block in a FFS. */ +static int +embed_func (char *arg, int flags) +{ + char *stage1_5; + char *device; + char *stage1_5_buffer = (char *) RAW_ADDR (0x100000); + int len, size; + int sector; + int i; + + stage1_5 = arg; + device = skip_to (0, stage1_5); + + /* Open a Stage 1.5. */ + if (! grub_open (stage1_5)) + return 1; + + /* Read the whole of the Stage 1.5. */ + len = grub_read (stage1_5_buffer, -1); + if (errnum) + return 1; + + size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE; + + /* Get the device where the Stage 1.5 will be embedded. */ + set_device (device); + if (errnum) + return 1; + + if (current_partition == 0xFFFFFF) + { + /* Embed it after the MBR. */ + + char mbr[SECTOR_SIZE]; + + /* No floppy has MBR. */ + if (! (current_drive & 0x80)) + { + errnum = ERR_DEV_VALUES; + return 1; + } + + /* Read the MBR of CURRENT_DRIVE. */ + if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr)) + return 1; + + /* Sanity check. */ + if (! PC_MBR_CHECK_SIG (mbr)) + { + errnum = ERR_BAD_PART_TABLE; + return 1; + } + + /* Check if the disk can store the Stage 1.5. */ + if (PC_SLICE_START (mbr, 0) - 1 < size) + { + errnum = ERR_DEV_VALUES; + return 1; + } + + sector = 1; + } + else + { + /* Embed it in the bootloader block in the FFS. */ + + /* Open the partition. */ + if (! open_partition ()) + return 1; + + /* Check if the current slice is a BSD slice. */ + if (grub_strcmp (fsys_table[fsys_type].name, "ffs") != 0) + { + errnum = ERR_DEV_VALUES; + return 1; + } + + /* Sanity check. */ + if (size > 14) + { + errnum = ERR_BAD_VERSION; + return 1; + } + + /* XXX: I don't know this is really correct. Someone who is + familiar with BSD should check for this. */ + sector = part_start + 1; +#if 1 + /* FIXME: Disable the embedding in FFS until someone checks if + the code above is correct. */ + errnum = ERR_DEV_VALUES; + return 1; +#endif + } + + /* Now perform the embedding. */ + for (i = 0; i < size; i++) + { + grub_memmove ((char *) SCRATCHADDR, stage1_5_buffer + i * SECTOR_SIZE, + SECTOR_SIZE); + if (biosdisk (BIOSDISK_WRITE, current_drive, &buf_geom, + sector + i * SECTOR_SIZE, 1, SCRATCHSEG)) + { + errnum = ERR_WRITE; + return 1; + } + } + + grub_printf (" %d sectors are embedded.\n", size); + return 0; +} + +static struct builtin builtin_embed = +{ + "embed", + embed_func, + BUILTIN_CMDLINE, + "embed STAGE1_5 DEVICE", + "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE" + " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition." + " Print the number of sectors which STAGE1_5 occupies if successful." +}; + /* fallback */ static int @@ -1375,6 +1503,150 @@ static struct builtin builtin_rootnoverify = " derived from attempting the mount will NOT work correctly." }; + +/* setup */ +static int +setup_func (char *arg, int flags) +{ + /* Point to the string of the installed drive/partition. */ + char *install_ptr; + /* Point to the string of the drive/parition where the GRUB images + reside. */ + char *image_ptr; + int install_drive, install_partition; + char *stage1 = "/boot/grub/stage1"; + char *stage2 = "/boot/grub/stage2"; + char *config_file = "/boot/grub/menu.lst"; + char install_arg[256]; + char buffer[32]; + static void sprint_device (int drive, int partition) + { + grub_sprintf (buffer, "(%cd%d", + (drive & 0x80) ? 'h' : 'f', + drive & ~0x80); + if ((partition & 0xFF0000) != 0xFF0000) + { + char tmp[16]; + grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF); + grub_strncat (buffer, tmp, sizeof (buffer)); + } + if ((partition & 0x00FF00) != 0x00FF00) + { + char tmp[16]; + grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF)); + grub_strncat (buffer, tmp, sizeof (buffer)); + } + grub_strncat (buffer, ")", sizeof (buffer)); + } + + struct stage1_5_map { + char *fsys; + char *name; + }; + + struct stage1_5_map stage1_5_map[] = + { + {"ext2fs", "/boot/grub/e2fs_stage1_5"}, + {"ffs", "/boot/grub/ffs_stage1_5"}, + {"fat", "/boot/grub/fat_stage1_5"}, + {"minix", "/boot/grub/minix_stage1_5"} + }; + + install_ptr = arg; + image_ptr = skip_to (0, install_ptr); + + /* Make sure that INSTALL_PTR is valid. */ + set_device (install_ptr); + if (errnum) + return 1; + + install_drive = current_drive; + install_partition = current_partition; + + /* Mount the drive pointed by IMAGE_PTR. */ + if (*image_ptr) + { + /* If the drive/partition where the images reside is specified, + get the drive and the partition. */ + set_device (image_ptr); + if (errnum) + return 1; + } + else + { + /* If omitted, use SAVED_PARTITION and SAVED_DRIVE. */ + current_partition = saved_partition; + current_drive = saved_drive; + } + + /* Open it. */ + if (! open_device ()) + return 1; + + /* Check for stage1 and stage2. We hardcode the filenames, so + if the user installed GRUB in a uncommon directory, this never + succeed. */ + if (! grub_open (stage1) || ! grub_open (stage2)) + return 1; + + /* If the drive where stage2 resides is a hard disk, try to use a + Stage 1.5. */ + if (current_drive & 0x80) + { + char *fsys = fsys_table[fsys_type].name; + int i; + int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]); + + /* Iterate finding the same filesystem name as FSYS. */ + for (i = 0; i < size; i++) + { + if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0) + { + /* OK, check if the Stage 1.5 exists. */ + if (grub_open (stage1_5_map[i].name)) + { + stage2 = stage1_5_map[i].name; + config_file = stage2; + } + break; + } + } + } + + /* Construct a string that is used by the command "install" as its + arguments. */ + sprint_device (install_drive, install_partition); + grub_sprintf (install_arg, "%s %s%s %s p", + stage1, + (install_drive != current_drive) ? "d " : "", + buffer, + stage2); + + /* Notify what will be run. */ + grub_printf (" Run \"install %s\"\n", install_arg); + + /* Run the command. */ +#if 0 + return install_func (install_arg, flags); +#else + return 0; +#endif +} + +static struct builtin builtin_setup = +{ + "setup", + setup_func, + BUILTIN_CMDLINE, + "setup 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," + " then find the GRUB images in the device IMAGE_DEVICE, otherwise" + " use the current \"root partition\", which can be set by the command" + " \"root\"." +}; + /* testload */ static int @@ -1567,6 +1839,7 @@ struct builtin *builtin_table[] = &builtin_default, &builtin_device, &builtin_displaymem, + &builtin_embed, &builtin_fallback, &builtin_fstest, &builtin_geometry, @@ -1585,6 +1858,7 @@ struct builtin *builtin_table[] = &builtin_read, &builtin_root, &builtin_rootnoverify, + &builtin_setup, &builtin_testload, &builtin_timeout, &builtin_title, diff --git a/stage2/char_io.c b/stage2/char_io.c index dc4c35655..f1be1f026 100644 --- a/stage2/char_io.c +++ b/stage2/char_io.c @@ -590,9 +590,10 @@ get_cmdline (char *prompt, char *cmdline, int maxlen, } } - /* goto part after line here */ - yend = ((llen + plen) / 79) + ystart; - putchar ('\n'); + /* Move the cursor to the end of the command. */ + lpos = llen; + cl_setcpos (); + grub_putchar ('\n'); gotoxy (0, getxy () & 0xff); /* If ECHO_CHAR is NUL, remove the leading spaces. */ @@ -708,7 +709,7 @@ grub_memcmp (const char *s1, const char *s2, int n) } #endif /* ! STAGE1_5 */ -#if 0 +#ifndef STAGE1_5 int grub_strncat (char *s1, const char *s2, int n) { @@ -727,7 +728,7 @@ grub_strncat (char *s1, const char *s2, int n) return 1; } -#endif +#endif /* ! STAGE1_5 */ #ifndef STAGE1_5 int diff --git a/stage2/shared.h b/stage2/shared.h index cc235e057..097a1064c 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -625,6 +625,7 @@ int grub_isspace (int c); int grub_strncat (char *s1, const char *s2, int n); char *grub_memmove (char *to, const char *from, int len); void *grub_memset (void *start, int c, int len); +int grub_strncat (char *s1, const char *s2, int n); char *grub_strstr (const char *s1, const char *s2); int grub_memcmp (const char *s1, const char *s2, int n); int grub_strcmp (const char *s1, const char *s2);