[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Fw: "partnew" Command Writes Wrong Ending Cylinder in MPT
From: |
Steve Burtchin |
Subject: |
Fw: "partnew" Command Writes Wrong Ending Cylinder in MPT |
Date: |
Sun, 4 Feb 2007 16:22:15 -0500 |
----- Original Message -----
From: "adrian15" <address@hidden>
To: "Steve Burtchin" <address@hidden>
Sent: Thursday, February 01, 2007 6:30 AM
Subject: Re: "partnew" Command Writes Wrong Ending Cylinder in MPT
> Steve Burtchin escribió:
> >> I can build a SGD cdrom with the changes if you want to and you can try
> >> yourself to see if it works ok or not.
> > That would be ideal!
> See the attached cdrom once in English cdrom press 'c' key and you'll
> get a grub console from which you can run the new command:
>
> partnewbeta
>
> I've also attached the builtins.c file so that you search for the
> partnewbeta string and see what you need to add a new command.
>
> >
> >> About the bug do you think that if we write:
> >>
> >> if (cylinder >= buf_geom.cylinders)
> >> cylinder = buf_geom.cylinders - 1;
> >>
> >> like this:
> >> // cylinders correction
> >> buf_geom.cylinders+=2;
> >> if (cylinder >= buf_geom.cylinders)
> >> cylinder = buf_geom.cylinders - 1;
> >>
> >> we will fix the bug?
> >>
> >> adrian15
> >>
> > That would definitely provide a workaround to the bug on MY COMPUTER
(for
> > the "partnew" command) provided "buf_geom.cylinders" is not used
anywhere
> > else (I don't think that it is, but its value may be). "Fix" is a
stronger
> > word implying that "buf_geom.cylinders" would be assigned the correct
value
> > to begin with. I still have'nt figured out how that gets assigned, or
if
> > its value gets used anywhere else that matters.
>
> > The data in the "buf_geom"
> > structure seems to get passed around quite a bit (eg. the "geometry"
> > function reports 1021 cylinders also [here its the value of
> > "geom.cylinders"], if that matters?).
>
> Do you mean geom.cylinders instead of buf_geom.cylinders ... interesting.
>
> >
> > I suspect the source of the bug was a 'dirty' fix to some earlier bug.
A
> > safer approach might be:
> >
> >
> > int cylinder, head, sector, bufgeomcylinders;
> >
> > bufgeomcylinders = buf_geom.cylinders
> > bufgeomcylinders+=2;
> > if (cylinder >= bufgeomcylinders)
> > cylinder = bufgeomcylinders - 1;
>
> That's the patch that I have applied.
> >
> >
> > leaving the "buf_geom" structure unchanged, and avoiding the potential
of
> > awakening that earlier bug.
>
> I do not agree with you but you may be right so I've applied your patch.
>
> You'll tell me if you have any problem.
>
> adrian15
>
>
----------------------------------------------------------------------------
----
> /* builtins.c - the GRUB builtin commands */
> /*
> * GRUB -- GRand Unified Bootloader
> * Copyright (C) 1999,2000,2001,2002,2003,2004 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 before shared.h, because we can't define
> WITHOUT_LIBC_STUBS here. */
> #ifdef GRUB_UTIL
> # include <stdio.h>
> #endif
>
> #include <shared.h>
> #include <filesys.h>
> #include <term.h>
>
> #ifdef SUPPORT_NETBOOT
> # define GRUB 1
> # include <etherboot.h>
> #endif
>
> #ifdef SUPPORT_SERIAL
> # include <serial.h>
> # include <terminfo.h>
> #endif
>
> #ifdef GRUB_UTIL
> # include <device.h>
> #else /* ! GRUB_UTIL */
> # include <apic.h>
> # include <smp-imps.h>
> #endif /* ! GRUB_UTIL */
>
> #ifdef USE_MD5_PASSWORDS
> # include <md5.h>
> #endif
>
> #define PART_TYPE_NUMBER 18
> #define PART_DESCRIPTION_MAXIMUM 44
>
>
> struct partition_type
> {
> int id;
> char *name;
> };
>
> struct partition_type partition_type_table[PART_TYPE_NUMBER] =
> {
>
>
> { 1 , "FAT12"}, // 1
> { 6 , "FAT16"}, // 2
> { 7 , "HPFS/NTFS"}, // 3
> { 11 , "W95 FAT32"},// 4
> { 12 , "W95 FAT32 (LBA)"},// 5
> { 14 , "W95 FAT16 (LBA)"}, // 6
> { 15 , "W95 Ext'd (LBA)"}, // 7
> {27 , "Hidden W95 FAT32"}, // 8
> {28 , "Hidden W95 FAT32"}, // 9
> {99 , "GNU HURD or Sys"}, // 10
> {129 , "Minix / old Lin"}, // 11
> {130 , "SWAP"}, // 12
> {131 , "Linux"}, // 13
> {134 , "NTFS volume set"}, //14
> {135 , "NTFS volume set"}, //15
> {136 , "Linux plaintext"},//16
> {142 , "Linux LVM"}, //17
> {191 , "Solaris"} //18
>
> };
>
>
>
>
> int partition_string_set (int *part_type, char *string) {
> int count;
> for (count=0;count<(PART_TYPE_NUMBER-1);count++) {
> if (*(part_type)==partition_type_table[count].id)
> {
> grub_sprintf(string,"%s",partition_type_table[count].name);
> return 0;
> }
> }
> return 1;
> }
>
> void set_partition_type (char *temp_string_ptr, int *type) {
> int read_char_number = 0;
> char read_char;
>
> open_device();
> errnum = ERR_NONE; // We do not want that partition error makes memmove
work bad
> grub_sprintf (temp_string_ptr,"%s", fsys_table[fsys_type].name);
> if (fsys_type == NUM_FSYS) // We go to a fixed partition type table
> {
> if (partition_string_set (type, temp_string_ptr))
{grub_sprintf(temp_string_ptr,"Unknown");}
> }
> }
>
>
> void set_partition_os (char *temp_string_ptr, int *type) {
> int read_char_number = 0;
> char read_char;
>
> open_device();
> errnum = ERR_NONE; // We do not want that partition error makes memmove
work bad
>
>
> set_partition_type (temp_string_ptr,type);
> if (!(grub_strcmp(temp_string_ptr,"fat")) ||
(!(grub_strcmp(temp_string_ptr,"HPFS/NTFS")))) {
> grub_sprintf(temp_string_ptr,"WINDOWS");
> } else {
> *temp_string_ptr=0;
> // Distro name code
> if (grub_open("/etc/issue")) {
> errnum = ERR_NONE; // We do not want that partition error makes memmove
work bad
> while ((grub_read(&read_char, 1)) && (grub_strlen(temp_string_ptr) <
(PART_DESCRIPTION_MAXIMUM-1) )) {
> errnum = ERR_NONE; // We do not want that partition error makes memmove
work bad
> if ((isspace (read_char) || (read_char >= ' ' && read_char <= '~')) &&
(read_char != 10)) {
> grub_sprintf(temp_string_ptr,"%s%c",temp_string_ptr,read_char);
> }
> read_char_number++;
> }
> grub_close();
> } else {
> errnum = ERR_NONE; // Force to open a new file
> if (grub_open("/grub/stage1")) {
> grub_close();
> errnum = ERR_NONE;
> grub_sprintf(temp_string_ptr,"%s","/BOOT");
> }}
> }
>
> errnum = ERR_NONE; // Ignore any error. There should not be any.
>
>
>
> }
>
>
> void add_choose_title (void) {
> add_title (&menu_array[menu_level], "$(choose_title)");
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "pause
Nothing to do");
> close_title ((char *) MENU_BUF, &menu_array[menu_level]);
>
> }
>
>
> void add_part_title (void) {
> add_title (&menu_array[menu_level], "N IDE SCSI GRUB HURD TYPE
OS");
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "pause
Nothing to do");
> close_title ((char *) MENU_BUF, &menu_array[menu_level]);
> }
>
>
> void add_part_instructions (int *type, int part) {
> char part_type_str_buffer[15];
> char os_type_str_buffer[50];
> char *part_type_str_ptr=part_type_str_buffer;
>
>
> int bsd_part = (part >> 8) & 0xFF;
> int pc_slice = part >> 16;
>
>
> set_partition_type (part_type_str_ptr,type);
> set_partition_os (os_type_str_buffer,type);
>
>
>
> if (bsd_part == 0xFF)
> {
> add_title (&menu_array[menu_level], "%d hd%c%d sd%c%d (hd%d,%d) hd%ds%d
%s %s",pc_slice+1,'a' + current_drive - 0x80,pc_slice+1,'a' +
current_drive - 0x80,pc_slice+1,current_drive -
0x80,pc_slice,current_drive -
0x80,pc_slice+1,part_type_str_ptr,os_type_str_buffer);
>
>
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_device=(hd%d,%d)",current_drive - 0x80,pc_slice);
> }
> else {
> add_title (&menu_array[menu_level], "%d hd%c%d sd%c%d (hd%d,%d,%c) hd%ds%d
%s %s",pc_slice+1,'a' + current_drive - 0x80,pc_slice+1,'a' +
current_drive - 0x80,pc_slice+1,current_drive - 0x80,pc_slice,bsd_part +
'a',current_drive - 0x80,pc_slice+1,part_type_str_ptr,os_type_str_buffer);
>
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_device=(hd%d,%d,%c)",current_drive - 0x80,pc_slice,bsd_part + 'a');
>
> }
> // Common instructions to partitions and slices
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_hurd_hd=hd%d",current_drive - 0x80);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_hd=hd%d",current_drive - 0x80);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_linux_letter=%c",'a'+current_drive - 0x80);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_lide_hd=hd%c",'a' + current_drive - 0x80);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_lscsi_hd=sd%c",'a' + current_drive - 0x80);
>
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_part=($(out_hurd_hd),%d)",pc_slice);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_lide_part=$(out_lide_hd)%d",(pc_slice+1));
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_lscsi_part=$(out_lscsi_hd)%d",(pc_slice+1));
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_hurd_part=$(out_hurd_hd)s%d",pc_slice+1);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_linux_part=$(out_linux_letter)%d",(pc_slice+1));
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_part_n=%d",pc_slice);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_linux_end=%c%d",'a' + current_drive - 0x80, pc_slice + 1);
> }
>
>
>
>
>
>
>
>
> // Warning Grub logical. 0 means success
> //
> int there_is_a_hard_disk (void) {
> int i,disk_no,j;
> // Check if there's any hard disk before doing anything - Begin
> for (i = 1;i < 2; i++) { for (j = 0; j < 16; j++) {
> struct geometry geom;
> disk_no = (i * 0x80) + j;
> if (! get_diskinfo (disk_no, &geom))
> return 0;
> } }
> return 1; //No hard disk found
>
> }
>
>
> /* The type of kernel loaded. */
> kernel_t kernel_type;
> /* The boot device. */
> static int bootdev;
> /* True when the debug mode is turned on, and false
> when it is turned off. */
> int debug = 0;
> /* The default entry. */
> int default_entry = 0;
> /* The fallback entry. */
> int fallback_entryno;
> int fallback_entries[MAX_FALLBACK_ENTRIES];
> /* The number of current entry. */
> int current_entryno;
> /* graphics file */
> char graphics_file[64];
> /* The address for Multiboot command-line buffer. */
> static char *mb_cmdline;
> /* The password. */
> char *password;
> /* The password type. */
> password_t password_type;
> /* The flag for indicating that the user is authoritative. */
> int auth = 0;
> /* The timeout. */
> int grub_timeout = -1;
> /* Whether to show the menu or not. */
> int show_menu = 1;
> /* The BIOS drive map. */
> static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];
>
> int real_map_func (unsigned long to, unsigned long from) {
> int i;
> /* Search for an empty slot in BIOS_DRIVE_MAP. */
> for (i = 0; i < DRIVE_MAP_SIZE; i++)
> {
> /* Perhaps the user wants to override the map. */
> if ((bios_drive_map[i] & 0xff) == from)
> break;
>
> if (! bios_drive_map[i])
> break;
> }
>
> if (i == DRIVE_MAP_SIZE)
> {
> errnum = ERR_WONT_FIT;
> return 1;
> }
>
> if (to == from)
> /* If TO is equal to FROM, delete the entry. */
> grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i
+ 1],
> sizeof (unsigned short) * (DRIVE_MAP_SIZE - i));
> else
> bios_drive_map[i] = from | (to << 8);
>
> return 0;
>
>
> }
>
>
> /* Prototypes for allowing straightfoward calling of builtins functions
> inside other functions. */
> static int configfile_func (char *arg, int flags);
> static int real_root_func (char *arg, int flags);
> static int set_func (char *arg, int flags);
>
> /* Initialize the data for builtins. */
> void
> init_builtins (void)
> {
> kernel_type = KERNEL_TYPE_NONE;
> /* BSD and chainloading evil hacks! */
> bootdev = set_bootdev (0);
> mb_cmdline = (char *) MB_CMDLINE_BUF;
> }
>
> /* Initialize the data for the configuration file. */
> void
> init_config (void)
> {
> default_entry = 0;
> password = 0;
> fallback_entryno = -1;
> fallback_entries[0] = -1;
> grub_timeout = -1;
> }
>
> void
> configfile_end (void)
> {
> #ifdef GRUB_UTIL
> /* Force to load the configuration file. */
> use_config_file = 1;
> #endif
>
> /* Make sure that the user will not be authoritative. */
> auth = 0;
>
> /* Restart cmain. */
> grub_longjmp (restart_env, 0);
>
> }
>
> /* Check a password for correctness. Returns 0 if password was
> correct, and a value != 0 for error, similarly to strcmp. */
> int
> check_password (char *entered, char* expected, password_t type)
> {
> switch (type)
> {
> case PASSWORD_PLAIN:
> return strcmp (entered, expected);
>
> #ifdef USE_MD5_PASSWORDS
> case PASSWORD_MD5:
> return check_md5_password (entered, expected);
> #endif
> default:
> /* unsupported password type: be secure */
> return 1;
> }
> }
>
> /* Print which sector is read when loading a file. */
> static void
> disk_read_print_func (int sector, int offset, int length)
> {
> grub_printf ("[%d,%d,%d]", sector, offset, length);
> }
>
>
> /* configfile */
> static int
> back_func (char *arg, int flags)
> {
>
> if (menu_level>0)
> { special_menu=0; // Restore special menu to a normal one
> // Go down a level
> menu_level--;
> return 0;
> }
> else
> {
> errnum = ERR_BAD_ARGUMENT; return 1;
> }
>
>
>
> }
>
> static struct builtin builtin_back =
> {
> "back",
> back_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "back FILE",
> "Comes back to previously loaded menu."
> };
>
> void check_int13_handler (int modify_saved_drive) {
> /* Check if we should set the int13 handler. */
> if (bios_drive_map[0] != 0)
> {
> int i;
> if (modify_saved_drive) {
> /* Search for SAVED_DRIVE. */
> for (i = 0; i < DRIVE_MAP_SIZE; i++)
> {
> if (! bios_drive_map[i])
> break;
> else if ((bios_drive_map[i] & 0xFF) == saved_drive)
> {
> /* Exchage SAVED_DRIVE with the mapped drive. */
> saved_drive = (bios_drive_map[i] >> 8) & 0xFF;
> break;
> }
> }
> }
> /* Set the handler. This is somewhat dangerous. */
> set_int13_handler (bios_drive_map);
> }
>
> }
>
> /* boot */
> static int
> boot_func (char *arg, int flags)
> {
> /* Clear the int15 handler if we can boot the kernel successfully.
> This assumes that the boot code never fails only if KERNEL_TYPE is
> not KERNEL_TYPE_NONE. Is this assumption is bad? */
> if (kernel_type != KERNEL_TYPE_NONE)
> unset_int15_handler ();
>
> #ifdef SUPPORT_NETBOOT
> /* Shut down the networking. */
> cleanup_net ();
> #endif
>
> switch (kernel_type)
> {
> case KERNEL_TYPE_FREEBSD:
> case KERNEL_TYPE_NETBSD:
> /* *BSD */
> bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline);
> break;
>
> case KERNEL_TYPE_LINUX:
> /* Linux */
> linux_boot ();
> break;
>
> case KERNEL_TYPE_BIG_LINUX:
> /* Big Linux */
> big_linux_boot ();
> break;
>
> case KERNEL_TYPE_CHAINLOADER:
> /* Chainloader */
>
> /* Check if we should set the int13 handler. */
> check_int13_handler(1); // 1 means that we want the function to
modify the saved drive
>
> gateA20 (0);
> boot_drive = saved_drive;
> chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr);
> break;
>
> case KERNEL_TYPE_MULTIBOOT:
> /* Multiboot */
> multi_boot ((int) entry_addr, (int) &mbi);
> break;
>
> default:
> errnum = ERR_BOOT_COMMAND;
> return 1;
> }
>
> return 0;
> }
>
> static struct builtin builtin_boot =
> {
> "boot",
> boot_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "boot",
> "Boot the OS/chain-loader which has been loaded."
> };
>
>
> /* call */
> static int
> call_func (char *arg, int flags)
> {
>
>
> // NEXT CODE IS EQUIVALENT TO CONFIGFILE command
>
> char *new_config = config_file;
>
> /* Check if the file ARG is present. */
> if (! grub_open (arg))
> return 1;
>
> grub_close ();
>
> if(add_menu ()) return 1;
> close_menu ((char *) MENU_BUF, &menu_array[menu_level]);
>
> // Copy ARG to CONFIG_FILE.
> while ((*new_config++ = *arg++) != 0)
> ;
>
> // menu_array config_file value has to be updated when loading a new file
> memmove(menu_array[menu_level].config_file, // TO
> config_file, // FROM
> 128); //SIZE
>
>
> configfile_end();
> /* Never reach here. */
> return 0;
> }
>
> static struct builtin builtin_call =
> {
> "call",
> call_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "call FILE",
> "Load FILE as the configuration file and return to current execution
when back command is called."
> };
>
>
> /* cat */
> static int
> cat_func (char *arg, int flags)
> {
>
>
> if (cat_is_on) {
> int temporal_count_lines;
> char c;
>
> temporal_count_lines=count_lines; // Fetch value of count_lines
> count_lines=0; // Force cat to count lines even when called from inside a
menu
>
> if (! grub_open (arg))
> return 1;
>
> while (grub_read (&c, 1))
> {
> /* Because running "cat" with a binary file can confuse the
terminal,
> print only some characters as they are. */
> //if (isspace (c) || (c >= ' ' && c <= '~'))
> grub_putchar (c);
> //else
> //grub_putchar ('?');
> }
>
> grub_close ();
> count_lines=temporal_count_lines; // Restore value of count_lines
> }
> return 0;
> }
>
> static struct builtin builtin_cat =
> {
> "cat",
> cat_func,
> BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "cat FILE",
> "Print the contents of the file FILE."
> };
> /* catis [on|off] */
> static int
> catis_func (char *arg, int flags)
> {
> /* If ARG is empty, toggle the flag. */
> if (! *arg)
> cat_is_on = ! cat_is_on;
> else if (grub_memcmp (arg, "on", 2) == 0)
> cat_is_on = 1;
> else if (grub_memcmp (arg, "off", 3) == 0)
> cat_is_on = 0;
> else
> {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> //grub_printf (" Internal pager is now %s\n", cat_is_on ? "on" : "off");
// We do not want to cat anything at all.
> return 0;
> }
>
> static struct builtin builtin_catis =
> {
> "catis",
> catis_func,
> BUILTIN_CMDLINE | BUILTIN_MENU,
> "catis [FLAG]",
> "Toggle cat output mode with no argument. If FLAG is given and its
value"
> " is `on', turn on the mode. If FLAG is `off', turn off the mode."
> };
>
> /* chainloader */
> static int
> chainloader_func (char *arg, int flags)
> {
> int force = 0;
> char *file = arg;
>
> /* If the option `--force' is specified? */
> if (substring ("--force", arg) <= 0)
> {
> force = 1;
> file = skip_to (0, arg);
> }
>
> /* Open the file. */
> if (! grub_open (file))
> {
> kernel_type = KERNEL_TYPE_NONE;
> return 1;
> }
>
> /* Read the first block. */
> if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE)
> {
> grub_close ();
> kernel_type = KERNEL_TYPE_NONE;
>
> /* This below happens, if a file whose size is less than 512 bytes
> is loaded. */
> if (errnum == ERR_NONE)
> errnum = ERR_EXEC_FORMAT;
>
> return 1;
> }
>
> /* If not loading it forcibly, check for the signature. */
> if (! force
> && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET))
> != BOOTSEC_SIGNATURE))
> {
> grub_close ();
> errnum = ERR_EXEC_FORMAT;
> kernel_type = KERNEL_TYPE_NONE;
> return 1;
> }
>
> grub_close ();
> kernel_type = KERNEL_TYPE_CHAINLOADER;
>
> /* XXX: Windows evil hack. For now, only the first five letters are
> checked. */
> if (IS_PC_SLICE_TYPE_FAT (current_slice)
> && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID,
> "MSWIN", 5))
> *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS))
> = part_start;
>
> errnum = ERR_NONE;
>
> return 0;
> }
>
> static struct builtin builtin_chainloader =
> {
> "chainloader",
> chainloader_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "chainloader [--force] FILE",
> "Load the chain-loader FILE. If --force is specified, then load it"
> " forcibly, whether the boot loader signature is present or not."
> };
>
> // let's comment cmp_func - adrian15 - it is not very useful
> /* This function could be used to debug new filesystem code. Put a file
> in the new filesystem and the same file in a well-tested filesystem.
> Then, run "cmp" with the files. If no output is obtained, probably
> the code is good, otherwise investigate what's wrong... */
> /* cmp FILE1 FILE2
> static int
> cmp_func (char *arg, int flags)
> {
> // The filenames.
> char *file1, *file2;
> // The addresses.
> char *addr1, *addr2;
> int i;
> // The size of the file.
> int size;
>
> // Get the filenames from ARG.
> file1 = arg;
> file2 = skip_to (0, arg);
> if (! *file1 || ! *file2)
> {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> // Terminate the filenames for convenience.
> nul_terminate (file1);
> nul_terminate (file2);
>
> // Read the whole data from FILE1.
> addr1 = (char *) RAW_ADDR (0x100000);
> if (! grub_open (file1))
> return 1;
>
> // Get the size.
> size = filemax;
> if (grub_read (addr1, -1) != size)
> {
> grub_close ();
> return 1;
> }
>
> grub_close ();
>
> // Read the whole data from FILE2.
> addr2 = addr1 + size;
> if (! grub_open (file2))
> return 1;
>
> // Check if the size of FILE2 is equal to the one of FILE2.
> if (size != filemax)
> {
> grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n",
> size, file1, filemax, file2);
> grub_close ();
> return 0;
> }
>
> if (! grub_read (addr2, -1))
> {
> grub_close ();
> return 1;
> }
>
> grub_close ();
>
> // Now compare ADDR1 with ADDR2.
> for (i = 0; i < size; i++)
> {
> if (addr1[i] != addr2[i])
> grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n",
> i, (unsigned) addr1[i], file1,
> (unsigned) addr2[i], file2);
> }
>
> return 0;
> }
>
> static struct builtin builtin_cmp =
> {
> "cmp",
> cmp_func,
> BUILTIN_CMDLINE,
> "cmp FILE1 FILE2",
> "Compare the file FILE1 with the FILE2 and inform the different values"
> " if any."
> };
> */
>
> /* color */
> /* Set new colors used for the menu interface. Support two methods to
> specify a color name: a direct integer representation and a symbolic
> color name. An example of the latter is "blink-light-gray/blue". */
> static int
> color_func (char *arg, int flags)
> {
> char *normal;
> char *highlight;
> int new_normal_color;
> int new_highlight_color;
> static char *color_list[16] =
> {
> "black",
> "blue",
> "green",
> "cyan",
> "red",
> "magenta",
> "brown",
> "light-gray",
> "dark-gray",
> "light-blue",
> "light-green",
> "light-cyan",
> "light-red",
> "light-magenta",
> "yellow",
> "white"
> };
>
> auto int color_number (char *str);
>
> /* Convert the color name STR into the magical number. */
> auto int color_number (char *str)
> {
> char *ptr;
> int i;
> int color = 0;
>
> /* Find the separator. */
> for (ptr = str; *ptr && *ptr != '/'; ptr++)
> ;
>
> /* If not found, return -1. */
> if (! *ptr)
> return -1;
>
> /* Terminate the string STR. */
> *ptr++ = 0;
>
> /* If STR contains the prefix "blink-", then set the `blink' bit
> in COLOR. */
> if (substring ("blink-", str) <= 0)
> {
> color = 0x80;
> str += 6;
> }
>
> /* Search for the color name. */
> for (i = 0; i < 16; i++)
> if (grub_strcmp (color_list[i], str) == 0)
> {
> color |= i;
> break;
> }
>
> if (i == 16)
> return -1;
>
> str = ptr;
> nul_terminate (str);
>
> /* Search for the color name. */
> for (i = 0; i < 8; i++)
> if (grub_strcmp (color_list[i], str) == 0)
> {
> color |= i << 4;
> break;
> }
>
> if (i == 8)
> return -1;
>
> return color;
> }
>
> normal = arg;
> highlight = skip_to (0, arg);
>
> new_normal_color = color_number (normal);
> if (new_normal_color < 0 && ! safe_parse_maxint (&normal,
&new_normal_color))
> return 1;
>
> /* The second argument is optional, so set highlight_color
> to inverted NORMAL_COLOR. */
> if (! *highlight)
> new_highlight_color = ((new_normal_color >> 4)
> | ((new_normal_color & 0xf) << 4));
> else
> {
> new_highlight_color = color_number (highlight);
> if (new_highlight_color < 0
> && ! safe_parse_maxint (&highlight, &new_highlight_color))
> return 1;
> }
>
> if (current_term->setcolor)
> current_term->setcolor (new_normal_color, new_highlight_color);
>
> return 0;
> }
>
> static struct builtin builtin_color =
> {
> "color",
> color_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "color NORMAL [HIGHLIGHT]",
> "Change the menu colors. The color NORMAL is used for most"
> " lines in the menu, and the color HIGHLIGHT is used to highlight the"
> " line where the cursor points. If you omit HIGHLIGHT, then the"
> " inverted color of NORMAL is used for the highlighted line."
> " The format of a color is \"FG/BG\". FG and BG are symbolic color
names."
> " A symbolic color name must be one of these: black, blue, green,"
> " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
> " light-green, light-cyan, light-red, light-magenta, yellow and white."
> " But only the first eight names can be used for BG. You can prefix"
> " \"blink-\" to FG if you want a blinking foreground color."
> };
>
>
> /* configfile */
> static int
> configfile_func (char *arg, int flags)
> {
> char *new_config = config_file;
>
> /* Check if the file ARG is present. */
> if (! grub_open (arg))
> return 1;
>
> grub_close ();
>
> /* Copy ARG to CONFIG_FILE. */
> while ((*new_config++ = *arg++) != 0)
> ;
>
> // menu_array config_file value has to be updated when loading a new file
> memmove(menu_array[menu_level].config_file, // TO
> config_file, // FROM
> 128); //SIZE
>
>
> configfile_end();
>
> /* Never reach here. */
> return 0;
> }
>
> static struct builtin builtin_configfile =
> {
> "configfile",
> configfile_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "configfile FILE",
> "Load FILE as the configuration file."
> };
>
>
>
>
> /* default */
> static int
> default_func (char *arg, int flags)
> {
> #ifndef SUPPORT_DISKLESS
> if (grub_strcmp (arg, "saved") == 0)
> {
> default_entry = saved_entryno;
> return 0;
> }
> #endif /* SUPPORT_DISKLESS */
>
> if (! safe_parse_maxint (&arg, &default_entry))
> return 1;
>
> return 0;
> }
>
> static struct builtin builtin_default =
> {
> "default",
> default_func,
> BUILTIN_MENU,
> #if 0
> "default [NUM | `saved']",
> "Set the default entry to entry number NUM (if not specified, it is"
> " 0, the first entry) or the entry number saved by savedefault."
> #endif
> };
>
>
> #ifdef GRUB_UTIL
> /* device */
> static int
> device_func (char *arg, int flags)
> {
> char *drive = arg;
> char *device;
>
> /* Get the drive number from DRIVE. */
> if (! set_device (drive))
> return 1;
>
> /* Get the device argument. */
> device = skip_to (0, drive);
>
> /* Terminate DEVICE. */
> nul_terminate (device);
>
> if (! *device || ! check_device (device))
> {
> errnum = ERR_FILE_NOT_FOUND;
> return 1;
> }
>
> assign_device_name (current_drive, device);
>
> return 0;
> }
>
> static struct builtin builtin_device =
> {
> "device",
> device_func,
> BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "device DRIVE DEVICE",
> "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This
command"
> " can be used only in the grub shell."
> };
> #endif /* GRUB_UTIL */
>
>
>
> /* displayapm // Removed displayapm because SGD does not need it.
> static int
> displayapm_func (char *arg, int flags)
> {
> if (mbi.flags & MB_INFO_APM_TABLE)
> {
> grub_printf ("APM BIOS information:\n"
> " Version: 0x%x\n"
> " 32-bit CS: 0x%x\n"
> " Offset: 0x%x\n"
> " 16-bit CS: 0x%x\n"
> " 16-bit DS: 0x%x\n"
> " 32-bit CS length: 0x%x\n"
> " 16-bit CS length: 0x%x\n"
> " 16-bit DS length: 0x%x\n",
> (unsigned) apm_bios_info.version,
> (unsigned) apm_bios_info.cseg,
> apm_bios_info.offset,
> (unsigned) apm_bios_info.cseg_16,
> (unsigned) apm_bios_info.dseg_16,
> (unsigned) apm_bios_info.cseg_len,
> (unsigned) apm_bios_info.cseg_16_len,
> (unsigned) apm_bios_info.dseg_16_len);
> }
> else
> {
> grub_printf ("No APM BIOS found or probe failed\n");
> }
>
> return 0;
> }
>
> static struct builtin builtin_displayapm =
> {
> "displayapm",
> displayapm_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "displayapm",
> "Display APM BIOS information."
> };
> */
>
> /* displaymem // Display mem removed. We do not need it in SGD
> static int
> displaymem_func (char *arg, int flags)
> {
> if (get_eisamemsize () != -1)
> grub_printf (" EISA Memory BIOS Interface is present\n");
> if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0
> || *((int *) SCRATCHADDR) != 0)
> grub_printf (" Address Map BIOS Interface is present\n");
>
> grub_printf (" Lower memory: %uK, "
> "Upper memory (to first chipset hole): %uK\n",
> mbi.mem_lower, mbi.mem_upper);
>
> if (mbi.flags & MB_INFO_MEM_MAP)
> {
> struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
> int end_addr = mbi.mmap_addr + mbi.mmap_length;
>
> grub_printf (" [Address Range Descriptor entries "
> "immediately follow (values are 64-bit)]\n");
> while (end_addr > (int) map)
> {
> char *str;
>
> if (map->Type == MB_ARD_MEMORY)
> str = "Usable RAM";
> else
> str = "Reserved";
> grub_printf (" %s: Base Address: 0x%x X 4GB + 0x%x,\n"
> " Length: 0x%x X 4GB + 0x%x bytes\n",
> str,
> (unsigned long) (map->BaseAddr >> 32),
> (unsigned long) (map->BaseAddr & 0xFFFFFFFF),
> (unsigned long) (map->Length >> 32),
> (unsigned long) (map->Length & 0xFFFFFFFF));
>
> map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size));
> }
> }
>
> return 0;
> }
>
> static struct builtin builtin_displaymem =
> {
> "displaymem",
> displaymem_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "displaymem",
> "Display what GRUB thinks the system address space map of the"
> " machine is, including all regions of physical RAM installed."
> };
> */
>
> /* dd */
> static int
> dd_func (char *arg, int flags)
> {
>
>
>
>
>
> /* Place to put variables - Begin */
> int current_size_read = 0;
> /* Auxiliar variables - Begin */
> int device_sector_number, size_to_read, actual_device_offset;
> char *read_and_write_buffer = (char *) RAW_ADDR (0x100000);
>
> int file_drive, file_partition, file_sector;
> struct geometry file_geom;
> /* Auxiliar variables - End */
> /* Parse variables - Begin */
> char *source_filename, *destination_device, *auxiliar_char_pointer;
> int file_offset, device_offset, size_to_dd;
> /* Parse variables - End */
> /* Place to put variables - End */
>
> auto void restore_file_values(void);
> auto void backup_file_values(void);
> auto int read_the_hard_disk_sector(void);
>
>
> auto void restore_file_values(void)
> {
> current_drive = file_drive ;
> current_partition = file_partition;
> buf_geom = file_geom;
> part_start = file_sector;
> }
>
> auto void backup_file_values(void)
> {
> file_drive = current_drive;
> file_partition = current_partition;
> file_geom = buf_geom;
> file_sector = part_start;
> }
>
> auto int read_the_hard_disk_sector(void)
> {
> /* Save READ FILE variables - Begin*/
> backup_file_values();
> /* Save READ FILE variables - End */
> if (! set_device (destination_device)
> || ! open_partition ()
> || ! devread
(device_sector_number,0,SECTOR_SIZE,read_and_write_buffer))
> return 0 ; // Simulate goto ddfail;
>
> /* Restore READ FILE variables - Begin*/
> restore_file_values();
> /* Restore READ FILE variables - End */
> return 1; // Do not do the goto ddfail;
> }
>
>
> int is_open = 0;
>
> /* Parse arguments - Begin */
> /* Parse filename */
> source_filename = arg;
> arg = skip_to (0,arg);
> nul_terminate(source_filename);
>
> /* Parse device */
> destination_device = arg;
> arg = skip_to (0,arg);
> nul_terminate(destination_device);
> /* Parse file offset */
> auxiliar_char_pointer = arg;
> arg = skip_to (0,arg);
> if ( ! safe_parse_maxint (&auxiliar_char_pointer, &file_offset) ) return
1;
> /* Parse device offset */
> auxiliar_char_pointer = arg;
> arg = skip_to (0,arg);
> if ( ! safe_parse_maxint (&auxiliar_char_pointer, &device_offset) ) return
1;
> /* Parse size */
> auxiliar_char_pointer = arg;
> arg = skip_to (0,arg);
> if ( ! safe_parse_maxint (&auxiliar_char_pointer, &size_to_dd) ) return 1;
> /* Parse arguments - End */
> /* Main algorithm - Begin */
> /* Prepare data - Begin */
> current_size_read = 0;
> /* Prepare data - End */
> is_open = grub_open (source_filename);
> /* Main While - Begin */
>
> // Calculate actual_device_offset
> if (device_offset < SECTOR_SIZE) actual_device_offset = device_offset ;
> else actual_device_offset = device_offset % SECTOR_SIZE;
> while ( current_size_read < size_to_dd ) {
> grub_seek (file_offset+current_size_read);
> device_sector_number = (int)((device_offset + current_size_read) /
SECTOR_SIZE ); // Let's hope that / works the same way as trunc
>
>
> /* Case :0 : 1st part of the sector without changes. 2nd part from the
file. 3rd part without changes. */
> if (size_to_dd < SECTOR_SIZE) {
> if (!(read_the_hard_disk_sector())) goto ddfail;
> size_to_read=size_to_dd;
> auxiliar_char_pointer=read_and_write_buffer+actual_device_offset;
> } else
> {
> /* Case : 1 : 1st part of the sector without changes. 2nd part read from
the file */
> if ((current_size_read==0) && (actual_device_offset)) {
> if (!(read_the_hard_disk_sector())) goto ddfail;
> size_to_read=SECTOR_SIZE - actual_device_offset;
> auxiliar_char_pointer=read_and_write_buffer+actual_device_offset;
> /* Case 2: 1st part of the sector read from the file. 2nd part without
changes. */
> } else {
> auxiliar_char_pointer=read_and_write_buffer;
> if ((current_size_read + SECTOR_SIZE)>size_to_dd) {
> if (!(read_the_hard_disk_sector())) goto ddfail;
> /* Let's contemplate the case device offset: 0 and size_to_dd <
SECTOR_SIZE */
> if (!(actual_device_offset)) size_to_read = size_to_dd;
> else size_to_read=actual_device_offset;
> /* Case 3: All the sector read from the file */
> } else {
> /* NO NEED TO READ THE HARD DISK SECTOR FIRST */
> size_to_read=SECTOR_SIZE;
> }
> }
> }
>
> /* Read from file - Begin */
>
> if ( (! grub_read (auxiliar_char_pointer,size_to_read)==size_to_read)
> || (!is_open)) goto ddfail;
> /* Read from file - End */
> /* Save READ FILE variables - Begin*/
> backup_file_values();
> /* Save READ FILE variables - End */
> /* Write to device - Begin */
> if ( ! set_device (destination_device)
> || ! open_partition ()
> || ! devwrite (device_sector_number,1,read_and_write_buffer))
> goto ddfail;
> /* Restore READ FILE variables - Begin*/
> restore_file_values();
> /* Restore READ FILE variables - End */
> /* Write to device - End */
>
> current_size_read += size_to_read;
> } // End of while
> /* Main While - End */
> /* If there's an error: */
>
>
>
> ddfail:
> if (is_open)
> grub_close ();
>
> disk_read_hook = 0;
>
> #ifndef NO_DECOMPRESSION
> no_decompression = 0;
> #endif
>
> return errnum;
>
>
>
> }
>
> static struct builtin builtin_dd =
> {
> "dd",
> dd_func,
> BUILTIN_CMDLINE,
> "dd SOURCE_FILE DESTINATION_DEVICE FILE_OFFSET DEVICE_OFFSET SIZE",
> "Copy SIZE bytes\n"
> "FROM: SOURCE_FILE beginning at FILE_OFFSET\n"
> "TO: DESTINATION_DEVICE beginning at DEVICE_OFFSET.\n"
> };
>
>
> /* dump FROM TO */
> #ifdef GRUB_UTIL
> static int
> dump_func (char *arg, int flags)
> {
> char *from, *to;
> FILE *fp;
> char c;
>
> from = arg;
> to = skip_to (0, arg);
> if (! *from || ! *to)
> {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> nul_terminate (from);
> nul_terminate (to);
>
> if (! grub_open (from))
> return 1;
>
> fp = fopen (to, "w");
> if (! fp)
> {
> errnum = ERR_WRITE;
> return 1;
> }
>
> while (grub_read (&c, 1))
> if (fputc (c, fp) == EOF)
> {
> errnum = ERR_WRITE;
> fclose (fp);
> return 1;
> }
>
> if (fclose (fp) == EOF)
> {
> errnum = ERR_WRITE;
> return 1;
> }
>
> grub_close ();
> return 0;
> }
>
> static struct builtin builtin_dump =
> {
> "dump",
> dump_func,
> BUILTIN_CMDLINE,
> "dump FROM TO",
> "Dump the contents of the file FROM to the file TO. FROM must be"
> " a GRUB file and TO must be an OS file."
> };
> #endif /* GRUB_UTIL */
>
>
> static char embed_info[32];
> /* 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;
>
> 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);
> grub_close ();
>
> 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];
> char ezbios_check[2*SECTOR_SIZE];
> int i;
>
> /* Open the partition. */
> if (! open_partition ())
> return 1;
>
> /* 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. */
> for (i = 0; i < 4; i++)
> if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size)
> {
> errnum = ERR_NO_DISK_SPACE;
> return 1;
> }
>
> /* Check for EZ-BIOS signature. It should be in the third
> * sector, but due to remapping it can appear in the second, so
> * load and check both.
> */
> if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check))
> return 1;
>
> if (! memcmp (ezbios_check + 3, "AERMH", 5)
> || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5))
> {
> /* The space after the MBR is used by EZ-BIOS which we must
> * not overwrite.
> */
> errnum = ERR_NO_DISK_SPACE;
> return 1;
> }
>
> sector = 1;
> }
> else
> {
> /* Embed it in the bootloader block in the filesystem. */
> int start_sector;
>
> /* Open the partition. */
> if (! open_device ())
> return 1;
>
> /* Check if the current slice supports embedding. */
> if (fsys_table[fsys_type].embed_func == 0
> || ! fsys_table[fsys_type].embed_func (&start_sector, size))
> {
> errnum = ERR_DEV_VALUES;
> return 1;
> }
>
> sector = part_start + start_sector;
> }
>
> /* Clear the cache. */
> buf_track = -1;
>
> /* Now perform the embedding. */
> if (! devwrite (sector - part_start, size, stage1_5_buffer))
> return 1;
>
> grub_printf (" %d sectors are embedded.\n", size);
> grub_sprintf (embed_info, "%d+%d", sector - part_start, 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
> fallback_func (char *arg, int flags)
> {
> int i = 0;
>
> while (*arg)
> {
> int entry;
> int j;
>
> if (! safe_parse_maxint (&arg, &entry))
> return 1;
>
> /* Remove duplications to prevent infinite looping. */
> for (j = 0; j < i; j++)
> if (entry == fallback_entries[j])
> break;
> if (j != i)
> continue;
>
> fallback_entries[i++] = entry;
> if (i == MAX_FALLBACK_ENTRIES)
> break;
>
> arg = skip_to (0, arg);
> }
>
> if (i < MAX_FALLBACK_ENTRIES)
> fallback_entries[i] = -1;
>
> fallback_entryno = (i == 0) ? -1 : 0;
>
> return 0;
> }
>
> static struct builtin builtin_fallback =
> {
> "fallback",
> fallback_func,
> BUILTIN_MENU,
> #if 0
> "fallback NUM...",
> "Go into unattended boot mode: if the default boot entry has any"
> " errors, instead of waiting for the user to do anything, it"
> " immediately starts over using the NUM entry (same numbering as the"
> " `default' command). This obviously won't help if the machine"
> " was rebooted by a kernel that GRUB loaded."
> #endif
> };
>
> /* fexists */
> static int
> fexists_func (char *arg, int flags)
> {
>
> if (! grub_open (arg))
> return 1;
>
> grub_close ();
> return 0;
> }
>
> static struct builtin builtin_fexists =
> {
> "fexists",
> fexists_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "fexists FILE",
> "Gives an error if FILE does not exists for grub."
> "Exists successfully if the file exists."
> "It is useful when used in conjunction with default and fallback
commands."
> };
>
>
> /* find */
> /* Search for the filename ARG in all of partitions. */
> static int
> find_func (char *arg, int flags)
> {
> char *filename = arg;
> unsigned long drive;
> unsigned long tmp_drive = saved_drive;
> unsigned long tmp_partition = saved_partition;
> int got_file = 0;
>
> /* Floppies. */
> for (drive = 0; drive < 8; drive++)
> {
> current_drive = drive;
> current_partition = 0xFFFFFF;
>
> if (open_device ())
> {
> saved_drive = current_drive;
> saved_partition = current_partition;
> if (grub_open (filename))
> {
> grub_close ();
> grub_printf (" (fd%d)\n", drive);
> got_file = 1;
> }
> }
>
> errnum = ERR_NONE;
> }
>
> /* Hard disks. */
> for (drive = 0x80; drive < 0x90; drive++)
> {
> unsigned long part = 0xFFFFFF;
> unsigned long start, len, offset, ext_offset;
> int type, entry;
> char buf[SECTOR_SIZE];
>
> current_drive = drive;
> while (next_partition (drive, 0xFFFFFF, &part, &type,
> &start, &len, &offset, &entry,
> &ext_offset, buf))
> {
> if (type != PC_SLICE_TYPE_NONE
> && ! IS_PC_SLICE_TYPE_BSD (type)
> && ! IS_PC_SLICE_TYPE_EXTENDED (type))
> {
> current_partition = part;
> if (open_device ())
> {
> saved_drive = current_drive;
> saved_partition = current_partition;
> if (grub_open (filename))
> {
> int bsd_part = (part >> 8) & 0xFF;
> int pc_slice = part >> 16;
>
> grub_close ();
>
> if (bsd_part == 0xFF)
> grub_printf (" (hd%d,%d)\n",
> drive - 0x80, pc_slice);
> else
> grub_printf (" (hd%d,%d,%c)\n",
> drive - 0x80, pc_slice, bsd_part + 'a');
>
> got_file = 1;
> }
> }
> }
>
> /* We want to ignore any error here. */
> errnum = ERR_NONE;
> }
>
> /* next_partition always sets ERRNUM in the last call, so clear
> it. */
> errnum = ERR_NONE;
> }
>
> saved_drive = tmp_drive;
> saved_partition = tmp_partition;
>
> if (got_file)
> {
> errnum = ERR_NONE;
> return 0;
> }
>
> errnum = ERR_FILE_NOT_FOUND;
> return 1;
> }
>
> static struct builtin builtin_find =
> {
> "find",
> find_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "find FILENAME",
> "Search for the filename FILENAME in all of partitions and print the
list of"
> " the devices which contain the file."
> };
>
>
> /* selectpart */
> /* Choose partitions from a hard disk with a menu */
> static int
> selectpart_func (char *arg, int flags)
> {
>
>
> unsigned long tmp_drive = saved_drive;
> unsigned long tmp_partition = saved_partition;
>
>
> special_menu = 1; // Force not to read the menu
>
>
> if(add_menu ()) return 1;
>
>
>
> // NEW CODE - BEGIN
> // Add main title
>
> add_choose_title ();
>
> add_part_title ();
>
> set_device (arg); // Saves in current_drive the hard disk
>
>
> unsigned long part = 0xFFFFFF;
> unsigned long start, len, offset, ext_offset;
> int type, entry;
> char buf[SECTOR_SIZE];
>
>
>
> while (next_partition (current_drive, 0xFFFFFF, &part, &type,
> &start, &len, &offset, &entry,
> &ext_offset, buf))
> {
>
>
>
> if (type != PC_SLICE_TYPE_NONE
> && ! IS_PC_SLICE_TYPE_BSD (type)
> && ! IS_PC_SLICE_TYPE_EXTENDED (type))
> {
>
> current_partition = part;
> saved_drive = current_drive;
> saved_partition = current_partition;
>
>
>
> add_part_instructions (&type, part);
>
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "back");
> // Close title
> close_title ((char *) MENU_BUF, &menu_array[menu_level]);
>
> }
>
> // We want to ignore any error here.
> errnum = ERR_NONE;
>
> }
> errnum = ERR_NONE; // We do not want that partition error makes memmove
work bad
> close_menu ((char *) MENU_BUF, &menu_array[menu_level]);
> // NEW CODE - END
>
> // Define the new menu - End
> saved_drive = tmp_drive;
> saved_partition = tmp_partition;
>
>
> configfile_end();
> // Never reach here.
> return 0;
> }
>
> static struct builtin builtin_selectpart =
> {
> "selectpart",
> selectpart_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "selectpart",
> "Choose partitions from a hard disk with a menu."
> };
>
>
> /* selectfile */
> /* Choose partitions from the ones where a file is found with a menu.*/
> static int
> selectfile_func (char *arg, int flags)
> {
> char *filename=arg;
> unsigned long tmp_drive = saved_drive;
> unsigned long tmp_partition = saved_partition;
> int got_file = 0;
>
> int drive; // Aux variables
>
> if (there_is_a_hard_disk ()) { errnum = ERR_FILE_NOT_FOUND; return 1; }
>
>
> special_menu = 1; // Force not to read the menu
>
>
> if(add_menu ()) return 1;
>
>
> // NEW CODE - BEGIN
> // Add main title
> add_choose_title ();
>
> add_part_title ();
>
>
>
> while (*arg) {
>
> filename=arg;
> arg = skip_to (0,arg); // Iterate over filenames
> nul_terminate (filename);
>
> add_title (&menu_array[menu_level], "FILE: %s",filename);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "pause
Nothing to do");
> close_title ((char *) MENU_BUF, &menu_array[menu_level]);
>
>
>
>
>
> for (drive = 0x80; drive < 0x90; drive++) {
>
> unsigned long part = 0xFFFFFF;
> unsigned long start, len, offset, ext_offset;
> int type, entry;
> char buf[SECTOR_SIZE];
>
> current_drive = drive;
> while (next_partition (current_drive, 0xFFFFFF, &part, &type,
> &start, &len, &offset, &entry,
> &ext_offset, buf))
> {
>
>
>
> if (type != PC_SLICE_TYPE_NONE
> && ! IS_PC_SLICE_TYPE_BSD (type)
> && ! IS_PC_SLICE_TYPE_EXTENDED (type))
> {
>
>
>
> current_partition = part;
>
> if (open_device ())
> {
> saved_drive = current_drive;
> saved_partition = current_partition;
>
> if (grub_open (filename)) {
> got_file=1;
> grub_close ();
> add_part_instructions (&type, part);
> // File instruction
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_file=%s",filename);
>
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "back");
> // Close title
> close_title ((char *) MENU_BUF, &menu_array[menu_level]);
> }
>
> }
>
> // We want to ignore any error here.
> errnum = ERR_NONE;
>
> }
> }
> /* next_partition always sets ERRNUM in the last call, so clear
> it. */
> errnum = ERR_NONE;
>
> } // Hard disks
> errnum = ERR_NONE; // We do not want that partition error makes memmove
work bad
>
>
>
>
>
> } // while filename
>
> if (!got_file)
> {
> back_func("",1);
> errnum = ERR_FILE_NOT_FOUND;
> return 1;
> }
>
>
> close_menu ((char *) MENU_BUF, &menu_array[menu_level]);
> // NEW CODE - END
>
> // Define the new menu - End
> saved_drive = tmp_drive;
> saved_partition = tmp_partition;
>
>
> configfile_end();
> // Never reach here.
> return 0;
> }
>
> static struct builtin builtin_selectfile =
> {
> "selectfile",
> selectfile_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "selectfile",
> "Choose partitions from the ones where a file is found with a menu."
> };
>
>
>
>
>
>
>
>
>
>
>
>
> /* findf */
> /* Search for the filename ARG in all of partitions. */
> static int
> findf_func (char *arg, int flags)
> {
> char *filename = arg;
> unsigned long drive;
> unsigned long tmp_drive = saved_drive;
> unsigned long tmp_partition = saved_partition;
> int got_file = 0;
>
> /* Hard disks. */
> for (drive = 0x80; drive < 0x90; drive++)
> {
> unsigned long part = 0xFFFFFF;
> unsigned long start, len, offset, ext_offset;
> int type, entry;
> char buf[SECTOR_SIZE];
> char device_found[14]; // A device should fit into 14 space
> current_drive = drive;
> while (next_partition (drive, 0xFFFFFF, &part, &type,
> &start, &len, &offset, &entry,
> &ext_offset, buf))
> {
> if (type != PC_SLICE_TYPE_NONE
> && ! IS_PC_SLICE_TYPE_BSD (type)
> && ! IS_PC_SLICE_TYPE_EXTENDED (type))
> {
> current_partition = part;
> if (open_device ())
> {
> saved_drive = current_drive;
> saved_partition = current_partition;
> if (grub_open (filename))
> {
> int bsd_part = (part >> 8) & 0xFF;
> int pc_slice = part >> 16;
>
> grub_close ();
> grub_sprintf (device_found,"out_hd=hd%d",drive - 0x80);
> set_func(device_found,1);
> grub_sprintf (device_found,"out_part=(hd%d,%d)",drive - 0x80, pc_slice);
> set_func(device_found,1);
> grub_sprintf (device_found,"out_part_n=%d",pc_slice);
> set_func(device_found,1);
> grub_sprintf (device_found,"out_linux_end=%c%d",'a' + drive - 0x80,
pc_slice + 1);
> set_func(device_found,1);
> grub_sprintf (device_found,"out_linux_letter=%c",'a' + drive - 0x80);
> set_func(device_found,1);
> grub_sprintf (device_found,"out_linux_number=%d", pc_slice + 1);
> set_func(device_found,1);
> if (bsd_part == 0xFF) {
> grub_sprintf (device_found,"out_device=(hd%d,%d)",
> drive - 0x80, pc_slice);
> }
> else
> {
> grub_sprintf (device_found,"out_slice=%c",bsd_part + 'a');
> set_func(device_found,1);
> grub_sprintf (device_found,"out_device=(hd%d,%d,%c)",
> drive - 0x80, pc_slice, bsd_part + 'a');
> }
> set_func(device_found,1);
> got_file = 1;
> }
> }
> }
> if (got_file) break;
> /* We want to ignore any error here. */
> errnum = ERR_NONE;
> }
> if (got_file) break;
> /* next_partition always sets ERRNUM in the last call, so clear
> it. */
> errnum = ERR_NONE;
> }
>
> saved_drive = tmp_drive;
> saved_partition = tmp_partition;
>
> if (got_file)
> {
>
> errnum = ERR_NONE;
> return 0;
> }
>
> errnum = ERR_FILE_NOT_FOUND;
> return 1;
> }
>
> static struct builtin builtin_findf =
> {
> "findf",
> findf_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "findf FILENAME",
> "Search for the filename FILENAME in all of partitions (only hard disks)
and save"
> "into out_hd, out_part, out_slice and out_device variables the drive of
the FILENAME"
>
> };
>
> /* graphics */
> static int
> gfxmenu_func (char *arg, int flags)
> {
> memmove(graphics_file, arg, sizeof graphics_file - 1);
> graphics_file[sizeof graphics_file - 1] = 0;
>
> return 0;
> }
>
> static struct builtin builtin_gfxmenu =
> {
> "gfxmenu",
> gfxmenu_func,
> BUILTIN_MENU | BUILTIN_HELP_LIST,
> "gfxmenu FILE",
> "Use the graphical menu from FILE."
> };
>
> /* graphics */
> static int
> gfxmenuoff_func (char *arg, int flags)
> {
> graphics_file[0] = 0;
> return 0;
> }
>
> static struct builtin builtin_gfxmenuoff =
> {
> "gfxmenuoff",
> gfxmenuoff_func,
> BUILTIN_MENU | BUILTIN_HELP_LIST,
> "gfxmenuoff",
> "Turn off the graphical menu."
> };
>
>
> /* geometry */
> static int
> geometry_func (char *arg, int flags)
> {
> struct geometry geom;
> char *msg;
> char *device = arg;
> #ifdef GRUB_UTIL
> char *ptr;
> #endif
>
> /* Get the device number. */
> set_device (device);
> if (errnum)
> return 1;
>
> /* Check for the geometry. */
> if (get_diskinfo (current_drive, &geom))
> {
> errnum = ERR_NO_DISK;
> return 1;
> }
>
> /* Attempt to read the first sector, because some BIOSes turns out not
> to support LBA even though they set the bit 0 in the support
> bitmap, only after reading something actually. */
> if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
> {
> errnum = ERR_READ;
> return 1;
> }
>
> #ifdef GRUB_UTIL
> ptr = skip_to (0, device);
> if (*ptr)
> {
> char *cylinder, *head, *sector, *total_sector;
> int num_cylinder, num_head, num_sector, num_total_sector;
>
> cylinder = ptr;
> head = skip_to (0, cylinder);
> sector = skip_to (0, head);
> total_sector = skip_to (0, sector);
> if (! safe_parse_maxint (&cylinder, &num_cylinder)
> || ! safe_parse_maxint (&head, &num_head)
> || ! safe_parse_maxint (§or, &num_sector))
> return 1;
>
> disks[current_drive].cylinders = num_cylinder;
> disks[current_drive].heads = num_head;
> disks[current_drive].sectors = num_sector;
>
> if (safe_parse_maxint (&total_sector, &num_total_sector))
> disks[current_drive].total_sectors = num_total_sector;
> else
> disks[current_drive].total_sectors
> = num_cylinder * num_head * num_sector;
> errnum = 0;
>
> geom = disks[current_drive];
> buf_drive = -1;
> }
> #endif /* GRUB_UTIL */
>
> #ifdef GRUB_UTIL
> msg = device_map[current_drive];
> #else
> if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
> msg = "LBA";
> else
> msg = "CHS";
> #endif
>
> grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, "
> "The number of sectors = %d, %s\n",
> current_drive,
> geom.cylinders, geom.heads, geom.sectors,
> geom.total_sectors, msg);
> real_open_partition (1);
>
> return 0;
> }
>
> static struct builtin builtin_geometry =
> {
> "geometry",
> geometry_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "geometry DRIVE [CYLINDER HEAD SECTOR [TOTAL_SECTOR]]",
> "Print the information for a drive DRIVE. In the grub shell, you can"
> " set the geometry of the drive arbitrarily. The number of the
cylinders,"
> " the one of the heads, the one of the sectors and the one of the total"
> " sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR,"
> " respectively. If you omit TOTAL_SECTOR, then it will be calculated
based"
> " on the C/H/S values automatically."
> };
>
> /* halt */
> static int
> halt_func (char *arg, int flags)
> {
> int no_apm;
>
> no_apm = (grub_memcmp (arg, "--no-apm", 8) == 0);
> grub_halt (no_apm);
>
> /* Never reach here. */
> return 1;
> }
>
> static struct builtin builtin_halt =
> {
> "halt",
> halt_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "halt [--no-apm]",
> "Halt your system. If APM is avaiable on it, turn off the power using"
> " the APM BIOS, unless you specify the option `--no-apm'."
> };
>
>
> /* help */
> #define MAX_SHORT_DOC_LEN 39
> #define MAX_LONG_DOC_LEN 66
>
> static int
> help_func (char *arg, int flags)
> {
> int all = 0;
>
> if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0)
> {
> all = 1;
> arg = skip_to (0, arg);
> }
>
> if (! *arg)
> {
> /* Invoked with no argument. Print the list of the short docs. */
> struct builtin **builtin;
> int left = 1;
>
> for (builtin = builtin_table; *builtin != 0; builtin++)
> {
> int len;
> int i;
>
> /* If this cannot be used in the command-line interface,
> skip this. */
> if (! ((*builtin)->flags & BUILTIN_CMDLINE))
> continue;
>
> /* If this doesn't need to be listed automatically and "--all"
> is not specified, skip this. */
> if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST))
> continue;
>
> len = grub_strlen ((*builtin)->short_doc);
> /* If the length of SHORT_DOC is too long, truncate it. */
> if (len > MAX_SHORT_DOC_LEN - 1)
> len = MAX_SHORT_DOC_LEN - 1;
>
> for (i = 0; i < len; i++)
> grub_putchar ((*builtin)->short_doc[i]);
>
> for (; i < MAX_SHORT_DOC_LEN; i++)
> grub_putchar (' ');
>
> if (! left)
> grub_putchar ('\n');
>
> left = ! left;
> }
>
> /* If the last entry was at the left column, no newline was printed
> at the end. */
> if (! left)
> grub_putchar ('\n');
> }
> else
> {
> /* Invoked with one or more patterns. */
> do
> {
> struct builtin **builtin;
> char *next_arg;
>
> /* Get the next argument. */
> next_arg = skip_to (0, arg);
>
> /* Terminate ARG. */
> nul_terminate (arg);
>
> for (builtin = builtin_table; *builtin; builtin++)
> {
> /* Skip this if this is only for the configuration file. */
> if (! ((*builtin)->flags & BUILTIN_CMDLINE))
> continue;
>
> if (substring (arg, (*builtin)->name) < 1)
> {
> char *doc = (*builtin)->long_doc;
>
> /* At first, print the name and the short doc. */
> grub_printf ("%s: %s\n",
> (*builtin)->name, (*builtin)->short_doc);
>
> /* Print the long doc. */
> while (*doc)
> {
> int len = grub_strlen (doc);
> int i;
>
> /* If LEN is too long, fold DOC. */
> if (len > MAX_LONG_DOC_LEN)
> {
> /* Fold this line at the position of a space. */
> for (len = MAX_LONG_DOC_LEN; len > 0; len--)
> if (doc[len - 1] == ' ')
> break;
> }
>
> grub_printf (" ");
> for (i = 0; i < len; i++)
> grub_putchar (*doc++);
> grub_putchar ('\n');
> }
> }
> }
>
> arg = next_arg;
> }
> while (*arg);
> }
>
> return 0;
> }
>
> static struct builtin builtin_help =
> {
> "help",
> help_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "help [--all] [PATTERN ...]",
> "Display helpful information about builtin commands. Not all commands"
> " aren't shown without the option `--all'."
> };
>
>
> /* hide */
> static int
> hide_func (char *arg, int flags)
> {
> if (! set_device (arg))
> return 1;
>
> if (! set_partition_hidden_flag (1))
> return 1;
>
> return 0;
> }
>
> static struct builtin builtin_hide =
> {
> "hide",
> hide_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "hide PARTITION",
> "Hide PARTITION by setting the \"hidden\" bit in"
> " its partition type code."
> };
>
>
> /* initrd */
> static int
> initrd_func (char *arg, int flags)
> {
> switch (kernel_type)
> {
> case KERNEL_TYPE_LINUX:
> case KERNEL_TYPE_BIG_LINUX:
> if (! load_initrd (arg))
> return 1;
> break;
>
> default:
> errnum = ERR_NEED_LX_KERNEL;
> return 1;
> }
>
> return 0;
> }
>
> static struct builtin builtin_initrd =
> {
> "initrd",
> initrd_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "initrd FILE [ARG ...]",
> "Load an initial ramdisk FILE for a Linux format boot image and set the"
> " appropriate parameters in the Linux setup area in memory."
> };
>
>
> /* install */
> static int
> install_func (char *arg, int flags)
> {
> char *stage1_file, *dest_dev, *file, *addr;
> char *stage1_buffer = (char *) RAW_ADDR (0x100000);
> char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
> char *old_sect = stage2_buffer + SECTOR_SIZE;
> char *stage2_first_buffer = old_sect + SECTOR_SIZE;
> char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
> /* XXX: Probably SECTOR_SIZE is reasonable. */
> char *config_filename = stage2_second_buffer + SECTOR_SIZE;
> char *dummy = config_filename + SECTOR_SIZE;
> int new_drive = GRUB_INVALID_DRIVE;
> 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;
> int stage2_first_sector, stage2_second_sector;
> char *ptr;
> int installaddr, installlist;
> /* Point to the location of the name of a configuration file in Stage 2.
*/
> char *config_file_location;
> /* If FILE is a Stage 1.5? */
> int is_stage1_5 = 0;
> /* Must call grub_close? */
> int is_open = 0;
> /* If LBA is forced? */
> int is_force_lba = 0;
> /* 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 */
>
> auto void disk_read_savesect_func (int sector, int offset, int length);
> auto void disk_read_blocklist_func (int sector, int offset, int length);
>
> /* Save the first sector of Stage2 in STAGE2_SECT. */
> auto void disk_read_savesect_func (int sector, int offset, int length)
> {
> if (debug)
> printf ("[%d]", sector);
>
> /* ReiserFS has files which sometimes contain data not aligned
> on sector boundaries. Returning an error is better than
> silently failing. */
> if (offset != 0 || length != SECTOR_SIZE)
> errnum = ERR_UNALIGNED;
>
> saved_sector = sector;
> }
>
> /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
> INSTALLSECT. */
> auto void disk_read_blocklist_func (int sector, int offset, int length)
> {
> if (debug)
> printf("[%d]", sector);
>
> if (offset != 0 || last_length != SECTOR_SIZE)
> {
> /* We found a non-sector-aligned data block. */
> errnum = ERR_UNALIGNED;
> return;
> }
>
> last_length = length;
>
> if (*((unsigned long *) (installlist - 4))
> + *((unsigned short *) installlist) != sector
> || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
> {
> installlist -= 8;
>
> if (*((unsigned long *) (installlist - 8)))
> errnum = ERR_WONT_FIT;
> else
> {
> *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
> *((unsigned long *) (installlist - 4)) = sector;
> }
> }
>
> *((unsigned short *) installlist) += 1;
> installaddr += 512;
> }
>
> /* First, check the GNU-style long option. */
> 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);
> if (*dest_dev == 'd')
> {
> new_drive = 0;
> dest_dev = skip_to (0, dest_dev);
> }
> file = skip_to (0, dest_dev);
> addr = skip_to (0, file);
>
> /* Get the installation address. */
> if (! safe_parse_maxint (&addr, &installaddr))
> {
> /* ADDR is not specified. */
> installaddr = 0;
> ptr = addr;
> errnum = 0;
> }
> else
> ptr = skip_to (0, addr);
>
> #ifndef NO_DECOMPRESSION
> /* Do not decompress Stage 1 or Stage 2. */
> no_decompression = 1;
> #endif
>
> /* Read Stage 1. */
> is_open = grub_open (stage1_file);
> if (! is_open
> || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE)
> goto fail;
>
> /* Read the old sector from DEST_DEV. */
> if (! set_device (dest_dev)
> || ! open_partition ()
> || ! devread (0, 0, SECTOR_SIZE, old_sect))
> goto fail;
>
> /* Store the information for the destination device. */
> dest_drive = current_drive;
> dest_partition = current_partition;
> dest_geom = buf_geom;
> dest_sector = part_start;
>
> /* Copy the possible DOS BPB, 59 bytes at byte offset 3. */
> grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET,
> old_sect + BOOTSEC_BPB_OFFSET,
> BOOTSEC_BPB_LENGTH);
>
> /* If for a hard disk, copy the possible MBR/extended part table. */
> if (dest_drive & 0x80)
> grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC,
> old_sect + STAGE1_WINDOWS_NT_MAGIC,
> STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC);
>
> /* Check for the version and the signature of Stage 1. */
> if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
> || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET))
> != BOOTSEC_SIGNATURE))
> {
> errnum = ERR_BAD_VERSION;
> goto fail;
> }
>
> /* This below is not true any longer. But should we leave this alone?
*/
>
> /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe
> routine. */
> if (! (dest_drive & 0x80)
> && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) ==
0x80
> || stage1_buffer[BOOTSEC_PART_OFFSET] == 0))
> {
> errnum = ERR_BAD_VERSION;
> goto fail;
> }
>
> grub_close ();
>
> /* Open Stage 2. */
> is_open = grub_open (file);
> if (! is_open)
> goto fail;
>
> src_drive = current_drive;
> src_partition = current_partition;
> src_part_start = part_start;
> src_geom = buf_geom;
>
> if (! new_drive)
> new_drive = src_drive;
> else if (src_drive != dest_drive)
> grub_printf ("Warning: the option `d' was not used, but the Stage 1
will"
> " be installed on a\ndifferent drive than the drive where"
> " the Stage 2 resides.\n");
>
> /* Set the boot drive. */
> *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
>
> /* Set the "force LBA" flag. */
> *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba;
>
> /* If DEST_DRIVE is a hard disk, enable the workaround, which is
> for buggy BIOSes which don't pass boot drive correctly. Instead,
> they pass 0x00 or 0x01 even when booted from 0x80. */
> if (dest_drive & BIOS_FLAG_FIXED_DISK)
> {
> if ( *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK))
== 0xeb )
> /* For present version 0.97: Replace the jmp (2 bytes) with
double nop's. */
> *((unsigned short *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK))
> = 0x9090;
> else if ( *((unsigned char *) (stage1_buffer +
STAGE1_BOOT_DRIVE_CHECK)) == 0x80 )
> {
> /* For previous versions 0.94-96: Set the "boot-drive-mask".
> This is the old workaround for buggy BIOSes which do not pass
boot drive correctly.
> The technique was to use 'or dl,0x80', hence testing for
0x80, i.e. or-instruction.
> REM: the old STAGE1_BOOT_DRIVE_MASK equals
STAGE1_BOOT_DRIVE_CHECK + 2. */
> *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK +
2))
> = (dest_drive & BIOS_FLAG_FIXED_DISK);
> }
> // else
> // {
> /* The boot sector is thus older than version 0.94.
> Changing 'goto fail' to a "do nothing" could even make 0.92
and 0.93
> acceptable for the purpose of rescuing their installations.
*/
> // goto fail;
> // }
> // Let's accept 0.92 and 0.93 for rescuing their installations! - adrian15
>
>
> }
>
> /* Read the first sector of Stage 2. */
> disk_read_hook = disk_read_savesect_func;
> if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
> goto fail;
>
> stage2_first_sector = saved_sector;
>
> /* Read the second sector of Stage 2. */
> if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
> goto fail;
>
> stage2_second_sector = saved_sector;
>
> /* Check for the version of Stage 2. */
> if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
> != COMPAT_VERSION)
> {
> errnum = ERR_BAD_VERSION;
> goto fail;
> }
>
> /* Check for the Stage 2 id. */
> if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2)
> is_stage1_5 = 1;
>
> /* If INSTALLADDR is not specified explicitly in the command-line,
> determine it by the Stage 2 id. */
> if (! installaddr)
> {
> if (! is_stage1_5)
> /* Stage 2. */
> installaddr = 0x8000;
> else
> /* Stage 1.5. */
> installaddr = 0x2000;
> }
>
> *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
> = stage2_first_sector;
> *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
> = installaddr;
> *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
> = installaddr >> 4;
>
> i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
> while (*((unsigned long *) i))
> {
> if (i < (int) stage2_first_buffer
> || (*((int *) (i - 4)) & 0x80000000)
> || *((unsigned short *) i) >= 0xA00
> || *((short *) (i + 2)) == 0)
> {
> errnum = ERR_BAD_VERSION;
> goto fail;
> }
>
> *((int *) i) = 0;
> *((int *) (i - 4)) = 0;
> i -= 8;
> }
>
> installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
> installaddr += SECTOR_SIZE;
>
> /* Read the whole of Stage2 except for the first sector. */
> grub_seek (SECTOR_SIZE);
>
> disk_read_hook = disk_read_blocklist_func;
> if (! grub_read (dummy, -1))
> goto fail;
>
> disk_read_hook = 0;
>
> /* Find a string for the configuration filename. */
> config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS;
> while (*(config_file_location++))
> ;
>
> /* Set the "force LBA" flag for Stage2. */
> *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA))
> = is_force_lba;
>
> if (*ptr == 'p')
> {
> *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
> = src_partition;
> if (is_stage1_5)
> {
> /* Reset the device information in FILE if it is a Stage 1.5. */
> unsigned long device = 0xFFFFFFFF;
>
> grub_memmove (config_file_location, (char *) &device,
> sizeof (device));
> }
>
> ptr = skip_to (0, ptr);
> }
>
> if (*ptr)
> {
> grub_strcpy (config_filename, ptr);
> nul_terminate (config_filename);
>
> if (! is_stage1_5)
> /* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION. */
> grub_strcpy (config_file_location, ptr);
> else
> {
> char *real_config;
> unsigned long device;
>
> /* Translate the external device syntax to the internal device
> syntax. */
> if (! (real_config = set_device (ptr)))
> {
> /* The Stage 2 PTR does not contain the device name, so
> use the root device instead. */
> errnum = ERR_NONE;
> current_drive = saved_drive;
> current_partition = saved_partition;
> real_config = ptr;
> }
>
> if (current_drive == src_drive)
> {
> /* If the drive where the Stage 2 resides is the same as
> the one where the Stage 1.5 resides, do not embed the
> drive number. */
> current_drive = GRUB_INVALID_DRIVE;
> }
>
> device = (current_drive << 24) | current_partition;
> grub_memmove (config_file_location, (char *) &device,
> sizeof (device));
> grub_strcpy (config_file_location + sizeof (device),
> real_config);
> }
>
> /* If a Stage 1.5 is used, then we need to modify the Stage2. */
> if (is_stage1_5)
> {
> char *real_config_filename = skip_to (0, ptr);
>
> is_open = grub_open (config_filename);
> if (! is_open)
> goto fail;
>
> /* Skip the first sector. */
> grub_seek (SECTOR_SIZE);
>
> disk_read_hook = disk_read_savesect_func;
> if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
> goto fail;
>
> disk_read_hook = 0;
> grub_close ();
> is_open = 0;
>
> /* Sanity check. */
> if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2)
> {
> errnum = ERR_BAD_VERSION;
> goto fail;
> }
>
> /* Set the "force LBA" flag for Stage2. */
> *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba;
>
> /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2. */
> if (*real_config_filename)
> {
> /* Specified */
> char *location;
>
> /* Find a string for the configuration filename. */
> location = stage2_buffer + STAGE2_VER_STR_OFFS;
> while (*(location++))
> ;
>
> /* 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 (stage2_buffer, 1, SECTOR_SIZE, fp)
> != SECTOR_SIZE)
> {
> fclose (fp);
> errnum = ERR_WRITE;
> goto fail;
> }
>
> fclose (fp);
> }
> else
> #endif /* GRUB_UTIL */
> {
> if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
> goto fail;
> }
> }
> }
>
> /* Clear the cache. */
> buf_track = -1;
>
> /* 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
> #endif /* GRUB_UTIL */
> {
> /* The first. */
> current_drive = src_drive;
> current_partition = src_partition;
>
> if (! open_partition ())
> goto fail;
>
> if (! devwrite (stage2_first_sector - src_part_start, 1,
> stage2_first_buffer))
> goto fail;
>
> if (! devwrite (stage2_second_sector - src_part_start, 1,
> stage2_second_buffer))
> goto fail;
> }
>
> /* Write the modified sector of Stage 1 to the disk. */
> current_drive = dest_drive;
> current_partition = dest_partition;
> if (! open_partition ())
> goto fail;
>
> devwrite (0, 1, stage1_buffer);
>
> fail:
> if (is_open)
> grub_close ();
>
> disk_read_hook = 0;
>
> #ifndef NO_DECOMPRESSION
> no_decompression = 0;
> #endif
>
> return errnum;
> }
>
> static struct builtin builtin_install =
> {
> "install",
> install_func,
> BUILTIN_CMDLINE,
> "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"
> " the booting drive. The Stage 2 will be loaded at address ADDR, which"
> " will be determined automatically if you don't specify it. If"
> " the option `p' or CONFIG_FILE is present, then the first block"
> " of Stage 2 is patched with new values of the partition and name"
> " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
> " this is the name of the true Stage 2) at boot time. If STAGE2 is a
Stage"
> " 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. If the option `--stage2' is specified, rewrite the
Stage"
> " 2 via your OS's filesystem instead of the raw device."
> };
>
>
>
>
> /* kernel */
> static int
> kernel_func (char *arg, int flags)
> {
> int len;
> kernel_t suggested_type = KERNEL_TYPE_NONE;
> unsigned long load_flags = 0;
>
> #ifndef AUTO_LINUX_MEM_OPT
> load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
> #endif
>
> /* Deal with GNU-style long options. */
> while (1)
> {
> /* If the option `--type=TYPE' is specified, convert the string to
> a kernel type. */
> if (grub_memcmp (arg, "--type=", 7) == 0)
> {
> arg += 7;
>
> if (grub_memcmp (arg, "netbsd", 6) == 0)
> suggested_type = KERNEL_TYPE_NETBSD;
> else if (grub_memcmp (arg, "freebsd", 7) == 0)
> suggested_type = KERNEL_TYPE_FREEBSD;
> else if (grub_memcmp (arg, "openbsd", 7) == 0)
> /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's
> point of view. */
> suggested_type = KERNEL_TYPE_NETBSD;
> else if (grub_memcmp (arg, "linux", 5) == 0)
> suggested_type = KERNEL_TYPE_LINUX;
> else if (grub_memcmp (arg, "biglinux", 8) == 0)
> suggested_type = KERNEL_TYPE_BIG_LINUX;
> else if (grub_memcmp (arg, "multiboot", 9) == 0)
> suggested_type = KERNEL_TYPE_MULTIBOOT;
> else
> {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
> }
> /* If the `--no-mem-option' is specified, don't pass a Linux's mem
> option automatically. If the kernel is another type, this flag
> has no effect. */
> else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
> load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
> else
> break;
>
> /* Try the next. */
> arg = skip_to (0, arg);
> }
>
> len = grub_strlen (arg);
>
> /* Reset MB_CMDLINE. */
> mb_cmdline = (char *) MB_CMDLINE_BUF;
> if (len + 1 > MB_CMDLINE_BUFLEN)
> {
> errnum = ERR_WONT_FIT;
> return 1;
> }
>
> /* Copy the command-line to MB_CMDLINE. */
> grub_memmove (mb_cmdline, arg, len + 1);
> kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags);
> if (kernel_type == KERNEL_TYPE_NONE)
> return 1;
>
> mb_cmdline += len + 1;
> return 0;
> }
>
> static struct builtin builtin_kernel =
> {
> "kernel",
> kernel_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
> "Attempt to load the primary boot image from FILE. The rest of the"
> " line is passed verbatim as the \"kernel command line\". Any modules"
> " must be reloaded after using this command. The option --type is used"
> " to suggest what type of kernel to be loaded. TYPE must be either of"
> " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
> " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
> " Linux's mem option automatically."
> };
>
>
> /* lock // Removed lock command because in SGD we do not need it.
> static int
> lock_func (char *arg, int flags)
> {
> if (! auth && password)
> {
> errnum = ERR_PRIVILEGED;
> return 1;
> }
>
> return 0;
> }
>
> static struct builtin builtin_lock =
> {
> "lock",
> lock_func,
> BUILTIN_CMDLINE,
> "lock",
> "Break a command execution unless the user is authenticated."
> };
> */
>
> /* makeactive */
> static int
> makeactive_func (char *arg, int flags)
> {
> if (! make_saved_active ())
> return 1;
>
> return 0;
> }
>
> static struct builtin builtin_makeactive =
> {
> "makeactive",
> makeactive_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "makeactive",
> "Set the active partition on the root disk to GRUB's root device."
> " This command is limited to _primary_ PC partitions on a hard disk."
> };
>
>
>
>
>
>
> /* map */
> /* Map FROM_DRIVE to TO_DRIVE. */
> static int
> map_func (char *arg, int flags)
> {
> char *to_drive;
> char *from_drive;
> unsigned long to, from;
>
> to_drive = arg;
> from_drive = skip_to (0, arg);
>
> /* Get the drive number for TO_DRIVE. */
> set_device (to_drive);
> if (errnum)
> return 1;
> to = current_drive;
>
> /* Get the drive number for FROM_DRIVE. */
> set_device (from_drive);
> if (errnum)
> return 1;
> from = current_drive;
>
> return (real_map_func(to,from));
>
> }
>
> static struct builtin builtin_map =
> {
> "map",
> map_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "map TO_DRIVE FROM_DRIVE",
> "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
> " when you chain-load some operating systems, such as DOS, if such an"
> " OS resides at a non-first drive."
> };
>
>
> #ifdef USE_MD5_PASSWORDS
> /* md5crypt */
> static int
> md5crypt_func (char *arg, int flags)
> {
> char crypted[36];
> char key[32];
> unsigned int seed;
> int i;
> const char *const seedchars =
> "./0123456789ABCDEFGHIJKLMNOPQRST"
> "UVWXYZabcdefghijklmnopqrstuvwxyz";
>
> /* First create a salt. */
>
> /* The magical prefix. */
> grub_memset (crypted, 0, sizeof (crypted));
> grub_memmove (crypted, "$1$", 3);
>
> /* Create the length of a salt. */
> seed = currticks ();
>
> /* Generate a salt. */
> for (i = 0; i < 8 && seed; i++)
> {
> /* FIXME: This should be more random. */
> crypted[3 + i] = seedchars[seed & 0x3f];
> seed >>= 6;
> }
>
> /* A salt must be terminated with `$', if it is less than 8 chars. */
> crypted[3 + i] = '$';
>
> #ifdef DEBUG_MD5CRYPT
> grub_printf ("salt = %s\n", crypted);
> #endif
>
> /* Get a password. */
> grub_memset (key, 0, sizeof (key));
> get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
>
> /* Crypt the key. */
> make_md5_password (key, crypted);
>
> grub_printf ("Encrypted: %s\n", crypted);
> return 0;
> }
>
> static struct builtin builtin_md5crypt =
> {
> "md5crypt",
> md5crypt_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "md5crypt",
> "Generate a password in MD5 format."
> };
> #endif /* USE_MD5_PASSWORDS */
>
>
> /* modaddr */
> static int
> modaddr_func (char *arg, int flags)
> {
> int addr;
>
> switch (kernel_type)
> {
> case KERNEL_TYPE_MULTIBOOT:
> if (safe_parse_maxint(&arg, &addr))
> {
> set_load_addr(addr);
> break;
> }
>
> /* else fallthrough */
>
> default:
> errnum = ERR_NEED_MB_KERNEL;
> return 1;
> }
>
> return 0;
> }
>
> static struct builtin builtin_modaddr =
> {
> "modaddr",
> modaddr_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "modaddr ADDRESS",
> "Set the load address for the next Multiboot module to ADDRESS"
> };
>
>
> /* module */
> static int
> module_func (char *arg, int flags)
> {
> int len = grub_strlen (arg);
>
> switch (kernel_type)
> {
> case KERNEL_TYPE_MULTIBOOT:
> if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF +
MB_CMDLINE_BUFLEN)
> {
> errnum = ERR_WONT_FIT;
> return 1;
> }
> grub_memmove (mb_cmdline, arg, len + 1);
> if (! load_module (arg, mb_cmdline))
> return 1;
> mb_cmdline += len + 1;
> break;
>
> case KERNEL_TYPE_LINUX:
> case KERNEL_TYPE_BIG_LINUX:
> if (! load_initrd (arg))
> return 1;
> break;
>
> default:
> errnum = ERR_NEED_MB_KERNEL;
> return 1;
> }
>
> return 0;
> }
>
> static struct builtin builtin_module =
> {
> "module",
> module_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "module FILE [ARG ...]",
> "Load a boot module FILE for a Multiboot format boot image (no"
> " interpretation of the file contents is made, so users of this"
> " command must know what the kernel in question expects). The"
> " rest of the line is passed as the \"module command line\", like"
> " the `kernel' command."
> };
>
>
> /* modulenounzip */
> static int
> modulenounzip_func (char *arg, int flags)
> {
> int ret;
>
> #ifndef NO_DECOMPRESSION
> no_decompression = 1;
> #endif
>
> ret = module_func (arg, flags);
>
> #ifndef NO_DECOMPRESSION
> no_decompression = 0;
> #endif
>
> return ret;
> }
>
> static struct builtin builtin_modulenounzip =
> {
> "modulenounzip",
> modulenounzip_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "modulenounzip FILE [ARG ...]",
> "The same as `module', except that automatic decompression is"
> " disabled."
> };
>
>
>
> /* partinfo */
> static int
> partinfo_func (char *arg, int flags)
> {
>
> save_fsys_type();
>
> }
>
> static struct builtin builtin_partinfo =
> {
> "partinfo",
> partinfo_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "partinfo",
> "Saves into AUX variable the information about the former rooted (root
(hdX,Y) partition."
> };
>
> /* partnewbeta PART TYPE START LEN */
> static int
> partnewbeta_func (char *arg, int flags)
> {
> int new_type, new_start, new_len;
> int start_cl, start_ch, start_dh;
> int end_cl, end_ch, end_dh;
> int entry;
> char mbr[512];
>
> /* Convert a LBA address to a CHS address in the INT 13 format. */
> auto void lba_to_chs (int lba, int *cl, int *ch, int *dh);
> void lba_to_chs (int lba, int *cl, int *ch, int *dh)
> {
>
> int cylinder, head, sector, bufgeomcylinders; //sburtchin patch adds this
variable
>
> sector = lba % buf_geom.sectors + 1;
> head = (lba / buf_geom.sectors) % buf_geom.heads;
> cylinder = lba / (buf_geom.sectors * buf_geom.heads);
>
> /* sburchin fix add 2 to bufgeomcylinders so that cylinder is calculated
ok. */
>
> bufgeomcylinders = buf_geom.cylinders;
> bufgeomcylinders+=2;
>
> if (cylinder >= bufgeomcylinders)
> cylinder = bufgeomcylinders - 1;
>
> /*
> OLD CODE
> if (cylinder >= buf_geom.cylinders)
> cylinder = buf_geom.cylinders - 1;
> */
>
> *cl = sector | ((cylinder & 0x300) >> 2);
> *ch = cylinder & 0xFF;
> *dh = head;
> }
>
> /* Get the drive and the partition. */
> if (! set_device (arg))
> return 1;
>
> /* The drive must be a hard disk. */
> if (! (current_drive & 0x80))
> {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> /* The partition must a primary partition. */
> if ((current_partition >> 16) > 3
> || (current_partition & 0xFFFF) != 0xFFFF)
> {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> entry = current_partition >> 16;
>
> /* Get the new partition type. */
> arg = skip_to (0, arg);
> if (! safe_parse_maxint (&arg, &new_type))
> return 1;
>
> /* The partition type is unsigned char. */
> if (new_type > 0xFF)
> {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> /* Get the new partition start. */
> arg = skip_to (0, arg);
> if (! safe_parse_maxint (&arg, &new_start))
> return 1;
>
> /* Get the new partition length. */
> arg = skip_to (0, arg);
> if (! safe_parse_maxint (&arg, &new_len))
> return 1;
>
> /* Read the MBR. */
> if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr))
> return 1;
>
> /* Check if the new partition will fit in the disk. */
> if (new_start + new_len > buf_geom.total_sectors)
> {
> errnum = ERR_GEOM;
> return 1;
> }
>
> /* Store the partition information in the MBR. */
> lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
> lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
>
> PC_SLICE_FLAG (mbr, entry) = 0;
> PC_SLICE_HEAD (mbr, entry) = start_dh;
> PC_SLICE_SEC (mbr, entry) = start_cl;
> PC_SLICE_CYL (mbr, entry) = start_ch;
> PC_SLICE_TYPE (mbr, entry) = new_type;
> PC_SLICE_EHEAD (mbr, entry) = end_dh;
> PC_SLICE_ESEC (mbr, entry) = end_cl;
> PC_SLICE_ECYL (mbr, entry) = end_ch;
> PC_SLICE_START (mbr, entry) = new_start;
> PC_SLICE_LENGTH (mbr, entry) = new_len;
>
> /* Make sure that the MBR has a valid signature. */
> PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
>
> /* Write back the MBR to the disk. */
> buf_track = -1;
> if (! rawwrite (current_drive, 0, mbr))
> return 1;
>
> return 0;
> }
>
> static struct builtin builtin_partnewbeta =
> {
> "partnewbeta",
> partnewbeta_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "partnewbeta PART TYPE START LEN",
> "Create a primary partition at the starting address START with the"
> " length LEN, with the type TYPE. START and LEN are in sector units."
> };
>
> /* password
> static int
> password_func (char *arg, int flags)
> {
> int len;
> password_t type = PASSWORD_PLAIN;
>
> #ifdef USE_MD5_PASSWORDS
> if (grub_memcmp (arg, "--md5", 5) == 0)
> {
> type = PASSWORD_MD5;
> arg = skip_to (0, arg);
> }
> #endif
> if (grub_memcmp (arg, "--", 2) == 0)
> {
> type = PASSWORD_UNSUPPORTED;
> arg = skip_to (0, arg);
> }
>
> if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
> {
> // Do password check!
> char entered[32];
>
> // Wipe out any previously entered password
> entered[0] = 0;
> get_cmdline ("Password: ", entered, 31, '*', 0);
>
> nul_terminate (arg);
> if (check_password (entered, arg, type) != 0)
> {
> errnum = ERR_PRIVILEGED;
> return 1;
> }
> }
> else
> {
> len = grub_strlen (arg);
>
> // PASSWORD NUL NUL ...
> if (len + 2 > PASSWORD_BUFLEN)
> {
> errnum = ERR_WONT_FIT;
> return 1;
> }
>
> // Copy the password and clear the rest of the buffer.
> password = (char *) PASSWORD_BUF;
> grub_memmove (password, arg, len);
> grub_memset (password + len, 0, PASSWORD_BUFLEN - len);
> password_type = type;
> }
> return 0;
> }
>
> static struct builtin builtin_password =
> {
> "password",
> password_func,
> BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
> "password [--md5] PASSWD [FILE]",
> "If used in the first section of a menu file, disable all"
> " interactive editing control (menu entry editor and"
> " command line). If the password PASSWD is entered, it loads the"
> " FILE as a new config file and restarts the GRUB Stage 2. If you"
> " omit the argument FILE, then GRUB just unlocks privileged"
> " instructions. You can also use it in the script section, in"
> " which case it will ask for the password, before continueing."
> " The option --md5 tells GRUB that PASSWD is encrypted with"
> " md5crypt."
> };
> */
>
> /* pause */
> static int
> pause_func (char *arg, int flags)
> {
> if (cat_is_on) {
>
> printf("%s\n", arg);
>
> /* If ESC is returned, then abort this entry. */
> if (ASCII_CHAR (getkey ()) == 27)
> return 1;
>
> }
> return 0;
> }
>
> static struct builtin builtin_pause =
> {
> "pause",
> pause_func,
> BUILTIN_MENU | BUILTIN_CMDLINE,
> "pause [MESSAGE ...]",
> "Print MESSAGE, then wait until a key is pressed."
> };
>
>
> #ifdef GRUB_UTIL
> /* quit */
> static int
> quit_func (char *arg, int flags)
> {
> stop ();
>
> /* Never reach here. */
> return 0;
> }
>
> static struct builtin builtin_quit =
> {
> "quit",
> quit_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "quit",
> "Exit from the GRUB shell."
> };
> #endif /* GRUB_UTIL */
>
>
> static int
> read_func (char *arg, int flags)
> {
> int addr;
>
> if (! safe_parse_maxint (&arg, &addr))
> return 1;
>
> grub_printf ("Address 0x%x: Value 0x%x\n",
> addr, *((unsigned *) RAW_ADDR (addr)));
> return 0;
> }
>
> static struct builtin builtin_read =
> {
> "read",
> read_func,
> BUILTIN_CMDLINE,
> "read ADDR",
> "Read a 32-bit value from memory at address ADDR and"
> " display it in hex format."
> };
>
>
> /* reboot */
> static int
> reboot_func (char *arg, int flags)
> {
> grub_reboot ();
>
> /* Never reach here. */
> return 1;
> }
>
> static struct builtin builtin_reboot =
> {
> "reboot",
> reboot_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "reboot",
> "Reboot your system."
> };
>
>
> /* Print the root device information. */
> static void
> print_root_device (void)
> {
> if (saved_drive == NETWORK_DRIVE)
> {
> /* Network drive. */
> grub_printf (" (nd):");
> }
> else if ((cdrom_drive != GRUB_INVALID_DRIVE) &&(saved_drive==cdrom_drive))
> {
> /* cdrom drive */
> grub_printf (" (cd):");
> }
> else if (saved_drive & 0x80)
> {
> /* Hard disk drive. */
> grub_printf (" (hd%d", saved_drive - 0x80);
>
> if ((saved_partition & 0xFF0000) != 0xFF0000)
> grub_printf (",%d", saved_partition >> 16);
>
> if ((saved_partition & 0x00FF00) != 0x00FF00)
> grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a');
>
> grub_printf ("):");
> }
> else
> {
> /* Floppy disk drive. */
> grub_printf (" (fd%d):", saved_drive);
> }
>
> /* Print the filesystem information. */
> current_partition = saved_partition;
> current_drive = saved_drive;
> print_fsys_type ();
> }
>
> static int
> real_root_func (char *arg, int attempt_mount)
> {
> int hdbias = 0;
> char *biasptr;
> char *next;
>
> /* If ARG is empty, just print the current root device. */
> if (! *arg)
> {
> print_root_device ();
> return 0;
> }
>
> /* Call set_device to get the drive and the partition in ARG. */
> next = set_device (arg);
> if (! next)
> return 1;
>
> /* Ignore ERR_FSYS_MOUNT. */
> if (attempt_mount)
> {
> if (! open_device () && errnum != ERR_FSYS_MOUNT)
> return 1;
> }
> else
> {
> /* This is necessary, because the location of a partition table
> must be set appropriately. */
> if (open_partition ())
> {
> set_bootdev (0);
> if (errnum)
> return 1;
> }
> }
>
> /* Clear ERRNUM. */
> errnum = 0;
> saved_partition = current_partition;
> saved_drive = current_drive;
>
> if (attempt_mount)
> {
> /* BSD and chainloading evil hacks !! */
> biasptr = skip_to (0, next);
> safe_parse_maxint (&biasptr, &hdbias);
> errnum = 0;
> bootdev = set_bootdev (hdbias);
> if (errnum)
> return 1;
>
> /* Print the type of the filesystem. */
> print_fsys_type ();
> }
>
> return 0;
> }
>
> static int
> root_func (char *arg, int flags)
> {
> return real_root_func (arg, 1);
> }
>
> static struct builtin builtin_root =
> {
> "root",
> root_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "root [DEVICE [HDBIAS]]",
> "Set the current \"root device\" to the device DEVICE, then"
> " attempt to mount it to get the partition size (for passing the"
> " partition descriptor in `ES:ESI', used by some chain-loaded"
> " bootloaders), the BSD drive-type (for booting BSD kernels using"
> " their native boot format), and correctly determine "
> " the PC partition where a BSD sub-partition is located. The"
> " optional HDBIAS parameter is a number to tell a BSD kernel"
> " how many BIOS drive numbers are on controllers before the current"
> " one. For example, if there is an IDE disk and a SCSI disk, and your"
> " FreeBSD root partition is on the SCSI disk, then use a `1' for
HDBIAS."
> };
>
>
> /* rootnoverify */
> static int
> rootnoverify_func (char *arg, int flags)
> {
> return real_root_func (arg, 0);
> }
>
> static struct builtin builtin_rootnoverify =
> {
> "rootnoverify",
> rootnoverify_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "rootnoverify [DEVICE [HDBIAS]]",
> "Similar to `root', but don't attempt to mount the partition. This"
> " is useful for when an OS is outside of the area of the disk that"
> " GRUB can read, but setting the correct root device is still"
> " desired. Note that the items mentioned in `root' which"
> " derived from attempting the mount will NOT work correctly."
> };
>
>
> /* savedefault
> static int
> savedefault_func (char *arg, int flags)
> {
> #if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
> unsigned long tmp_drive = saved_drive;
> unsigned long tmp_partition = saved_partition;
> char *default_file = (char *) DEFAULT_FILE_BUF;
> char buf[10];
> char sect[SECTOR_SIZE];
> int entryno;
> int sector_count = 0;
> int saved_sectors[2];
> int saved_offsets[2];
> int saved_lengths[2];
>
> // Save sector information about at most two sectors.
> auto void disk_read_savesect_func (int sector, int offset, int length);
> void disk_read_savesect_func (int sector, int offset, int length)
> {
> if (sector_count < 2)
> {
> saved_sectors[sector_count] = sector;
> saved_offsets[sector_count] = offset;
> saved_lengths[sector_count] = length;
> }
> sector_count++;
> }
>
> // This command is only useful when you boot an entry from the menu
interface.
> if (! (flags & BUILTIN_SCRIPT))
> {
> errnum = ERR_UNRECOGNIZED;
> return 1;
> }
>
> // Determine a saved entry number.
> if (*arg)
> {
> if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0)
> {
> int i;
> int index = 0;
>
> for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
> {
> if (fallback_entries[i] < 0)
> break;
> if (fallback_entries[i] == current_entryno)
> {
> index = i + 1;
> break;
> }
> }
>
> if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0)
> {
> // This is the last.
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> entryno = fallback_entries[index];
> }
> else if (! safe_parse_maxint (&arg, &entryno))
> return 1;
> }
> else
> entryno = current_entryno;
>
> // Open the default file.
> saved_drive = boot_drive;
> saved_partition = install_partition;
> if (grub_open (default_file))
> {
> int len;
>
> disk_read_hook = disk_read_savesect_func;
> len = grub_read (buf, sizeof (buf));
> disk_read_hook = 0;
> grub_close ();
>
> if (len != sizeof (buf))
> {
> // This is too small. Do not modify the file manually, please!
> errnum = ERR_READ;
> goto fail;
> }
>
> if (sector_count > 2)
> {
> // Is this possible?! Too fragmented!
> errnum = ERR_FSYS_CORRUPT;
> goto fail;
> }
>
> // Set up a string to be written.
> grub_memset (buf, '\n', sizeof (buf));
> grub_sprintf (buf, "%d", entryno);
>
> if (saved_lengths[0] < sizeof (buf))
> {
> // The file is anchored to another file and the first few bytes
> // are spanned in two sectors. Uggh...
> if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
> sect))
> goto fail;
> grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]);
> if (! rawwrite (current_drive, saved_sectors[0], sect))
> goto fail;
>
> if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE,
> sect))
> goto fail;
> grub_memmove (sect + saved_offsets[1],
> buf + saved_lengths[0],
> sizeof (buf) - saved_lengths[0]);
> if (! rawwrite (current_drive, saved_sectors[1], sect))
> goto fail;
> }
> else
> {
> // This is a simple case. It fits into a single sector.
> if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
> sect))
> goto fail;
> grub_memmove (sect + saved_offsets[0], buf, sizeof (buf));
> if (! rawwrite (current_drive, saved_sectors[0], sect))
> goto fail;
> }
>
> // Clear the cache.
> buf_track = -1;
> }
>
> fail:
> saved_drive = tmp_drive;
> saved_partition = tmp_partition;
> return errnum;
> #else
> // ! SUPPORT_DISKLESS && ! GRUB_UTIL
> errnum = ERR_UNRECOGNIZED;
> return 1;
> #endif
> // ! SUPPORT_DISKLESS && ! GRUB_UTIL
> }
>
> static struct builtin builtin_savedefault =
> {
> "savedefault",
> savedefault_func,
> BUILTIN_CMDLINE,
> "savedefault [NUM | `fallback']",
> "Save the current entry as the default boot entry if no argument is"
> " specified. If a number is specified, this number is saved. If"
> " `fallback' is used, next fallback entry is saved."
> };
> */
>
> // setkey
> /*
> struct keysym
> {
> char *unshifted_name; // the name in unshifted state
> char *shifted_name; // the name in shifted state
> unsigned char unshifted_ascii; // the ascii code in unshifted state
> unsigned char shifted_ascii; // the ascii code in shifted state
> unsigned char keycode; // keyboard scancode
> };
>
> // The table for key symbols. If the "shifted" member of an entry is
> // NULL, the entry does not have shifted state.
> static struct keysym keysym_table[] =
> {
> {"escape", 0, 0x1b, 0, 0x01},
> {"1", "exclam", '1', '!', 0x02},
> {"2", "at", '2', '@', 0x03},
> {"3", "numbersign", '3', '#', 0x04},
> {"4", "dollar", '4', '$', 0x05},
> {"5", "percent", '5', '%', 0x06},
> {"6", "caret", '6', '^', 0x07},
> {"7", "ampersand", '7', '&', 0x08},
> {"8", "asterisk", '8', '*', 0x09},
> {"9", "parenleft", '9', '(', 0x0a},
> {"0", "parenright", '0', ')', 0x0b},
> {"minus", "underscore", '-', '_', 0x0c},
> {"equal", "plus", '=', '+', 0x0d},
> {"backspace", 0, '\b', 0, 0x0e},
> {"tab", 0, '\t', 0, 0x0f},
> {"q", "Q", 'q', 'Q', 0x10},
> {"w", "W", 'w', 'W', 0x11},
> {"e", "E", 'e', 'E', 0x12},
> {"r", "R", 'r', 'R', 0x13},
> {"t", "T", 't', 'T', 0x14},
> {"y", "Y", 'y', 'Y', 0x15},
> {"u", "U", 'u', 'U', 0x16},
> {"i", "I", 'i', 'I', 0x17},
> {"o", "O", 'o', 'O', 0x18},
> {"p", "P", 'p', 'P', 0x19},
> {"bracketleft", "braceleft", '[', '{', 0x1a},
> {"bracketright", "braceright", ']', '}', 0x1b},
> {"enter", 0, '\n', 0, 0x1c},
> {"control", 0, 0, 0, 0x1d},
> {"a", "A", 'a', 'A', 0x1e},
> {"s", "S", 's', 'S', 0x1f},
> {"d", "D", 'd', 'D', 0x20},
> {"f", "F", 'f', 'F', 0x21},
> {"g", "G", 'g', 'G', 0x22},
> {"h", "H", 'h', 'H', 0x23},
> {"j", "J", 'j', 'J', 0x24},
> {"k", "K", 'k', 'K', 0x25},
> {"l", "L", 'l', 'L', 0x26},
> {"semicolon", "colon", ';', ':', 0x27},
> {"quote", "doublequote", '\'', '"', 0x28},
> {"backquote", "tilde", '`', '~', 0x29},
> {"shift", 0, 0, 0, 0x2a},
> {"backslash", "bar", '\\', '|', 0x2b},
> {"z", "Z", 'z', 'Z', 0x2c},
> {"x", "X", 'x', 'X', 0x2d},
> {"c", "C", 'c', 'C', 0x2e},
> {"v", "V", 'v', 'V', 0x2f},
> {"b", "B", 'b', 'B', 0x30},
> {"n", "N", 'n', 'N', 0x31},
> {"m", "M", 'm', 'M', 0x32},
> {"comma", "less", ',', '<', 0x33},
> {"period", "greater", '.', '>', 0x34},
> {"slash", "question", '/', '?', 0x35},
> {"alt", 0, 0, 0, 0x38},
> {"space", 0, ' ', 0, 0x39},
> {"capslock", 0, 0, 0, 0x3a},
> {"F1", 0, 0, 0, 0x3b},
> {"F2", 0, 0, 0, 0x3c},
> {"F3", 0, 0, 0, 0x3d},
> {"F4", 0, 0, 0, 0x3e},
> {"F5", 0, 0, 0, 0x3f},
> {"F6", 0, 0, 0, 0x40},
> {"F7", 0, 0, 0, 0x41},
> {"F8", 0, 0, 0, 0x42},
> {"F9", 0, 0, 0, 0x43},
> {"F10", 0, 0, 0, 0x44},
> // Caution: do not add NumLock here! we cannot deal with it properly.
> {"delete", 0, 0x7f, 0, 0x53}
> };
>
> static int
> setkey_func (char *arg, int flags)
> {
> char *to_key, *from_key;
> int to_code, from_code;
> int map_in_interrupt = 0;
>
> auto int find_key_code (char *key);
> auto int find_ascii_code (char *key);
>
> auto int find_key_code (char *key)
> {
> int i;
>
> for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]);
i++)
> {
> if (keysym_table[i].unshifted_name &&
> grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
> return keysym_table[i].keycode;
> else if (keysym_table[i].shifted_name &&
> grub_strcmp (key, keysym_table[i].shifted_name) == 0)
> return keysym_table[i].keycode;
> }
>
> return 0;
> }
>
> auto int find_ascii_code (char *key)
> {
> int i;
>
> for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]);
i++)
> {
> if (keysym_table[i].unshifted_name &&
> grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
> return keysym_table[i].unshifted_ascii;
> else if (keysym_table[i].shifted_name &&
> grub_strcmp (key, keysym_table[i].shifted_name) == 0)
> return keysym_table[i].shifted_ascii;
> }
>
> return 0;
> }
>
> to_key = arg;
> from_key = skip_to (0, to_key);
>
> if (! *to_key)
> {
> // If the user specifies no argument, reset the key mappings.
> grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned
short));
> grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned
short));
>
> return 0;
> }
> else if (! *from_key)
> {
> // The user must specify two arguments or zero argument.
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> nul_terminate (to_key);
> nul_terminate (from_key);
>
> to_code = find_ascii_code (to_key);
> from_code = find_ascii_code (from_key);
> if (! to_code || ! from_code)
> {
> map_in_interrupt = 1;
> to_code = find_key_code (to_key);
> from_code = find_key_code (from_key);
> if (! to_code || ! from_code)
> {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
> }
>
> if (map_in_interrupt)
> {
> int i;
>
> // Find an empty slot.
> for (i = 0; i < KEY_MAP_SIZE; i++)
> {
> if ((bios_key_map[i] & 0xff) == from_code)
> // Perhaps the user wants to overwrite the map.
> break;
>
> if (! bios_key_map[i])
> break;
> }
>
> if (i == KEY_MAP_SIZE)
> {
> errnum = ERR_WONT_FIT;
> return 1;
> }
>
> if (to_code == from_code)
> // If TO is equal to FROM, delete the entry.
> grub_memmove ((char *) &bios_key_map[i],
> (char *) &bios_key_map[i + 1],
> sizeof (unsigned short) * (KEY_MAP_SIZE - i));
> else
> bios_key_map[i] = (to_code << 8) | from_code;
>
> // Ugly but should work.
> unset_int15_handler ();
> set_int15_handler ();
> }
> else
> {
> int i;
>
> // Find an empty slot.
> for (i = 0; i < KEY_MAP_SIZE; i++)
> {
> if ((ascii_key_map[i] & 0xff) == from_code)
> // Perhaps the user wants to overwrite the map.
> break;
>
> if (! ascii_key_map[i])
> break;
> }
>
> if (i == KEY_MAP_SIZE)
> {
> errnum = ERR_WONT_FIT;
> return 1;
> }
>
> if (to_code == from_code)
> // If TO is equal to FROM, delete the entry.
> grub_memmove ((char *) &ascii_key_map[i],
> (char *) &ascii_key_map[i + 1],
> sizeof (unsigned short) * (KEY_MAP_SIZE - i));
> else
> ascii_key_map[i] = (to_code << 8) | from_code;
> }
>
> return 0;
> }
>
> static struct builtin builtin_setkey =
> {
> "setkey",
> setkey_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "setkey [TO_KEY FROM_KEY]",
> "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
> " A key must be an alphabet, a digit, or one of these: escape, exclam,"
> " at, numbersign, dollar, percent, caret, ampersand, asterisk,
parenleft,"
> " parenright, minus, underscore, equal, plus, backspace, tab,
bracketleft,"
> " braceleft, bracketright, braceright, enter, control, semicolon,
colon,"
> " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
> " less, period, greater, slash, question, alt, space, capslock, FX (X"
> " is a digit), and delete. If no argument is specified, reset key"
> " mappings."
> };
> */
>
> /* 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;
> unsigned long installed_drive, installed_partition;
> unsigned long image_drive, image_partition;
> unsigned long tmp_drive, tmp_partition;
> char stage1[64];
> char stage2[64];
> char config_filename[64];
> char real_config_filename[64];
> char cmd_arg[256];
> char device[16];
> char *buffer = (char *) RAW_ADDR (0x100000);
> int is_force_lba = 0;
> char *stage2_arg = 0;
> char *prefix = 0;
>
> auto int check_file (char *file);
> auto void sprint_device (int drive, int partition);
> auto int embed_stage1_5 (char * stage1_5, int drive, int partition);
>
> /* Check if the file FILE exists like Autoconf. */
> int check_file (char *file)
> {
> int ret;
>
> grub_printf (" Checking if \"%s\" exists... ", file);
> ret = grub_open (file);
> if (ret)
> {
> grub_close ();
> grub_printf ("yes\n");
> }
> else
> grub_printf ("no\n");
>
> return ret;
> }
>
> /* Construct a device name in DEVICE. */
> void sprint_device (int drive, int partition)
> {
> grub_sprintf (device, "(%cd%d",
> (drive & 0x80) ? 'h' : 'f',
> drive & ~0x80);
> if ((partition & 0xFF0000) != 0xFF0000)
> {
> char tmp[16];
> grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
> grub_strncat (device, tmp, 256);
> }
> if ((partition & 0x00FF00) != 0x00FF00)
> {
> char tmp[16];
> grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
> grub_strncat (device, tmp, 256);
> }
> grub_strncat (device, ")", 256);
> }
>
> int embed_stage1_5 (char *stage1_5, int drive, int partition)
> {
> /* We install GRUB into the MBR, so try to embed the
> Stage 1.5 in the sectors right after the MBR. */
> sprint_device (drive, partition);
> grub_sprintf (cmd_arg, "%s %s", stage1_5, device);
>
> /* Notify what will be run. */
> grub_printf (" Running \"embed %s\"... ", cmd_arg);
>
> embed_func (cmd_arg, flags);
> if (! errnum)
> {
> /* Construct the blocklist representation. */
> grub_sprintf (buffer, "%s%s", device, embed_info);
> grub_printf ("succeeded\n");
> return 1;
> }
> else
> {
> grub_printf ("failed (this is not fatal)\n");
> return 0;
> }
> }
>
> struct stage1_5_map {
> char *fsys;
> char *name;
> };
> struct stage1_5_map stage1_5_map[] =
> {
> {"ext2fs", "/e2fs_stage1_5"},
> {"fat", "/fat_stage1_5"},
> {"ufs", "/ufs_stage1_5"},
> {"ufs2", "/ufs2_stage1_5"},
> {"ffs", "/ffs_stage1_5"},
> {"iso9660", "/iso9660_stage1_5"},
> {"jfs", "/jfs_stage1_5"},
> {"minix", "/minix_stage1_5"},
> {"reiserfs", "/reiserfs_stage1_5"},
> {"vstafs", "/vstafs_stage1_5"},
> {"xfs", "/xfs_stage1_5"}
> };
>
> tmp_drive = saved_drive;
> tmp_partition = saved_partition;
>
> /* Check if the user specifies --force-lba. */
> while (1)
> {
> if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) ==
0)
> {
> is_force_lba = 1;
> arg = skip_to (0, arg);
> }
> else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) ==
0)
> {
> prefix = arg + sizeof ("--prefix=") - 1;
> arg = skip_to (0, arg);
> nul_terminate (prefix);
> }
> #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);
>
> /* Make sure that INSTALL_PTR is valid. */
> set_device (install_ptr);
> if (errnum)
> return 1;
>
> installed_drive = current_drive;
> installed_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_drive = saved_drive;
> current_partition = saved_partition;
> }
>
> image_drive = saved_drive = current_drive;
> image_partition = saved_partition = current_partition;
>
> /* Open it. */
> if (! open_device ())
> goto fail;
>
> /* Check if stage1 exists. If the user doesn't specify the option
> `--prefix', attempt /boot/grub and /grub. */
> /* NOTE: It is dangerous to run this command without `--prefix' in the
> grub shell, since that affects `--stage2'. */
> if (! prefix)
> {
> prefix = "/boot/grub";
> grub_sprintf (stage1, "%s%s", prefix, "/stage1");
> if (! check_file (stage1))
> {
> errnum = ERR_NONE;
> prefix = "/grub";
> grub_sprintf (stage1, "%s%s", prefix, "/stage1");
> if (! check_file (stage1))
> goto fail;
> }
> }
> else
> {
> grub_sprintf (stage1, "%s%s", prefix, "/stage1");
> if (! check_file (stage1))
> goto fail;
> }
>
> /* The prefix was determined. */
> grub_sprintf (stage2, "%s%s", prefix, "/stage2");
> grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst");
> *real_config_filename = 0;
>
> /* Check if stage2 exists. */
> if (! check_file (stage2))
> goto fail;
>
> {
> 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. */
> char stage1_5[64];
>
> grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name);
> if (check_file (stage1_5))
> {
> if (embed_stage1_5 (stage1_5,
> installed_drive, installed_partition)
> || embed_stage1_5 (stage1_5,
> image_drive, image_partition))
> {
> grub_strcpy (real_config_filename, config_filename);
> sprint_device (image_drive, image_partition);
> grub_sprintf (config_filename, "%s%s", device, stage2);
> grub_strcpy (stage2, buffer);
> }
> }
> errnum = 0;
> break;
> }
> }
>
> /* Construct a string that is used by the command "install" as its
> arguments. */
> sprint_device (installed_drive, installed_partition);
>
> #if 1
> /* Don't embed a drive number unnecessarily. */
> grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s",
> is_force_lba? "--force-lba " : "",
> stage2_arg? stage2_arg : "",
> stage2_arg? " " : "",
> stage1,
> (installed_drive != image_drive) ? "d " : "",
> device,
> stage2,
> config_filename,
> real_config_filename);
> #else /* NOT USED */
> /* This code was used, because we belived some BIOSes had a problem
> that they didn't pass a booting drive correctly. It turned out,
> however, stage1 could trash a booting drive when checking LBA
support,
> because some BIOSes modified the register %dx in INT 13H, AH=48H.
> So it becamed unclear whether GRUB should use a pre-defined booting
> drive or not. If the problem still exists, it would be necessary to
> switch back to this code. */
> grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s",
> is_force_lba? "--force-lba " : "",
> stage2_arg? stage2_arg : "",
> stage2_arg? " " : "",
> stage1,
> device,
> stage2,
> config_filename,
> real_config_filename);
> #endif /* NOT USED */
>
> /* Notify what will be run. */
> grub_printf (" Running \"install %s\"... ", cmd_arg);
>
> /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical
> with IMAGE_DRIVE and IMAGE_PARTITION, respectively. */
> saved_drive = image_drive;
> saved_partition = image_partition;
>
> /* Run the command. */
> if (! install_func (cmd_arg, flags))
> grub_printf ("succeeded\nDone.\n");
> else
> grub_printf ("failed\n");
>
> fail:
> saved_drive = tmp_drive;
> saved_partition = tmp_partition;
> return errnum;
> }
>
> static struct builtin builtin_setup =
> {
> "setup",
> setup_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "setup [--prefix=DIR] [--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,"
> " then find the GRUB images in the device IMAGE_DEVICE, otherwise"
> " 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."
> };
>
>
> /* timeout */
> static int
> timeout_func (char *arg, int flags)
> {
> if (! safe_parse_maxint (&arg, &grub_timeout))
> return 1;
>
> return 0;
> }
>
> static struct builtin builtin_timeout =
> {
> "timeout",
> timeout_func,
> BUILTIN_MENU,
> #if 0
> "timeout SEC",
> "Set a timeout, in SEC seconds, before automatically booting the"
> " default entry (normally the first entry defined)."
> #endif
> };
>
>
> /* title */
> static int
> title_func (char *arg, int flags)
> {
> /* This function is not actually used at least currently. */
> return 0;
> }
>
> static struct builtin builtin_title =
> {
> "title",
> title_func,
> BUILTIN_TITLE,
> #if 0
> "title [NAME ...]",
> "Start a new boot entry, and set its name to the contents of the"
> " rest of the line, starting with the first non-space character."
> #endif
> };
>
>
> /* unhide */
> static int
> unhide_func (char *arg, int flags)
> {
> if (! set_device (arg))
> return 1;
>
> if (! set_partition_hidden_flag (0))
> return 1;
>
> return 0;
> }
>
> static struct builtin builtin_unhide =
> {
> "unhide",
> unhide_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "unhide PARTITION",
> "Unhide PARTITION by clearing the \"hidden\" bit in its"
> " partition type code."
> };
>
> /* selecthd */
> static int
> selecthd_func (char *arg, int flags)
> {
> int i,j, disk_no; // Aux variables
>
> // Check if there's any hard disk before doing anything
> if (there_is_a_hard_disk ()) { errnum = ERR_FILE_NOT_FOUND; return 1; }
>
>
> special_menu = 1; // Force not to read the menu
>
>
> if(add_menu ()) return 1;
>
>
>
> // NEW CODE - BEGIN
> // Add main title
>
>
> add_choose_title ();
>
>
> add_title (&menu_array[menu_level], "NATURAL LINUX-IDE LINUX-SCSI GRUB
HURD");
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "pause
Nothing to do");
> close_title ((char *) MENU_BUF, &menu_array[menu_level]);
>
>
>
> // Add title and instructions concerning hard disks
> for (i = 1;i < 2; i++)
> {
> for (j = 0; j < 16; j++)
> {
> struct geometry geom;
> disk_no = (i * 0x80) + j;
> if (! get_diskinfo (disk_no, &geom))
> {
> // Add title
>
> add_title (&menu_array[menu_level], " %d hd%c sd%c
(hd%d) hd%d",j + 1,'a'+j,'a'+j, j,j);
>
> // Add instructions
>
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_device=(hd%d)",j);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_hd=hd%d",j);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_linux_letter=%c",'a'+j);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_lide_hd=hd%c",'a' + j);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_lscsi_hd=sd%c",'a' + j);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "set
out_hurd_hd=hd%d",j);
> add_instruction (&menu_array[menu_level], (char *) MENU_BUF, "back");
>
> close_title ((char *) MENU_BUF, &menu_array[menu_level]);
> }
> }
> }
>
> close_menu ((char *) MENU_BUF, &menu_array[menu_level]);
> // NEW CODE - END
>
>
> // Define the new menu - End
>
> configfile_end();
> /* Never reach here. */
> return 0;
> }
>
> static struct builtin builtin_selecthd =
> {
> "selecthd",
> selecthd_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "selecthd",
> "Let user select hd and return into the step the configfile was
loading.."
> };
>
>
> #define VARIABLE_STORE_SIZE 512
> char variable_store[VARIABLE_STORE_SIZE];
> unsigned int variable_store_actpos; /* Points to the next free entry */
> struct variable_list_struct {
> char *name;
> char *value;
> } variable_list[VARIABLES_MAX];
>
> static void var_show(void)
> {
> int i = 0;
>
> for (; i < VARIABLES_MAX; i++)
> if (variable_list[i].name)
> {
> grub_printf("%s = %s\n",
> variable_list[i].name,
> variable_list[i].value);
> }
> }
>
> static int var_get_index(char *var)
> {
> int i = 0;
>
> if (!*var)
> return -1;
>
> for (; i < VARIABLES_MAX; i++)
> if (variable_list[i].name &&
> grub_strcmp(variable_list[i].name, var) == 0)
> return i;
>
> return -1;
> }
>
> char *var_get(char *var)
> {
> int i;
>
> if ((i = var_get_index(var)) == -1)
> return NULL;
>
> return variable_list[i].value;
> }
>
> static char *var_alloc_mem(unsigned int len)
> {
> if (VARIABLE_STORE_SIZE < variable_store_actpos + len
> || !len)
> return NULL;
>
> variable_store_actpos += len;
> return &variable_store[variable_store_actpos - len];
> }
>
> /* Maybe we're implementing "unset" later? */
> static int var_get_free_var(void)
> {
> int i = 0;
>
> for (; i < VARIABLES_MAX; i++)
> if (variable_list[i].name == NULL)
> return i;
>
> return -1;
> }
>
> static inline char *skip_ws(char *s)
> {
> while (isspace(*s))
> s++;
> return s;
> }
>
> static int var_sprint_once(char *buf, char *str)
> {
>
> char *b = buf;
>
>
> while (*str)
> {
>
> if (*str == '$' && *(str + 1) == '$')
> {
> *b++ = *str++;
> str++;
> }
> else if (*str == '$' && *(str + 1) == '(')
> {
> /* Found start of variable */
> char *end_var;
> char *c = str + 2;
>
> end_var = c;
> while (*end_var && *end_var != ')')
> end_var++;
>
> if (*end_var == ')')
> {
> char *val;
>
> /* Copy variable name into var */
>
> str = end_var + 1;
>
> *end_var = 0;
> if ((val = var_get(c)))
> {
> /* All ok, we got it */
> /* Copy to buf */
> while (*val)
> *b++ = *val++;
>
> *end_var = ')';
>
> continue;
> }
> /* else
> grub_printf("Unknown variable: %var!\n", var); */
>
> *end_var = ')';
> }
> }
>
> *b++ = *str++;
> }
>
> *b = 0;
>
> return b - buf;
> }
>
> int var_sprint(char *buf, char *str)
> {
> //int i = 10;
> /* Waste some stack here... */
> const int buffer_size = 1000;
> char buffer[buffer_size];
>
> grub_strcpy(buf, str);
>
> /* adrian15 - So that we can parse $$ without any problem
>
> We're not checking any return values here or any array overflows... :(
> do
> {
> if (grub_strlen(buf) > buffer_size)
> {
> grub_printf("Buffer overflow: %s(%d)\n", __FILE__, __LINE__);
> while (1) {}
> }
>
> grub_strcpy(buffer, buf);
>
> var_sprint_once(buf, buffer);
> }
> while (--i && grub_strcmp(buf, buffer));
>
> if (!i)
> {
> grub_printf("Possible loop in var_sprintf!\n");
> getkey();
> }
> */
> if (grub_strlen(buf) > buffer_size)
> {
> grub_printf("Buffer overflow: %s(%d)\n", __FILE__, __LINE__);
> while (1) {}
> }
>
> grub_strcpy(buffer, buf);
>
> var_sprint_once(buf, buffer);
>
> return grub_strlen(buf);
> }
>
> /* Use our own buffer instead of a supplied one and
> * return the pointer to the buffer and not the bytes
> * processed. */
> /* We try to detect buffer overruns... */
> static char var_sprint_buffer[1500];
> static const long var_sprint_magic = 0x14233241;
> char *var_sprint_buf(char *str, int *bytes)
> {
> *(long *)(var_sprint_buffer + sizeof(var_sprint_buffer) -
sizeof(var_sprint_magic)) = var_sprint_magic;
>
> *bytes = var_sprint(var_sprint_buffer, str);
>
> if (*(long *)(var_sprint_buffer + sizeof(var_sprint_buffer) -
sizeof(var_sprint_magic)) != var_sprint_magic)
> {
> grub_printf("Possible buffer overrun: %s(%d)\n", __FILE__,
__LINE__);
> while (1) {}
> }
> return var_sprint_buffer;
> }
>
> /* This function just updates the pointer to the value, this value has to
> * be inside the variable_store */
> static int var_set_no_copy(char *name, char *val)
> {
> int i;
>
> if (val < variable_store || val >= (variable_store +
VARIABLE_STORE_SIZE))
> return 1;
>
> i = var_get_index(name);
>
> if (i == -1)
> {
> /* The variable doesn't exist yet, so we have a new variable */
> char *a = name;
>
> /* Some sanity check */
> while (*a)
> {
> if (*a == '(' || *a == ')' || *a == ' ')
> return 1;
> a++;
> }
>
>
> if ((i = var_get_free_var()) == -1)
> return 1;
>
> if ((a = var_alloc_mem(grub_strlen(name) + 1)) == NULL)
> return 1;
>
> grub_strcpy(a, name);
> variable_list[i].name = a;
> }
>
> variable_list[i].value = val;
>
> return 0; /* Ok */
> }
>
> /* XXX: this is a bit code duplication with var_set_no_copy,
> * so if someone has some free time, feel free to join this
> */
> int var_set(char *name, char *value, int parse)
> {
> int i;
>
> if (parse)
> value = var_sprint_buf(value, &i);
>
> i = var_get_index(name);
>
> if (i == -1)
> {
> /* The variable doesn't exist yet, so we have a new variable */
> char *a = name;
>
> /* Some sanity check */
> while (*a)
> {
> if (*a == '(' || *a == ')' || *a == ' ')
> return 1;
> a++;
> }
>
> if ((i = var_get_free_var()) == -1)
> return 1;
>
> if ((a = var_alloc_mem(grub_strlen(name) + 1)) == NULL)
> return 1;
>
> grub_strcpy(a, name);
> variable_list[i].name = a;
>
> if ((a = var_alloc_mem(grub_strlen(value) + 1)) == NULL)
> return 1;
>
> grub_strcpy(a, value);
> variable_list[i].value = a;
> }
> else
> {
> /* Variable already exists */
> if (grub_strlen(variable_list[i].value) >= grub_strlen(value))
> {
> /* We can just replace the value but we're potentially
> * loosing space */
> grub_strcpy(variable_list[i].value, value);
> }
> else
> {
> /* New value is longer then the old one, we need to
> * allocate a new place and drop the old one (i.e. wasting it) */
> char *a;
> if ((a = var_alloc_mem(grub_strlen(value) + 1)) == NULL)
> return 1;
>
> grub_strcpy(a, value);
>
> variable_list[i].value = a;
> }
> }
>
> //grub_printf("Saved %s=\"%s\" in slot %d.\n", variable_list[i].name,
variable_list[i].value, i + 1);
> //getkey();
>
> return 0; /* Ok */
> }
>
>
>
>
> static int
> set_func(char *arg, int flags)
> {
> char *a = arg;
> char *variable, *value;
> char *end_variable, end_variable_val;
> char *end_value, end_value_val;
> char end_char;
> int i = 0, parse = 0, emptysetonly = 0;
>
> a = skip_ws(a);
>
> if (!*a)
> {
> var_show();
> return 0;
> }
>
> variable = a;
> while (*a && *a != ':' && *a != '=' && *a != ' ')
> a++;
> end_variable_val = *a;
> end_variable = a;
>
> a = skip_ws(a);
>
> if (*a == ':')
> {
> parse = 1;
> a++;
> }
> if (*a == '?')
> {
> emptysetonly = 1;
> a++;
> }
>
> if (*a != '=')
> goto bad_arg;
>
> a++;
> a = skip_ws(a);
>
> end_char = ' ';
> if (*a == '"')
> {
> end_char = *a;
> a++;
> }
> /* XXX: add/fix \" and \\ stuff */
> value = a;
> while (*a && *a != end_char)
> a++;
> end_value_val = *a;
> end_value = a;
>
> *end_value = *end_variable = 0;
>
> if ((emptysetonly && var_get_index(variable) == -1) ||
> !emptysetonly)
> i = var_set(variable, value, parse);
>
> *end_value = end_value_val;
> *end_variable = end_variable_val;
>
> return i;
>
> bad_arg:
> grub_printf("%s: ERR_BAD_ARGUMENT\n", __func__);
> getkey();
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> static struct builtin builtin_set =
> {
> "set",
> set_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "set var=val",
> "Set a variable to a value."
> };
>
> static int
> print_func(char *arg, int flags)
> {
> grub_printf("%s\n", var_sprint_buf(arg, &flags));
> return 0;
> }
>
> static struct builtin builtin_print =
> {
> "print",
> print_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "print \"string with vars\"",
> "Print a string which may contain variables. Variables are enclosed"
> " in $( and ) (like \"make\")."
> };
>
> static struct builtin builtin_echo =
> {
> "echo",
> print_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "echo \"string with vars\"",
> "Alias for \"print\"."
> };
>
>
>
>
> #define TOGGLES 2
> #define MAX_BLOCKS 3
> #define MAX_VAR_PER_BLOCK 4
>
> struct toggle_data_struct {
> int key; /* int because of F-keys !? */
> int current_block;
> char nr_blocks;
> struct {
> char nr_vars;
> struct {
> int var; /* index of variable_list */
> char *value; /* pointer to value */
> } var[MAX_VAR_PER_BLOCK];
> } block[MAX_BLOCKS];
> } toggle_data[TOGGLES];
> int toggles_used = 0;
>
> char toggle_trigger_init_done;
>
> static int get_toggle_slot_for_key(int key)
> {
> int i = 0;
>
> for (; i < TOGGLES; i++)
> if (toggle_data[i].key == key)
> return i;
>
> return -1;
> }
>
> int toggle_print_status(int x, int y)
> {
> /* Basically print all variable which are on the left side on toggles */
> int printed[VARIABLES_MAX];
> int printed_something = 0;
> int i, t, b, v, dummy;
> const int ylines = 6;
> int xpos[ylines];
> int dy = 0;
>
> for (i = 0; i < ylines; i++)
> xpos[i] = x;
>
> for (i = 0; i < VARIABLES_MAX; i++)
> printed[i] = 0;
>
> for (t = 0; t < toggles_used; t++)
> {
> for (b = 0; b < toggle_data[t].nr_blocks; b++)
> {
> for (v = 0; v < toggle_data[t].block[b].nr_vars; v++)
> {
> i = toggle_data[t].block[b].var[v].var;
> if (!printed[i])
> {
> int len;
> char *vals;
>
> gotoxy(xpos[dy], y + dy);
>
> /* don't use printf here since we need the lengths
> * of the printed string and we don't want to use another
> * buffer for sprintf
> */
> grub_putstr(variable_list[i].name);
> grub_putchar('=');
> len = grub_strlen(variable_list[i].name) + 1;
>
> vals = var_sprint_buf(variable_list[i].value, &dummy);
> grub_putstr(vals);
> len += grub_strlen(vals);
>
> xpos[dy] += len + 2;
>
> if (++dy == ylines) {
> dy = 0;
> }
>
> printed[i] = printed_something = 1;
> }
> }
> }
> }
>
> return printed_something;
> }
>
> static int toggle_do_block(int slot, int block_nr)
> {
> int v;
>
> if (slot >= toggles_used || block_nr >= toggle_data[slot].nr_blocks)
> return 0;
>
> /* Set all variables in th block block_nr to their new values */
> for (v = 0; v < toggle_data[slot].block[block_nr].nr_vars; v++)
> {
> int l = toggle_data[slot].block[block_nr].var[v].var;
>
> var_set_no_copy(variable_list[l].name,
toggle_data[slot].block[block_nr].var[v].value);
> }
>
> return 1; /* Ok */
> }
>
> static int toggle_find_slot(int key)
> {
> int i = 0;
>
> for (; i < toggles_used; i++)
> if (toggle_data[i].key == key)
> return i;
>
> return -1;
> }
>
> int toggle_do_key(int key)
> {
> int slot;
>
> if ((slot = toggle_find_slot(key)) == -1)
> return 0;
>
> /* Proceed to the next block */
> if (++toggle_data[slot].current_block == toggle_data[slot].nr_blocks)
> toggle_data[slot].current_block = 0;
>
> toggle_do_block(slot, toggle_data[slot].current_block);
>
> return 1;
> }
>
> int toggle_iterate_key(int key)
> {
> int slot;
>
> if ((slot = toggle_find_slot(key)) == -1) {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> /* Proceed to the next block */
> if (++toggle_data[slot].current_block == toggle_data[slot].nr_blocks) {
> errnum = ERR_BAD_ARGUMENT;
> // Although we're going through an error we set the values to the
first values for safety
> toggle_data[slot].current_block=0;
> toggle_do_block(slot, toggle_data[slot].current_block);
> return 1;
> }
>
> toggle_do_block(slot, toggle_data[slot].current_block);
>
> return 0;
> }
>
> int toggle_set_first_key(int key)
> {
> int slot;
>
> if ((slot = toggle_find_slot(key)) == -1) {
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> /* Proceed to the fist block */
> toggle_data[slot].current_block = 0;
>
> toggle_do_block(slot, toggle_data[slot].current_block);
>
> return 0;
> }
>
> /* toggle
>
> static int
> toggle_func(char *arg, int flags)
> {
> int slot, key, block = 0, i;
> char *a = arg, *eb;
> int command;
> enum {
> COMMAND_SET,
> COMMAND_SELECT,
> COMMAND_TRIGGER,
> COMMAND_SETFIRST,
> COMMAND_ITERATE
> };
>
> // static int process_var(int bl, int var, char *start, char *end)
> int process_var(int bl, int var, char *start, char *end)
> {
> char *p, origvar, *origvarp, origval, *v;
>
> //grub_printf("VAR(%d, %d) %s [%d]\n", bl, var, start, end-start+1);
>
> start = skip_ws(start);
> p = start;
> while (p < end && *p != '=' && !isspace(*p))
> p++;
>
> origvar = *p;
> origvarp = p;
>
> p = skip_ws(p);
> if (*p != '=')
> return 1;
>
> p = skip_ws(p+1);
>
> // value is now from p to end (both inclusive)
>
> origval = *(end + 1);
> *(end + 1) = 0;
> *origvarp = 0;
>
> // See if we already have the same value in that toggle
> // (in case we're entering a menu multiple time we would
> // allocate memory multiple time)
>
> if (toggle_data[slot].block[bl].var[var].value &&
> var_get_index(start) != -1 &&
> !grub_strcmp(toggle_data[slot].block[bl].var[var].value, p))
> {
> }
> else
> {
> // Allocate space for the value and hang it in
> if ((v = var_alloc_mem(grub_strlen(p) + 1)) == NULL)
> return 1;
> grub_strcpy(v, p);
>
> var_set_no_copy(start, v);
>
> if ((toggle_data[slot].block[bl].var[var].var = var_get_index(start))
== -1)
> return 1; // internal error
> toggle_data[slot].block[bl].var[var].value = v;
> }
>
> *origvarp = origvar;
> *(end + 1) = origval;
>
> //grub_printf("slot=%d block=%d var=%d %d=%s\n", slot, bl, var,
toggle_data[slot].block[bl].var[var].var, v);
>
> if (var >= toggle_data[slot].block[bl].nr_vars)
> toggle_data[slot].block[bl].nr_vars = var + 1;
>
> return 0;
> }
> //static int process_block(int bl, char *start, char *end)
> int process_block(int bl, char *start, char *end)
> {
> char *p = start;
> int var = 0;
>
> //grub_printf("BL(%d) %s [%d]\n", bl, start, end-start+1);
>
> while (p <= end)
> {
> if (*p == ',' || p == end)
> {
> if (var == MAX_VAR_PER_BLOCK)
> return ERR_WONT_FIT;
>
> if (process_var(bl, var, start, (p == end) ? p : (p-1)))
> return ERR_BAD_ARGUMENT;
>
> var++;
> start = p + 1;
> }
> p++;
> }
>
> return 0;
> }
>
>
> // parse args
> // proceed to next arg
> while (*a && *a == ' ')
> a++;
>
> // Get command
> {
> eb = a;
>
> while (!isspace(*eb))
> eb++;
>
> if (!isspace(*eb))
> goto bad_arg;
>
> //grub_printf("trigger: processing line: %s\n", a);
>
> *eb = 0;
>
> if (!grub_strcmp(a, "set"))
> command = COMMAND_SET;
> else if (!grub_strcmp(a, "select"))
> command = COMMAND_SELECT;
> else if (!grub_strcmp(a, "trigger"))
> command = COMMAND_TRIGGER;
> else if (!grub_strcmp(a, "setfirst"))
> command = COMMAND_SETFIRST;
> else if (!grub_strcmp(a, "iterate"))
> command = COMMAND_ITERATE;
> else
> {
> grub_printf("toggle: Unknown command!\n");
> goto bad_arg;
> }
>
> *eb = ' ';
> a = eb + 1;
> }
>
> a = skip_ws(a);
>
> if (command == COMMAND_SET)
> {
>
> if (!*a || !*(a+1))
> goto bad_arg;
>
> key = *a;
> a++;
>
> //grub_printf("key: %c\n", key);
>
> // Find slot for key
> slot = get_toggle_slot_for_key(key);
> if (slot == -1)
> {
> // Get next free toggle_data slot
> slot = toggles_used;
> if (slot == TOGGLES)
> goto wont_fit;
> toggle_data[slot].key = key;
> toggles_used++;
> }
>
> // Reset current slot
> toggle_data[slot].nr_blocks = toggle_data[slot].current_block = 0;
> for (i = 0; i < MAX_VAR_PER_BLOCK; i++)
> toggle_data[slot].block[i].nr_vars = 0;
>
> while (*a)
> {
> int ret;
>
> a = skip_ws(a);
>
> if (*a != '{')
> goto bad_arg;
> // find the correspondig '}'
> eb = a++;
> while (*eb && *eb != '}')
> eb++;
> if (*eb != '}')
> goto bad_arg;
> // Now we have the block between a and eb-1
> ret = process_block(block, a, eb-1);
> if (ret == ERR_WONT_FIT)
> goto wont_fit;
> if (ret)
> goto bad_arg;
>
> a = eb + 1;
>
> block++;
> if (*a) {
> if (block == MAX_BLOCKS)
> goto wont_fit;
> }
> }
> toggle_data[slot].nr_blocks = block;
>
> // finally, set all vars from the first block
> toggle_do_block(slot, 0);
> }
> else if (command == COMMAND_SELECT)
> {
> while (*a)
> {
> int k, b, s;
>
> // there's something between a and eb-1 now
> // *a is a key and *(a+1) == '='
> k = *a++;
>
> if (*a++ != '=')
> goto bad_arg;
>
> if (!safe_parse_maxint(&a, &b))
> goto bad_arg;
>
> if ((s = toggle_find_slot(k)) == -1)
> goto bad_arg;
>
> if (!toggle_do_block(s, b))
> goto bad_arg;
>
> toggle_data[s].current_block = b;
>
> a = skip_ws(a);
> }
> }
> else if (command == COMMAND_TRIGGER)
> {
> char *vr, *vre, *vl, *vle, *vrval;
> char o;
> int cmp;
> // remaining a(rg) format: VAR==VAL "command"
> //grub_printf("%s: trigger\n");
>
> // Find the '='
> vr = a;
> while (*a && *a != ' ' && *a != '=')
> a++;
>
> if (*a != '=' || *(a+1) != '=')
> goto bad_arg;
>
> vre = a;
>
> if (vr == vre)
> goto bad_arg;
>
> a += 2;
> vl = a;
>
> while (!isspace(*a))
> a++;
>
> vle = a;
>
> if (vl == vle)
> goto bad_arg;
>
>
> *vre = 0;
> vrval = var_get(vr);
> *vre = '=';
>
> if (!vrval)
> goto bad_arg;
>
> o = *vle;
> *vle = 0;
> cmp = grub_strcmp(vrval, vl);
> *vle = o;
>
> a = skip_ws(a);
>
> if (!cmp)
> toggle_func(a, 0);
> }
> else if (command == COMMAND_SETFIRST) {
> while (*a)
> {
> int k;
> k = *a;
> return (toggle_set_first_key(k));
> }
> }
> else if (command == COMMAND_ITERATE) {
> while (*a)
> {
> int k;
> k = *a;
> return (toggle_iterate_key(k));
> }
> }
>
> return 0;
>
> wont_fit:
> grub_printf("%s: ERR_WONT_FIT\n", __func__);
> getkey();
> errnum = ERR_WONT_FIT;
> return 1;
>
> bad_arg:
> grub_printf("%s: ERR_BAD_ARGUMENT\n", __func__);
> getkey();
> errnum = ERR_BAD_ARGUMENT;
> return 1;
> }
>
> void toggle_trigger_init(void)
> {
> int detect_vmware(void)
> // static int detect_vmware(void)
> {
> #ifndef GRUB_UTIL
> char *start = (char *)0xc0000;
> int size = 16 << 10;
> int i = 0, p = 0;
> char *s = "VMware, Inc.";
>
> while (i < size)
> {
> if (*(start + i) == s[p])
> {
> p++;
> if (!s[p])
> return 1;
> }
> else
> p = 0;
> i++;
> }
> #endif
> return 0;
> }
>
> if (toggle_trigger_init_done)
> return;
> toggle_trigger_init_done = 1;
>
> var_set("TT_VMWARE", (detect_vmware()) ? "1" : "0", 0);
> }
>
> static struct builtin builtin_toggle =
> {
> "toggle",
> toggle_func,
> BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
> "toggle [command] args...\n",
> "[command] can be: set - select - trigger - setfirst - iterate\n"
> "toggle set k {KERNEL= $(KERNELSTABLE)} {KERNEL=$(KERNELDEVEL)}\n"
> " (Switches with a shift+k press)\n"
> "toggle select k=1\n"
> " Select DEVEL kernels cause count begins at 0\n"
> "toggle select k=0\n"
> " Select stable kernel\n"
> "toggle set K {var1=val1,var2=val2} {var1=val3,var2=val4}\n"
> " you can put more commands in a block also\n"
> "toggle trigger TT_val==1 ...\n"
> " Evaluate the following ... commands if the toggle-trigger value is
set.\n"
> "toggle setfirst k\n"
> " Sets k to its first value (Stable kernel). Error if no value
present.\n"
> "toggle iterate k\n"
> " Sets k to the next value. Error if we're in last value.\n"
>
>
> };
>
> */
>
>
> static char var_expand_line_edit = 1;
>
> char is_var_expand(void)
> {
> return var_expand_line_edit;
> }
>
> /* setgrubdevice */
>
> static int
> setgrubdevice_func (char *arg, int flags)
> {
>
> char map_str[25]; // We should use some cheaper memory such as
menu_entries but I am not very sure
> char *map_ptr = map_str;
> grub_sprintf (map_ptr,"grub_device=");
> if (saved_drive == NETWORK_DRIVE)
> {
> /* Network drive. */
> grub_sprintf (map_ptr,"%s(nd)",map_ptr);
> }
> else if ((cdrom_drive != GRUB_INVALID_DRIVE) &&(saved_drive==cdrom_drive))
> {
> /* cdrom drive */
> grub_sprintf (map_ptr,"%s(cd)",map_ptr);
> }
> else if (saved_drive & 0x80)
> {
> /* Hard disk drive. */
> grub_sprintf (map_ptr,"%s(hd%d",map_ptr, saved_drive - 0x80);
>
> if ((saved_partition & 0xFF0000) != 0xFF0000)
> grub_sprintf (map_ptr,"%s,%d",map_ptr, saved_partition >> 16);
>
> if ((saved_partition & 0x00FF00) != 0x00FF00)
> grub_sprintf (map_ptr,"%s,%c",map_ptr, ((saved_partition >> 8) & 0xFF) +
'a');
>
> grub_sprintf (map_ptr,"%s)",map_ptr);
> }
> else
> {
> /* Floppy disk drive. */
> grub_sprintf (map_ptr,"%s(fd%d)",map_ptr, saved_drive);
> }
>
> set_func(map_ptr,1);
>
> return 0; // Everything is fine
>
>
> }
>
> static struct builtin builtin_setgrubdevice =
> {
> "setgrubdevice",
> setgrubdevice_func,
> BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "setgrubdevice",
> "Sets grub device variable to the current root"
> };
>
>
>
> /* usbshift */
>
> static int
> usbshift_func (char *arg, int flags)
> {
> /* Check if we're running inside hd0 thanks to saved_drive*/
> if (saved_drive == 0x80) {
> int i = 0x80;
> char map_str[25]; // We should use some cheaper memory such as
menu_entries but I am not very sure
> char *map_ptr = map_str;
> /* Drives shift */
> grub_sprintf(map_ptr,"(hd%d) (hd%d)",i +1 - 0x80 ,i - 0x80);
> struct geometry geom;
>
> while ((! get_diskinfo (i, &geom))&&(! get_diskinfo (i+1, &geom)))
> {
> if (map_func(map_ptr,1)) return 1;
> i++;
> grub_sprintf(map_ptr,"(hd%d) (hd%d)",i + 1 - 0x80,i - 0x80);
> }
> /* map_func always sets ERRNUM in the last call, so clear it. */
> errnum = ERR_NONE;
> grub_sprintf(map_ptr,"(hd0) (hd%d)",i - 0x80);
> if (map_func(map_ptr,1)) return 1;
> /* saved_drive renamed */
> saved_drive = i;
> /* grub_device renamed */
>
>
> if (saved_drive & 0x80)
> {
> setgrubdevice_func("",1); // Set grub device variable as the root one
> } else return 1; // Saved drive must be a drive at this point!!!
>
>
> /*Let's call the bios to swap drives without rebooting */
>
> check_int13_handler(0); // 0 means that we want the function NOT to modify
the saved drive
> root_func ((var_sprint_buf("$(grub_device)", &i)),1); // i must be a
integer, it does not matter modifying it right now
> boot_drive = saved_drive;
> install_partition = saved_partition;
>
> /* Restore map vector */
> i = 0x80;
> grub_sprintf(map_ptr,"(hd%d) (hd%d)",i - 0x80 ,i - 0x80);
> while ((! get_diskinfo (i, &geom)))
> {
> if (map_func(map_ptr,1)) return 1;
> i++;
> grub_sprintf(map_ptr,"(hd%d) (hd%d)",i - 0x80 ,i - 0x80);
> }
> /* map_func always sets ERRNUM in the last call, so clear it. */
> errnum = ERR_NONE;
>
>
> return 0; // Everything is fine
>
>
> } else return 0; // If there's no hd0 we do not want any error here.
>
> }
>
> static struct builtin builtin_usbshift =
> {
> "usbshift",
> usbshift_func,
> BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
> "usbshift",
> "Shift the devices so that first device is the last one."
> " and then the second one is the first one, the third one"
> " is the second one and so on."
> };
>
>
>
>
> /* The table of builtin commands. Sorted in dictionary order. */
> struct builtin *builtin_table[] =
> {
> &builtin_back,
> &builtin_boot,
> &builtin_call,
> &builtin_cat,
> &builtin_catis,
> &builtin_chainloader,
> // &builtin_cmp, - let's comment the cmp command we do not need it in SGD
> &builtin_color,
> &builtin_configfile,
> &builtin_dd,
> &builtin_default,
> #ifdef GRUB_UTIL
> &builtin_device,
> #endif /* GRUB_UTIL */
> // &builtin_displayapm,
> // &builtin_displaymem,
> #ifdef GRUB_UTIL
> &builtin_dump,
> #endif /* GRUB_UTIL */
> &builtin_echo,
> &builtin_embed,
> &builtin_fallback,
> &builtin_fexists,
> &builtin_find,
> &builtin_findf,
> &builtin_geometry,
> &builtin_gfxmenu,
> &builtin_gfxmenuoff,
> &builtin_halt,
> &builtin_help,
> &builtin_hide,
> &builtin_initrd,
> &builtin_install,
> &builtin_kernel,
> // &builtin_lock, // We do not need lock command in SGD, maybe in a SGD
hd installation :)
> &builtin_makeactive,
> &builtin_map,
> #ifdef USE_MD5_PASSWORDS
> &builtin_md5crypt,
> #endif /* USE_MD5_PASSWORDS */
> &builtin_modaddr,
> &builtin_module,
> &builtin_modulenounzip,
> &builtin_partinfo,
> &builtin_partnewbeta,
> //&builtin_password,
> &builtin_pause,
> &builtin_print,
> #ifdef GRUB_UTIL
> &builtin_quit,
> #endif /* GRUB_UTIL */
> &builtin_read,
> &builtin_reboot,
> &builtin_root,
> &builtin_rootnoverify,
> //&builtin_savedefault,
> &builtin_selectfile,
> &builtin_selecthd,
> &builtin_selectpart,
> &builtin_set,
> &builtin_setgrubdevice,
> //&builtin_setkey,
> &builtin_setup,
> &builtin_timeout,
> &builtin_title,
> // &builtin_toggle,
> &builtin_unhide,
> &builtin_usbshift,
> 0
> };
>
>
sgd_0.9578_partnewbeta.iso
Description: Binary data
builtins.c
Description: Binary data
- Fw: "partnew" Command Writes Wrong Ending Cylinder in MPT, Steve Burtchin, 2007/02/04
- Fw: "partnew" Command Writes Wrong Ending Cylinder in MPT, Steve Burtchin, 2007/02/04
- Fw: "partnew" Command Writes Wrong Ending Cylinder in MPT, Steve Burtchin, 2007/02/04
- Fw: "partnew" Command Writes Wrong Ending Cylinder in MPT, Steve Burtchin, 2007/02/04
- Fw: "partnew" Command Writes Wrong Ending Cylinder in MPT, Steve Burtchin, 2007/02/04
- Fw: "partnew" Command Writes Wrong Ending Cylinder in MPT,
Steve Burtchin <=
- Re: "partnew" Command Writes Wrong Ending Cylinder in MPT, sburtchin, 2007/02/15