|
|
/* The default entry. */ | /* The default entry. */ |
int default_entry = 0; | int default_entry = 0; |
/* The fallback entry. */ | /* The fallback entry. */ |
int fallback_entry = -1; |
int fallback_entryno; |
|
int fallback_entries[MAX_FALLBACK_ENTRIES]; |
/* The number of current entry. */ | /* The number of current entry. */ |
int current_entryno; | int current_entryno; |
/* The address for Multiboot command-line buffer. */ | /* The address for Multiboot command-line buffer. */ |
|
|
{ | { |
default_entry = 0; | default_entry = 0; |
password = 0; | password = 0; |
fallback_entry = -1; |
fallback_entryno = -1; |
|
fallback_entries[0] = -1; |
grub_timeout = -1; | grub_timeout = -1; |
} | } |
| |
|
|
} | } |
| |
| |
|
/* blocklist_read_helper nee disk_read_blocklist_func was a nested |
|
* function, to which pointers were taken and exposed globally. Even |
|
* in the GNU-C nested functions extension, they have local linkage, |
|
* and aren't guaranteed to be accessable *at all* outside of their |
|
* containing scope. |
|
* |
|
* Above and beyond all of that, the variables within blocklist_func_context |
|
* are originally local variables, with local (not even static) linkage, |
|
* from within blocklist_func. These were each referenced by |
|
* disk_read_blocklist_func, which is only called from other functions |
|
* through a globally scoped pointer. |
|
* |
|
* The documentation in GCC actually uses the words "all hell will break |
|
* loose" to describe this scenario. |
|
* |
|
* Also, "start_sector" was also used uninitialized, but gcc doesn't warn |
|
* about it (possibly because of the scoping madness?) |
|
*/ |
|
|
|
static struct { |
|
int start_sector; |
|
int num_sectors; |
|
int num_entries; |
|
int last_length; |
|
} blocklist_func_context = { |
|
.start_sector = 0, |
|
.num_sectors = 0, |
|
.num_entries = 0, |
|
.last_length = 0 |
|
}; |
|
|
|
/* Collect contiguous blocks into one entry as many as possible, |
|
and print the blocklist notation on the screen. */ |
|
static void |
|
blocklist_read_helper (int sector, int offset, int length) |
|
{ |
|
int *start_sector = &blocklist_func_context.start_sector; |
|
int *num_sectors = &blocklist_func_context.num_sectors; |
|
int *num_entries = &blocklist_func_context.num_entries; |
|
int *last_length = &blocklist_func_context.last_length; |
|
|
|
if (*num_sectors > 0) |
|
{ |
|
if (*start_sector + *num_sectors == sector |
|
&& offset == 0 && *last_length == SECTOR_SIZE) |
|
{ |
|
*num_sectors++; |
|
*last_length = length; |
|
return; |
|
} |
|
else |
|
{ |
|
if (*last_length == SECTOR_SIZE) |
|
grub_printf ("%s%d+%d", *num_entries ? "," : "", |
|
*start_sector - part_start, *num_sectors); |
|
else if (*num_sectors > 1) |
|
grub_printf ("%s%d+%d,%d[0-%d]", *num_entries ? "," : "", |
|
*start_sector - part_start, *num_sectors-1, |
|
*start_sector + *num_sectors-1 - part_start, |
|
*last_length); |
|
else |
|
grub_printf ("%s%d[0-%d]", *num_entries ? "," : "", |
|
*start_sector - part_start, *last_length); |
|
*num_entries++; |
|
*num_sectors = 0; |
|
} |
|
} |
|
|
|
if (offset > 0) |
|
{ |
|
grub_printf("%s%d[%d-%d]", *num_entries ? "," : "", |
|
sector-part_start, offset, offset+length); |
|
*num_entries++; |
|
} |
|
else |
|
{ |
|
*start_sector = sector; |
|
*num_sectors = 1; |
|
*last_length = length; |
|
} |
|
} |
|
|
/* blocklist */ | /* blocklist */ |
static int | static int |
blocklist_func (char *arg, int flags) | blocklist_func (char *arg, int flags) |
{ | { |
char *dummy = (char *) RAW_ADDR (0x100000); | char *dummy = (char *) RAW_ADDR (0x100000); |
int start_sector; |
|
int num_sectors = 0; |
|
int num_entries = 0; |
|
int last_length = 0; |
|
|
|
/* Collect contiguous blocks into one entry as many as possible, |
|
and print the blocklist notation on the screen. */ |
|
static void disk_read_blocklist_func (int sector, int offset, int length) |
|
{ |
|
if (num_sectors > 0) |
|
{ |
|
if (start_sector + num_sectors == sector |
|
&& offset == 0 && last_length == SECTOR_SIZE) |
|
{ |
|
num_sectors++; |
|
last_length = length; |
|
return; |
|
} |
|
else |
|
{ |
|
if (last_length == SECTOR_SIZE) |
|
grub_printf ("%s%d+%d", num_entries ? "," : "", |
|
start_sector - part_start, num_sectors); |
|
else if (num_sectors > 1) |
|
grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "", |
|
start_sector - part_start, num_sectors-1, |
|
start_sector + num_sectors-1 - part_start, |
|
last_length); |
|
else |
|
grub_printf ("%s%d[0-%d]", num_entries ? "," : "", |
|
start_sector - part_start, last_length); |
|
num_entries++; |
|
num_sectors = 0; |
|
} |
|
} |
|
|
|
if (offset > 0) |
|
{ |
|
grub_printf("%s%d[%d-%d]", num_entries ? "," : "", |
|
sector-part_start, offset, offset+length); |
|
num_entries++; |
|
} |
|
else |
|
{ |
|
start_sector = sector; |
|
num_sectors = 1; |
|
last_length = length; |
|
} |
|
} |
|
| |
|
int *start_sector = &blocklist_func_context.start_sector; |
|
int *num_sectors = &blocklist_func_context.num_sectors; |
|
int *num_entries = &blocklist_func_context.num_entries; |
|
|
/* Open the file. */ | /* Open the file. */ |
if (! grub_open (arg)) | if (! grub_open (arg)) |
return 1; | return 1; |
|
|
grub_printf (")"); | grub_printf (")"); |
| |
/* Read in the whole file to DUMMY. */ | /* Read in the whole file to DUMMY. */ |
disk_read_hook = disk_read_blocklist_func; |
disk_read_hook = blocklist_read_helper; |
if (! grub_read (dummy, -1)) | if (! grub_read (dummy, -1)) |
goto fail; | goto fail; |
| |
/* The last entry may not be printed yet. Don't check if it is a | /* The last entry may not be printed yet. Don't check if it is a |
* full sector, since it doesn't matter if we read too much. */ | * full sector, since it doesn't matter if we read too much. */ |
if (num_sectors > 0) |
if (*num_sectors > 0) |
grub_printf ("%s%d+%d", num_entries ? "," : "", |
grub_printf ("%s%d+%d", *num_entries ? "," : "", |
start_sector - part_start, num_sectors); |
*start_sector - part_start, *num_sectors); |
| |
grub_printf ("\n"); | grub_printf ("\n"); |
| |
|
|
"white" | "white" |
}; | }; |
| |
|
auto int color_number (char *str); |
|
|
/* Convert the color name STR into the magical number. */ | /* Convert the color name STR into the magical number. */ |
static int color_number (char *str) |
auto int color_number (char *str) |
{ | { |
char *ptr; | char *ptr; |
int i; | int i; |
|
|
}; | }; |
#endif /* SUPPORT_NETBOOT */ | #endif /* SUPPORT_NETBOOT */ |
| |
|
static int terminal_func (char *arg, int flags); |
|
|
|
#ifdef SUPPORT_GRAPHICS |
|
|
|
static int splashimage_func(char *arg, int flags) { |
|
char splashimage[64]; |
|
int i; |
|
|
|
/* filename can only be 64 characters due to our buffer size */ |
|
if (strlen(arg) > 63) |
|
return 1; |
|
if (flags == BUILTIN_CMDLINE) { |
|
if (!grub_open(arg)) |
|
return 1; |
|
grub_close(); |
|
} |
|
|
|
strcpy(splashimage, arg); |
|
|
|
/* get rid of TERM_NEED_INIT from the graphics terminal. */ |
|
for (i = 0; term_table[i].name; i++) { |
|
if (grub_strcmp (term_table[i].name, "graphics") == 0) { |
|
term_table[i].flags &= ~TERM_NEED_INIT; |
|
break; |
|
} |
|
} |
|
|
|
graphics_set_splash(splashimage); |
|
|
|
if (flags == BUILTIN_CMDLINE && graphics_inited) { |
|
graphics_end(); |
|
graphics_init(); |
|
graphics_cls(); |
|
} |
|
|
|
/* FIXME: should we be explicitly switching the terminal as a |
|
* side effect here? */ |
|
terminal_func("graphics", flags); |
|
|
|
return 0; |
|
} |
|
|
|
static struct builtin builtin_splashimage = |
|
{ |
|
"splashimage", |
|
splashimage_func, |
|
BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, |
|
"splashimage FILE", |
|
"Load FILE as the background image when in graphics mode." |
|
}; |
|
|
|
|
|
/* foreground */ |
|
static int |
|
foreground_func(char *arg, int flags) |
|
{ |
|
if (grub_strlen(arg) == 6) { |
|
int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; |
|
int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; |
|
int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; |
|
|
|
foreground = (r << 16) | (g << 8) | b; |
|
if (graphics_inited) |
|
graphics_set_palette(15, r, g, b); |
|
|
|
return (0); |
|
} |
|
|
|
return (1); |
|
} |
|
|
|
static struct builtin builtin_foreground = |
|
{ |
|
"foreground", |
|
foreground_func, |
|
BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, |
|
"foreground RRGGBB", |
|
"Sets the foreground color when in graphics mode." |
|
"RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." |
|
}; |
|
|
|
|
|
/* background */ |
|
static int |
|
background_func(char *arg, int flags) |
|
{ |
|
if (grub_strlen(arg) == 6) { |
|
int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2; |
|
int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2; |
|
int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2; |
|
|
|
background = (r << 16) | (g << 8) | b; |
|
if (graphics_inited) |
|
graphics_set_palette(0, r, g, b); |
|
return (0); |
|
} |
|
|
|
return (1); |
|
} |
|
|
|
static struct builtin builtin_background = |
|
{ |
|
"background", |
|
background_func, |
|
BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, |
|
"background RRGGBB", |
|
"Sets the background color when in graphics mode." |
|
"RR is red, GG is green, and BB blue. Numbers must be in hexadecimal." |
|
}; |
|
|
|
#endif /* SUPPORT_GRAPHICS */ |
|
|
|
|
|
/* clear */ |
|
static int |
|
clear_func() |
|
{ |
|
if (current_term->cls) |
|
current_term->cls(); |
|
|
|
return 0; |
|
} |
|
|
|
static struct builtin builtin_clear = |
|
{ |
|
"clear", |
|
clear_func, |
|
BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
|
"clear", |
|
"Clear the screen" |
|
}; |
|
|
| |
/* displayapm */ | /* displayapm */ |
static int | static int |
|
|
static int | static int |
fallback_func (char *arg, int flags) | fallback_func (char *arg, int flags) |
{ | { |
if (! safe_parse_maxint (&arg, &fallback_entry)) |
int i = 0; |
return 1; |
|
|
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; | return 0; |
} | } |
| |
|
|
fallback_func, | fallback_func, |
BUILTIN_MENU, | BUILTIN_MENU, |
#if 0 | #if 0 |
"fallback NUM", |
"fallback NUM...", |
"Go into unattended boot mode: if the default boot entry has any" | "Go into unattended boot mode: if the default boot entry has any" |
" errors, instead of waiting for the user to do anything, it" | " errors, instead of waiting for the user to do anything, it" |
" immediately starts over using the NUM entry (same numbering as the" | " immediately starts over using the NUM entry (same numbering as the" |
|
|
| |
| |
/* install */ | /* install */ |
|
static struct { |
|
int saved_sector; |
|
int installaddr; |
|
int installlist; |
|
char *stage2_first_buffer; |
|
} install_func_context = { |
|
.saved_sector = 0, |
|
.installaddr = 0, |
|
.installlist = 0, |
|
.stage2_first_buffer = NULL, |
|
}; |
|
|
|
/* Save the first sector of Stage2 in STAGE2_SECT. */ |
|
/* Formerly disk_read_savesect_func with local scope inside install_func */ |
|
static void |
|
install_savesect_helper(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; |
|
|
|
install_func_context.saved_sector = sector; |
|
} |
|
|
|
/* Write SECTOR to INSTALLLIST, and update INSTALLADDR and INSTALLSECT. */ |
|
/* Formerly disk_read_blocklist_func with local scope inside install_func */ |
|
static void |
|
install_blocklist_helper (int sector, int offset, int length) |
|
{ |
|
int *installaddr = &install_func_context.installaddr; |
|
int *installlist = &install_func_context.installlist; |
|
char **stage2_first_buffer = &install_func_context.stage2_first_buffer; |
|
/* Was the last sector full? */ |
|
static int last_length = SECTOR_SIZE; |
|
|
|
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; |
|
} |
|
|
static int | static int |
install_func (char *arg, int flags) | install_func (char *arg, int flags) |
{ | { |
|
|
char *stage1_buffer = (char *) RAW_ADDR (0x100000); | char *stage1_buffer = (char *) RAW_ADDR (0x100000); |
char *stage2_buffer = stage1_buffer + SECTOR_SIZE; | char *stage2_buffer = stage1_buffer + SECTOR_SIZE; |
char *old_sect = stage2_buffer + SECTOR_SIZE; | char *old_sect = stage2_buffer + SECTOR_SIZE; |
char *stage2_first_buffer = old_sect + SECTOR_SIZE; |
/* stage2_first_buffer used to be defined as: |
char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; |
* char *stage2_first_buffer = old_sect + SECTOR_SIZE; */ |
|
char **stage2_first_buffer = &install_func_context.stage2_first_buffer; |
|
/* and stage2_second_buffer was: |
|
* char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; */ |
|
char *stage2_second_buffer = old_sect + SECTOR_SIZE + SECTOR_SIZE; |
/* XXX: Probably SECTOR_SIZE is reasonable. */ | /* XXX: Probably SECTOR_SIZE is reasonable. */ |
char *config_filename = stage2_second_buffer + SECTOR_SIZE; | char *config_filename = stage2_second_buffer + SECTOR_SIZE; |
char *dummy = config_filename + SECTOR_SIZE; | char *dummy = config_filename + SECTOR_SIZE; |
int new_drive = 0xFF; |
int new_drive = GRUB_INVALID_DRIVE; |
int dest_drive, dest_partition, dest_sector; | int dest_drive, dest_partition, dest_sector; |
int src_drive, src_partition, src_part_start; | int src_drive, src_partition, src_part_start; |
int i; | int i; |
struct geometry dest_geom, src_geom; | struct geometry dest_geom, src_geom; |
int saved_sector; |
int *saved_sector = &install_func_context.saved_sector; |
int stage2_first_sector, stage2_second_sector; | int stage2_first_sector, stage2_second_sector; |
char *ptr; | char *ptr; |
int installaddr, installlist; |
int *installaddr = &install_func_context.installaddr; |
|
int *installlist = &install_func_context.installlist; |
/* Point to the location of the name of a configuration file in Stage 2. */ | /* Point to the location of the name of a configuration file in Stage 2. */ |
char *config_file_location; | char *config_file_location; |
/* If FILE is a Stage 1.5? */ | /* If FILE is a Stage 1.5? */ |
|
|
int is_open = 0; | int is_open = 0; |
/* If LBA is forced? */ | /* If LBA is forced? */ |
int is_force_lba = 0; | int is_force_lba = 0; |
/* Was the last sector full? */ |
|
int last_length = SECTOR_SIZE; |
|
|
|
#ifdef GRUB_UTIL | #ifdef GRUB_UTIL |
/* If the Stage 2 is in a partition mounted by an OS, this will store | /* If the Stage 2 is in a partition mounted by an OS, this will store |
the filename under the OS. */ | the filename under the OS. */ |
char *stage2_os_file = 0; | char *stage2_os_file = 0; |
#endif /* GRUB_UTIL */ | #endif /* GRUB_UTIL */ |
|
|
/* Save the first sector of Stage2 in STAGE2_SECT. */ |
|
static 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; |
*stage2_first_buffer = old_sect + SECTOR_SIZE; |
} |
|
|
|
/* Write SECTOR to INSTALLLIST, and update INSTALLADDR and |
|
INSTALLSECT. */ |
|
static 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. */ | /* First, check the GNU-style long option. */ |
while (1) | while (1) |
|
|
addr = skip_to (0, file); | addr = skip_to (0, file); |
| |
/* Get the installation address. */ | /* Get the installation address. */ |
if (! safe_parse_maxint (&addr, &installaddr)) |
if (! safe_parse_maxint (&addr, installaddr)) |
{ | { |
/* ADDR is not specified. */ | /* ADDR is not specified. */ |
installaddr = 0; |
*installaddr = 0; |
ptr = addr; | ptr = addr; |
errnum = 0; | errnum = 0; |
} | } |
|
|
= (dest_drive & BIOS_FLAG_FIXED_DISK); | = (dest_drive & BIOS_FLAG_FIXED_DISK); |
| |
/* Read the first sector of Stage 2. */ | /* Read the first sector of Stage 2. */ |
disk_read_hook = disk_read_savesect_func; |
disk_read_hook = install_savesect_helper; |
if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE) |
if (grub_read (*stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE) |
goto fail; | goto fail; |
| |
stage2_first_sector = saved_sector; |
stage2_first_sector = *saved_sector; |
| |
/* Read the second sector of Stage 2. */ | /* Read the second sector of Stage 2. */ |
if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE) | if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE) |
goto fail; | goto fail; |
| |
stage2_second_sector = saved_sector; |
stage2_second_sector = *saved_sector; |
| |
/* Check for the version of Stage 2. */ | /* Check for the version of Stage 2. */ |
if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS)) | if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS)) |
|
|
| |
/* If INSTALLADDR is not specified explicitly in the command-line, | /* If INSTALLADDR is not specified explicitly in the command-line, |
determine it by the Stage 2 id. */ | determine it by the Stage 2 id. */ |
if (! installaddr) |
if (! *installaddr) |
{ | { |
if (! is_stage1_5) | if (! is_stage1_5) |
/* Stage 2. */ | /* Stage 2. */ |
installaddr = 0x8000; |
*installaddr = 0x8000; |
else | else |
/* Stage 1.5. */ | /* Stage 1.5. */ |
installaddr = 0x2000; |
*installaddr = 0x2000; |
} | } |
| |
*((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR)) | *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR)) |
= stage2_first_sector; | = stage2_first_sector; |
*((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS)) | *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS)) |
= installaddr; |
= *installaddr; |
*((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT)) | *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT)) |
= installaddr >> 4; |
= *installaddr >> 4; |
| |
i = (int) stage2_first_buffer + SECTOR_SIZE - 4; |
i = (int) *stage2_first_buffer + SECTOR_SIZE - 4; |
while (*((unsigned long *) i)) | while (*((unsigned long *) i)) |
{ | { |
if (i < (int) stage2_first_buffer |
if (i < (int) *stage2_first_buffer |
|| (*((int *) (i - 4)) & 0x80000000) | || (*((int *) (i - 4)) & 0x80000000) |
|| *((unsigned short *) i) >= 0xA00 | || *((unsigned short *) i) >= 0xA00 |
|| *((short *) (i + 2)) == 0) | || *((short *) (i + 2)) == 0) |
|
|
i -= 8; | i -= 8; |
} | } |
| |
installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4; |
*installlist = (int) *stage2_first_buffer + SECTOR_SIZE + 4; |
installaddr += SECTOR_SIZE; |
*installaddr += SECTOR_SIZE; |
| |
/* Read the whole of Stage2 except for the first sector. */ | /* Read the whole of Stage2 except for the first sector. */ |
grub_seek (SECTOR_SIZE); | grub_seek (SECTOR_SIZE); |
| |
disk_read_hook = disk_read_blocklist_func; |
disk_read_hook = install_blocklist_helper; |
if (! grub_read (dummy, -1)) | if (! grub_read (dummy, -1)) |
goto fail; | goto fail; |
| |
|
|
/* If the drive where the Stage 2 resides is the same as | /* If the drive where the Stage 2 resides is the same as |
the one where the Stage 1.5 resides, do not embed the | the one where the Stage 1.5 resides, do not embed the |
drive number. */ | drive number. */ |
current_drive = 0xFF; |
current_drive = GRUB_INVALID_DRIVE; |
} | } |
| |
device = (current_drive << 24) | current_partition; | device = (current_drive << 24) | current_partition; |
|
|
/* Skip the first sector. */ | /* Skip the first sector. */ |
grub_seek (SECTOR_SIZE); | grub_seek (SECTOR_SIZE); |
| |
disk_read_hook = disk_read_savesect_func; |
disk_read_hook = install_savesect_helper; |
if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE) | if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE) |
goto fail; | goto fail; |
| |
|
|
else | else |
#endif /* GRUB_UTIL */ | #endif /* GRUB_UTIL */ |
{ | { |
if (! devwrite (saved_sector - part_start, 1, stage2_buffer)) |
if (! devwrite (*saved_sector - part_start, 1, stage2_buffer)) |
goto fail; | goto fail; |
} | } |
} | } |
|
|
goto fail; | goto fail; |
} | } |
| |
if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) |
if (fwrite (*stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) |
{ | { |
fclose (fp); | fclose (fp); |
errnum = ERR_WRITE; | errnum = ERR_WRITE; |
|
|
goto fail; | goto fail; |
| |
if (! devwrite (stage2_first_sector - src_part_start, 1, | if (! devwrite (stage2_first_sector - src_part_start, 1, |
stage2_first_buffer)) |
*stage2_first_buffer)) |
goto fail; | goto fail; |
| |
if (! devwrite (stage2_second_sector - src_part_start, 1, | if (! devwrite (stage2_second_sector - src_part_start, 1, |
|
|
savedefault_func (char *arg, int flags) | savedefault_func (char *arg, int flags) |
{ | { |
#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL) | #if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL) |
char buffer[512]; |
unsigned long tmp_drive = saved_drive; |
int *entryno_ptr; |
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 | /* This command is only useful when you boot an entry from the menu |
interface. */ | interface. */ |
|
|
errnum = ERR_UNRECOGNIZED; | errnum = ERR_UNRECOGNIZED; |
return 1; | return 1; |
} | } |
|
|
/* Get the geometry of the boot drive (i.e. the disk which contains |
|
this stage2). */ |
|
if (get_diskinfo (boot_drive, &buf_geom)) |
|
{ |
|
errnum = ERR_NO_DISK; |
|
return 1; |
|
} |
|
| |
/* Load the second sector of this stage2. */ |
/* Determine a saved entry number. */ |
if (! rawread (boot_drive, install_second_sector, 0, SECTOR_SIZE, buffer)) |
if (*arg) |
{ | { |
return 1; |
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; |
|
} |
| |
/* Sanity check. */ |
entryno = fallback_entries[index]; |
if (buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2 |
} |
|| *((short *) (buffer + STAGE2_VER_MAJ_OFFS)) != COMPAT_VERSION) |
else if (! safe_parse_maxint (&arg, &entryno)) |
{ |
return 1; |
errnum = ERR_BAD_VERSION; |
|
return 1; |
|
} | } |
|
else |
entryno_ptr = (int *) (buffer + STAGE2_SAVED_ENTRYNO); |
entryno = current_entryno; |
| |
/* Check if the saved entry number differs from current entry number. */ |
/* Open the default file. */ |
if (*entryno_ptr != current_entryno) |
saved_drive = boot_drive; |
{ |
saved_partition = install_partition; |
/* Overwrite the saved entry number. */ |
if (grub_open (default_file)) |
*entryno_ptr = current_entryno; |
{ |
|
int len; |
|
|
|
disk_read_hook = disk_read_savesect_func; |
|
len = grub_read (buf, sizeof (buf)); |
|
disk_read_hook = 0; |
|
grub_close (); |
| |
/* Save the image in the disk. */ |
if (len != sizeof (buf)) |
if (! rawwrite (boot_drive, install_second_sector, buffer)) |
{ |
return 1; |
/* 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. */ | /* Clear the cache. */ |
buf_track = -1; | buf_track = -1; |
} | } |
| |
return 0; |
fail: |
|
saved_drive = tmp_drive; |
|
saved_partition = tmp_partition; |
|
return errnum; |
#else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ | #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ |
errnum = ERR_UNRECOGNIZED; | errnum = ERR_UNRECOGNIZED; |
return 1; | return 1; |
|
|
"savedefault", | "savedefault", |
savedefault_func, | savedefault_func, |
BUILTIN_CMDLINE, | BUILTIN_CMDLINE, |
"savedefault", |
"savedefault [NUM | `fallback']", |
"Save the current entry as the default boot entry." |
"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." |
}; | }; |
| |
| |
|
|
int to_code, from_code; | int to_code, from_code; |
int map_in_interrupt = 0; | int map_in_interrupt = 0; |
| |
static int find_key_code (char *key) |
auto int find_key_code (char *key); |
|
auto int find_ascii_code (char *key); |
|
|
|
auto int find_key_code (char *key) |
{ | { |
int i; | int i; |
| |
|
|
return 0; | return 0; |
} | } |
| |
static int find_ascii_code (char *key) |
auto int find_ascii_code (char *key) |
{ | { |
int i; | int i; |
| |
|
|
{ | { |
{"ext2fs", "/e2fs_stage1_5"}, | {"ext2fs", "/e2fs_stage1_5"}, |
{"fat", "/fat_stage1_5"}, | {"fat", "/fat_stage1_5"}, |
|
{"ufs2", "/ufs2_stage1_5"}, |
{"ffs", "/ffs_stage1_5"}, | {"ffs", "/ffs_stage1_5"}, |
|
{"iso9660", "/iso9660_stage1_5"}, |
{"jfs", "/jfs_stage1_5"}, | {"jfs", "/jfs_stage1_5"}, |
{"minix", "/minix_stage1_5"}, | {"minix", "/minix_stage1_5"}, |
{"reiserfs", "/reiserfs_stage1_5"}, | {"reiserfs", "/reiserfs_stage1_5"}, |
|
|
}; | }; |
| |
| |
#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) |
#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS) |
/* terminal */ | /* terminal */ |
static int | static int |
terminal_func (char *arg, int flags) | terminal_func (char *arg, int flags) |
|
|
end: | end: |
current_term = term_table + default_term; | current_term = term_table + default_term; |
current_term->flags = term_flags; | current_term->flags = term_flags; |
|
|
if (lines) | if (lines) |
max_lines = lines; | max_lines = lines; |
else | else |
/* 24 would be a good default value. */ |
max_lines = current_term->max_lines; |
max_lines = 24; |
|
|
|
/* If the interface is currently the command-line, | /* If the interface is currently the command-line, |
restart it to repaint the screen. */ | restart it to repaint the screen. */ |
if (current_term != prev_term && (flags & BUILTIN_CMDLINE)) |
if ((current_term != prev_term) && (flags & BUILTIN_CMDLINE)){ |
|
if (prev_term->shutdown) |
|
prev_term->shutdown(); |
|
if (current_term->startup) |
|
current_term->startup(); |
grub_longjmp (restart_cmdline_env, 0); | grub_longjmp (restart_cmdline_env, 0); |
|
} |
| |
return 0; | return 0; |
} | } |
|
|
"terminal", | "terminal", |
terminal_func, | terminal_func, |
BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, | BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST, |
"terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules]", |
"terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules] [graphics]", |
"Select a terminal. When multiple terminals are specified, wait until" | "Select a terminal. When multiple terminals are specified, wait until" |
" you push any key to continue. If both console and serial are specified," | " you push any key to continue. If both console and serial are specified," |
" the terminal to which you input a key first will be selected. If no" | " the terminal to which you input a key first will be selected. If no" |
|
|
" seconds. The option --lines specifies the maximum number of lines." | " seconds. The option --lines specifies the maximum number of lines." |
" The option --silent is used to suppress messages." | " The option --silent is used to suppress messages." |
}; | }; |
#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */ |
#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */ |
| |
| |
#ifdef SUPPORT_SERIAL | #ifdef SUPPORT_SERIAL |
|
|
/* The table of builtin commands. Sorted in dictionary order. */ | /* The table of builtin commands. Sorted in dictionary order. */ |
struct builtin *builtin_table[] = | struct builtin *builtin_table[] = |
{ | { |
|
#ifdef SUPPORT_GRAPHICS |
|
&builtin_background, |
|
#endif |
&builtin_blocklist, | &builtin_blocklist, |
&builtin_boot, | &builtin_boot, |
#ifdef SUPPORT_NETBOOT | #ifdef SUPPORT_NETBOOT |
|
|
#endif /* SUPPORT_NETBOOT */ | #endif /* SUPPORT_NETBOOT */ |
&builtin_cat, | &builtin_cat, |
&builtin_chainloader, | &builtin_chainloader, |
|
&builtin_clear, |
&builtin_cmp, | &builtin_cmp, |
&builtin_color, | &builtin_color, |
&builtin_configfile, | &builtin_configfile, |
|
|
&builtin_embed, | &builtin_embed, |
&builtin_fallback, | &builtin_fallback, |
&builtin_find, | &builtin_find, |
|
#ifdef SUPPORT_GRAPHICS |
|
&builtin_foreground, |
|
#endif |
&builtin_fstest, | &builtin_fstest, |
&builtin_geometry, | &builtin_geometry, |
&builtin_halt, | &builtin_halt, |
|
|
#endif /* SUPPORT_SERIAL */ | #endif /* SUPPORT_SERIAL */ |
&builtin_setkey, | &builtin_setkey, |
&builtin_setup, | &builtin_setup, |
#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) |
#ifdef SUPPORT_GRAPHICS |
|
&builtin_splashimage, |
|
#endif /* SUPPORT_GRAPHICS */ |
|
#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS) |
&builtin_terminal, | &builtin_terminal, |
#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */ |
#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */ |
#ifdef SUPPORT_SERIAL | #ifdef SUPPORT_SERIAL |
&builtin_terminfo, | &builtin_terminfo, |
#endif /* SUPPORT_SERIAL */ | #endif /* SUPPORT_SERIAL */ |