bug-grub
[Top][All Lists]
Advanced

[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 (&sector, &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
> };
>
>

Attachment: sgd_0.9578_partnewbeta.iso
Description: Binary data

Attachment: builtins.c
Description: Binary data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]