bug-grub
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: "partnew" Command Writes Wrong Ending Cylinder in MPT- adrian15 Feb


From: sburtchin
Subject: Re: "partnew" Command Writes Wrong Ending Cylinder in MPT- adrian15 Feb 1, 2007; 6:37am
Date: Thu, 15 Feb 2007 19:35:04 -0800 (PST)

NOTE: Adding message of adrian15 Feb 1, 2007; 6:37am to Nabble thread.

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
-- 
View this message in context: 
http://www.nabble.com/%22partnew%22-Command-Writes-Wrong-Ending-Cylinder-in-MPT-tf2599372.html#a8998458
Sent from the Grub - Bugs mailing list archive at Nabble.com.





reply via email to

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