Home | History | Annotate | Download | only in stage2
      1 /* builtins.c - the GRUB builtin commands */
      2 /*
      3  *  GRUB  --  GRand Unified Bootloader
      4  *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
      5  *
      6  *  This program is free software; you can redistribute it and/or modify
      7  *  it under the terms of the GNU General Public License as published by
      8  *  the Free Software Foundation; either version 2 of the License, or
      9  *  (at your option) any later version.
     10  *
     11  *  This program is distributed in the hope that it will be useful,
     12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *  GNU General Public License for more details.
     15  *
     16  *  You should have received a copy of the GNU General Public License
     17  *  along with this program; if not, write to the Free Software
     18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     19  */
     20 
     21 /* Include stdio.h before shared.h, because we can't define
     22    WITHOUT_LIBC_STUBS here.  */
     23 #ifdef GRUB_UTIL
     24 # include <stdio.h>
     25 #endif
     26 
     27 #include <shared.h>
     28 #include <filesys.h>
     29 #include <term.h>
     30 
     31 #ifdef SUPPORT_NETBOOT
     32 # define GRUB	1
     33 # include <etherboot.h>
     34 #endif
     35 
     36 #ifdef SUPPORT_SERIAL
     37 # include <serial.h>
     38 # include <terminfo.h>
     39 #endif
     40 
     41 #ifdef GRUB_UTIL
     42 # include <device.h>
     43 #else /* ! GRUB_UTIL */
     44 # include <apic.h>
     45 # include <smp-imps.h>
     46 #endif /* ! GRUB_UTIL */
     47 
     48 #ifdef USE_MD5_PASSWORDS
     49 # include <md5.h>
     50 #endif
     51 
     52 /* The type of kernel loaded.  */
     53 kernel_t kernel_type;
     54 /* The boot device.  */
     55 static int bootdev;
     56 /* True when the debug mode is turned on, and false
     57    when it is turned off.  */
     58 int debug = 0;
     59 /* The default entry.  */
     60 int default_entry = 0;
     61 /* The fallback entry.  */
     62 int fallback_entryno;
     63 int fallback_entries[MAX_FALLBACK_ENTRIES];
     64 /* The number of current entry.  */
     65 int current_entryno;
     66 /* The address for Multiboot command-line buffer.  */
     67 static char *mb_cmdline;
     68 /* Whether or not the user loaded a custom command line */
     69 static unsigned char cmdline_loaded = 0;
     70 /* The password.  */
     71 char *password;
     72 /* The password type.  */
     73 password_t password_type;
     74 /* The flag for indicating that the user is authoritative.  */
     75 int auth = 0;
     76 /* The timeout.  */
     77 int grub_timeout = -1;
     78 /* Whether to show the menu or not.  */
     79 int show_menu = 1;
     80 /* The BIOS drive map.  */
     81 static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];
     82 
     83 /* Prototypes for allowing straightfoward calling of builtins functions
     84    inside other functions.  */
     85 static int configfile_func (char *arg, int flags);
     86 
     87 /* Initialize the data for builtins.  */
     88 void
     89 init_builtins (void)
     90 {
     91   kernel_type = KERNEL_TYPE_NONE;
     92   /* BSD and chainloading evil hacks!  */
     93   bootdev = set_bootdev (0);
     94   mb_cmdline = (char *) MB_CMDLINE_BUF;
     95 }
     96 
     97 /* Initialize the data for the configuration file.  */
     98 void
     99 init_config (void)
    100 {
    101   default_entry = 0;
    102   password = 0;
    103   fallback_entryno = -1;
    104   fallback_entries[0] = -1;
    105   grub_timeout = -1;
    106 }
    107 
    108 /* Check a password for correctness.  Returns 0 if password was
    109    correct, and a value != 0 for error, similarly to strcmp. */
    110 int
    111 check_password (char *entered, char* expected, password_t type)
    112 {
    113   switch (type)
    114     {
    115     case PASSWORD_PLAIN:
    116       return strcmp (entered, expected);
    117 
    118 #ifdef USE_MD5_PASSWORDS
    119     case PASSWORD_MD5:
    120       return check_md5_password (entered, expected);
    121 #endif
    122     default:
    123       /* unsupported password type: be secure */
    124       return 1;
    125     }
    126 }
    127 
    128 /* Print which sector is read when loading a file.  */
    129 static void
    130 disk_read_print_func (int sector, int offset, int length)
    131 {
    132   grub_printf ("[%d,%d,%d]", sector, offset, length);
    133 }
    134 
    135 
    136 /* blocklist */
    138 static int
    139 blocklist_func (char *arg, int flags)
    140 {
    141   char *dummy = (char *) RAW_ADDR (0x100000);
    142   int start_sector;
    143   int num_sectors = 0;
    144   int num_entries = 0;
    145   int last_length = 0;
    146 
    147   auto void disk_read_blocklist_func (int sector, int offset, int length);
    148 
    149   /* Collect contiguous blocks into one entry as many as possible,
    150      and print the blocklist notation on the screen.  */
    151   auto void disk_read_blocklist_func (int sector, int offset, int length)
    152     {
    153       if (num_sectors > 0)
    154 	{
    155 	  if (start_sector + num_sectors == sector
    156 	      && offset == 0 && last_length == SECTOR_SIZE)
    157 	    {
    158 	      num_sectors++;
    159 	      last_length = length;
    160 	      return;
    161 	    }
    162 	  else
    163 	    {
    164 	      if (last_length == SECTOR_SIZE)
    165 		grub_printf ("%s%d+%d", num_entries ? "," : "",
    166 			     start_sector - part_start, num_sectors);
    167 	      else if (num_sectors > 1)
    168 		grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
    169 			     start_sector - part_start, num_sectors-1,
    170 			     start_sector + num_sectors-1 - part_start,
    171 			     last_length);
    172 	      else
    173 		grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
    174 			     start_sector - part_start, last_length);
    175 	      num_entries++;
    176 	      num_sectors = 0;
    177 	    }
    178 	}
    179 
    180       if (offset > 0)
    181 	{
    182 	  grub_printf("%s%d[%d-%d]", num_entries ? "," : "",
    183 		      sector-part_start, offset, offset+length);
    184 	  num_entries++;
    185 	}
    186       else
    187 	{
    188 	  start_sector = sector;
    189 	  num_sectors = 1;
    190 	  last_length = length;
    191 	}
    192     }
    193 
    194   /* Open the file.  */
    195   if (! grub_open (arg))
    196     return 1;
    197 
    198   /* Print the device name.  */
    199   grub_printf ("(%cd%d",
    200 	       (current_drive & 0x80) ? 'h' : 'f',
    201 	       current_drive & ~0x80);
    202 
    203   if ((current_partition & 0xFF0000) != 0xFF0000)
    204     grub_printf (",%d", (current_partition >> 16) & 0xFF);
    205 
    206   if ((current_partition & 0x00FF00) != 0x00FF00)
    207     grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
    208 
    209   grub_printf (")");
    210 
    211   /* Read in the whole file to DUMMY.  */
    212   disk_read_hook = disk_read_blocklist_func;
    213   if (! grub_read (dummy, -1))
    214     goto fail;
    215 
    216   /* The last entry may not be printed yet.  Don't check if it is a
    217    * full sector, since it doesn't matter if we read too much. */
    218   if (num_sectors > 0)
    219     grub_printf ("%s%d+%d", num_entries ? "," : "",
    220 		 start_sector - part_start, num_sectors);
    221 
    222   grub_printf ("\n");
    223 
    224  fail:
    225   disk_read_hook = 0;
    226   grub_close ();
    227   return errnum;
    228 }
    229 
    230 static struct builtin builtin_blocklist =
    231 {
    232   "blocklist",
    233   blocklist_func,
    234   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
    235   "blocklist FILE",
    236   "Print the blocklist notation of the file FILE."
    237 };
    238 
    239 /* boot */
    240 static int
    241 boot_func (char *arg, int flags)
    242 {
    243   /* Clear the int15 handler if we can boot the kernel successfully.
    244      This assumes that the boot code never fails only if KERNEL_TYPE is
    245      not KERNEL_TYPE_NONE. Is this assumption is bad?  */
    246   if (kernel_type != KERNEL_TYPE_NONE)
    247     unset_int15_handler ();
    248 
    249 #ifdef SUPPORT_NETBOOT
    250   /* Shut down the networking.  */
    251   cleanup_net ();
    252 #endif
    253 
    254   switch (kernel_type)
    255     {
    256     case KERNEL_TYPE_FREEBSD:
    257     case KERNEL_TYPE_NETBSD:
    258       /* *BSD */
    259       bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline);
    260       break;
    261 
    262     case KERNEL_TYPE_LINUX:
    263       /* Linux */
    264       linux_boot ();
    265       break;
    266 
    267     case KERNEL_TYPE_BIG_LINUX:
    268       /* Big Linux */
    269       big_linux_boot ();
    270       break;
    271 
    272     case KERNEL_TYPE_CHAINLOADER:
    273       /* Chainloader */
    274 
    275       /* Check if we should set the int13 handler.  */
    276       if (bios_drive_map[0] != 0)
    277 	{
    278 	  int i;
    279 
    280 	  /* Search for SAVED_DRIVE.  */
    281 	  for (i = 0; i < DRIVE_MAP_SIZE; i++)
    282 	    {
    283 	      if (! bios_drive_map[i])
    284 		break;
    285 	      else if ((bios_drive_map[i] & 0xFF) == saved_drive)
    286 		{
    287 		  /* Exchage SAVED_DRIVE with the mapped drive.  */
    288 		  saved_drive = (bios_drive_map[i] >> 8) & 0xFF;
    289 		  break;
    290 		}
    291 	    }
    292 
    293 	  /* Set the handler. This is somewhat dangerous.  */
    294 	  set_int13_handler (bios_drive_map);
    295 	}
    296 
    297       gateA20 (0);
    298       boot_drive = saved_drive;
    299       chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr);
    300       break;
    301 
    302     case KERNEL_TYPE_MULTIBOOT:
    303       /* Multiboot */
    304       multi_boot ((int) entry_addr, (int) &mbi);
    305       break;
    306 
    307     default:
    308       errnum = ERR_BOOT_COMMAND;
    309       return 1;
    310     }
    311 
    312   return 0;
    313 }
    314 
    315 static struct builtin builtin_boot =
    316 {
    317   "boot",
    318   boot_func,
    319   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
    320   "boot",
    321   "Boot the OS/chain-loader which has been loaded."
    322 };
    323 
    324 
    325 #ifdef SUPPORT_NETBOOT
    327 /* bootp */
    328 static int
    329 bootp_func (char *arg, int flags)
    330 {
    331   int with_configfile = 0;
    332 
    333   if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
    334       == 0)
    335     {
    336       with_configfile = 1;
    337       arg = skip_to (0, arg);
    338     }
    339 
    340   if (! bootp ())
    341     {
    342       if (errnum == ERR_NONE)
    343 	errnum = ERR_DEV_VALUES;
    344 
    345       return 1;
    346     }
    347 
    348   /* Notify the configuration.  */
    349   print_network_configuration ();
    350 
    351   /* XXX: this can cause an endless loop, but there is no easy way to
    352      detect such a loop unfortunately.  */
    353   if (with_configfile)
    354     configfile_func (config_file, flags);
    355 
    356   return 0;
    357 }
    358 
    359 static struct builtin builtin_bootp =
    360 {
    361   "bootp",
    362   bootp_func,
    363   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
    364   "bootp [--with-configfile]",
    365   "Initialize a network device via BOOTP. If the option `--with-configfile'"
    366   " is given, try to load a configuration file specified by the 150 vendor"
    367   " tag."
    368 };
    369 #endif /* SUPPORT_NETBOOT */
    370 
    371 
    372 /* cat */
    374 static int
    375 cat_func (char *arg, int flags)
    376 {
    377   char c;
    378 
    379   if (! grub_open (arg))
    380     return 1;
    381 
    382   while (grub_read (&c, 1))
    383     {
    384       /* Because running "cat" with a binary file can confuse the terminal,
    385 	 print only some characters as they are.  */
    386       if (grub_isspace (c) || (c >= ' ' && c <= '~'))
    387 	grub_putchar (c);
    388       else
    389 	grub_putchar ('?');
    390     }
    391 
    392   grub_close ();
    393   return 0;
    394 }
    395 
    396 static struct builtin builtin_cat =
    397 {
    398   "cat",
    399   cat_func,
    400   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
    401   "cat FILE",
    402   "Print the contents of the file FILE."
    403 };
    404 
    405 
    406 /* chainloader */
    408 static int
    409 chainloader_func (char *arg, int flags)
    410 {
    411   int force = 0;
    412   char *file = arg;
    413 
    414   /* If the option `--force' is specified?  */
    415   if (substring ("--force", arg) <= 0)
    416     {
    417       force = 1;
    418       file = skip_to (0, arg);
    419     }
    420 
    421   /* Open the file.  */
    422   if (! grub_open (file))
    423     {
    424       kernel_type = KERNEL_TYPE_NONE;
    425       return 1;
    426     }
    427 
    428   /* Read the first block.  */
    429   if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE)
    430     {
    431       grub_close ();
    432       kernel_type = KERNEL_TYPE_NONE;
    433 
    434       /* This below happens, if a file whose size is less than 512 bytes
    435 	 is loaded.  */
    436       if (errnum == ERR_NONE)
    437 	errnum = ERR_EXEC_FORMAT;
    438 
    439       return 1;
    440     }
    441 
    442   /* If not loading it forcibly, check for the signature.  */
    443   if (! force
    444       && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET))
    445 	  != BOOTSEC_SIGNATURE))
    446     {
    447       grub_close ();
    448       errnum = ERR_EXEC_FORMAT;
    449       kernel_type = KERNEL_TYPE_NONE;
    450       return 1;
    451     }
    452 
    453   grub_close ();
    454   kernel_type = KERNEL_TYPE_CHAINLOADER;
    455 
    456   /* XXX: Windows evil hack. For now, only the first five letters are
    457      checked.  */
    458   if (IS_PC_SLICE_TYPE_FAT (current_slice)
    459       && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID,
    460 			"MSWIN", 5))
    461     *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS))
    462       = part_start;
    463 
    464   errnum = ERR_NONE;
    465 
    466   return 0;
    467 }
    468 
    469 static struct builtin builtin_chainloader =
    470 {
    471   "chainloader",
    472   chainloader_func,
    473   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
    474   "chainloader [--force] FILE",
    475   "Load the chain-loader FILE. If --force is specified, then load it"
    476   " forcibly, whether the boot loader signature is present or not."
    477 };
    478 
    479 
    480 /* This function could be used to debug new filesystem code. Put a file
    482    in the new filesystem and the same file in a well-tested filesystem.
    483    Then, run "cmp" with the files. If no output is obtained, probably
    484    the code is good, otherwise investigate what's wrong...  */
    485 /* cmp FILE1 FILE2 */
    486 static int
    487 cmp_func (char *arg, int flags)
    488 {
    489   /* The filenames.  */
    490   char *file1, *file2;
    491   /* The addresses.  */
    492   char *addr1, *addr2;
    493   int i;
    494   /* The size of the file.  */
    495   int size;
    496 
    497   /* Get the filenames from ARG.  */
    498   file1 = arg;
    499   file2 = skip_to (0, arg);
    500   if (! *file1 || ! *file2)
    501     {
    502       errnum = ERR_BAD_ARGUMENT;
    503       return 1;
    504     }
    505 
    506   /* Terminate the filenames for convenience.  */
    507   nul_terminate (file1);
    508   nul_terminate (file2);
    509 
    510   /* Read the whole data from FILE1.  */
    511   addr1 = (char *) RAW_ADDR (0x100000);
    512   if (! grub_open (file1))
    513     return 1;
    514 
    515   /* Get the size.  */
    516   size = filemax;
    517   if (grub_read (addr1, -1) != size)
    518     {
    519       grub_close ();
    520       return 1;
    521     }
    522 
    523   grub_close ();
    524 
    525   /* Read the whole data from FILE2.  */
    526   addr2 = addr1 + size;
    527   if (! grub_open (file2))
    528     return 1;
    529 
    530   /* Check if the size of FILE2 is equal to the one of FILE2.  */
    531   if (size != filemax)
    532     {
    533       grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n",
    534 		   size, file1, filemax, file2);
    535       grub_close ();
    536       return 0;
    537     }
    538 
    539   if (! grub_read (addr2, -1))
    540     {
    541       grub_close ();
    542       return 1;
    543     }
    544 
    545   grub_close ();
    546 
    547   /* Now compare ADDR1 with ADDR2.  */
    548   for (i = 0; i < size; i++)
    549     {
    550       if (addr1[i] != addr2[i])
    551 	grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n",
    552 		     i, (unsigned) addr1[i], file1,
    553 		     (unsigned) addr2[i], file2);
    554     }
    555 
    556   return 0;
    557 }
    558 
    559 static struct builtin builtin_cmp =
    560 {
    561   "cmp",
    562   cmp_func,
    563   BUILTIN_CMDLINE,
    564   "cmp FILE1 FILE2",
    565   "Compare the file FILE1 with the FILE2 and inform the different values"
    566   " if any."
    567 };
    568 
    569 
    570 /* color */
    572 /* Set new colors used for the menu interface. Support two methods to
    573    specify a color name: a direct integer representation and a symbolic
    574    color name. An example of the latter is "blink-light-gray/blue".  */
    575 static int
    576 color_func (char *arg, int flags)
    577 {
    578   char *normal;
    579   char *highlight;
    580   int new_normal_color;
    581   int new_highlight_color;
    582   static char *color_list[16] =
    583   {
    584     "black",
    585     "blue",
    586     "green",
    587     "cyan",
    588     "red",
    589     "magenta",
    590     "brown",
    591     "light-gray",
    592     "dark-gray",
    593     "light-blue",
    594     "light-green",
    595     "light-cyan",
    596     "light-red",
    597     "light-magenta",
    598     "yellow",
    599     "white"
    600   };
    601 
    602   auto int color_number (char *str);
    603 
    604   /* Convert the color name STR into the magical number.  */
    605   auto int color_number (char *str)
    606     {
    607       char *ptr;
    608       int i;
    609       int color = 0;
    610 
    611       /* Find the separator.  */
    612       for (ptr = str; *ptr && *ptr != '/'; ptr++)
    613 	;
    614 
    615       /* If not found, return -1.  */
    616       if (! *ptr)
    617 	return -1;
    618 
    619       /* Terminate the string STR.  */
    620       *ptr++ = 0;
    621 
    622       /* If STR contains the prefix "blink-", then set the `blink' bit
    623 	 in COLOR.  */
    624       if (substring ("blink-", str) <= 0)
    625 	{
    626 	  color = 0x80;
    627 	  str += 6;
    628 	}
    629 
    630       /* Search for the color name.  */
    631       for (i = 0; i < 16; i++)
    632 	if (grub_strcmp (color_list[i], str) == 0)
    633 	  {
    634 	    color |= i;
    635 	    break;
    636 	  }
    637 
    638       if (i == 16)
    639 	return -1;
    640 
    641       str = ptr;
    642       nul_terminate (str);
    643 
    644       /* Search for the color name.  */
    645       for (i = 0; i < 8; i++)
    646 	if (grub_strcmp (color_list[i], str) == 0)
    647 	  {
    648 	    color |= i << 4;
    649 	    break;
    650 	  }
    651 
    652       if (i == 8)
    653 	return -1;
    654 
    655       return color;
    656     }
    657 
    658   normal = arg;
    659   highlight = skip_to (0, arg);
    660 
    661   new_normal_color = color_number (normal);
    662   if (new_normal_color < 0 && ! safe_parse_maxint (&normal, &new_normal_color))
    663     return 1;
    664 
    665   /* The second argument is optional, so set highlight_color
    666      to inverted NORMAL_COLOR.  */
    667   if (! *highlight)
    668     new_highlight_color = ((new_normal_color >> 4)
    669 			   | ((new_normal_color & 0xf) << 4));
    670   else
    671     {
    672       new_highlight_color = color_number (highlight);
    673       if (new_highlight_color < 0
    674 	  && ! safe_parse_maxint (&highlight, &new_highlight_color))
    675 	return 1;
    676     }
    677 
    678   if (current_term->setcolor)
    679     current_term->setcolor (new_normal_color, new_highlight_color);
    680 
    681   return 0;
    682 }
    683 
    684 static struct builtin builtin_color =
    685 {
    686   "color",
    687   color_func,
    688   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
    689   "color NORMAL [HIGHLIGHT]",
    690   "Change the menu colors. The color NORMAL is used for most"
    691   " lines in the menu, and the color HIGHLIGHT is used to highlight the"
    692   " line where the cursor points. If you omit HIGHLIGHT, then the"
    693   " inverted color of NORMAL is used for the highlighted line."
    694   " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
    695   " A symbolic color name must be one of these: black, blue, green,"
    696   " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
    697   " light-green, light-cyan, light-red, light-magenta, yellow and white."
    698   " But only the first eight names can be used for BG. You can prefix"
    699   " \"blink-\" to FG if you want a blinking foreground color."
    700 };
    701 
    702 
    703 /* configfile */
    705 static int
    706 configfile_func (char *arg, int flags)
    707 {
    708   char *new_config = config_file;
    709 
    710   /* Check if the file ARG is present.  */
    711   if (! grub_open (arg))
    712     return 1;
    713 
    714   grub_close ();
    715 
    716   /* Copy ARG to CONFIG_FILE.  */
    717   while ((*new_config++ = *arg++) != 0)
    718     ;
    719 
    720 #ifdef GRUB_UTIL
    721   /* Force to load the configuration file.  */
    722   use_config_file = 1;
    723 #endif
    724 
    725   /* Make sure that the user will not be authoritative.  */
    726   auth = 0;
    727 
    728   /* Restart cmain.  */
    729   grub_longjmp (restart_env, 0);
    730 
    731   /* Never reach here.  */
    732   return 0;
    733 }
    734 
    735 static struct builtin builtin_configfile =
    736 {
    737   "configfile",
    738   configfile_func,
    739   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
    740   "configfile FILE",
    741   "Load FILE as the configuration file."
    742 };
    743 
    744 
    745 /* debug */
    747 static int
    748 debug_func (char *arg, int flags)
    749 {
    750   if (debug)
    751     {
    752       debug = 0;
    753       grub_printf (" Debug mode is turned off\n");
    754     }
    755   else
    756     {
    757       debug = 1;
    758       grub_printf (" Debug mode is turned on\n");
    759     }
    760 
    761   return 0;
    762 }
    763 
    764 static struct builtin builtin_debug =
    765 {
    766   "debug",
    767   debug_func,
    768   BUILTIN_CMDLINE,
    769   "debug",
    770   "Turn on/off the debug mode."
    771 };
    772 
    773 
    774 /* default */
    776 static int
    777 default_func (char *arg, int flags)
    778 {
    779 #ifndef SUPPORT_DISKLESS
    780   if (grub_strcmp (arg, "saved") == 0)
    781     {
    782       default_entry = saved_entryno;
    783       return 0;
    784     }
    785 #endif /* SUPPORT_DISKLESS */
    786 
    787   if (! safe_parse_maxint (&arg, &default_entry))
    788     return 1;
    789 
    790   return 0;
    791 }
    792 
    793 static struct builtin builtin_default =
    794 {
    795   "default",
    796   default_func,
    797   BUILTIN_MENU,
    798 #if 0
    799   "default [NUM | `saved']",
    800   "Set the default entry to entry number NUM (if not specified, it is"
    801   " 0, the first entry) or the entry number saved by savedefault."
    802 #endif
    803 };
    804 
    805 
    806 #ifdef GRUB_UTIL
    808 /* device */
    809 static int
    810 device_func (char *arg, int flags)
    811 {
    812   char *drive = arg;
    813   char *device;
    814 
    815   /* Get the drive number from DRIVE.  */
    816   if (! set_device (drive))
    817     return 1;
    818 
    819   /* Get the device argument.  */
    820   device = skip_to (0, drive);
    821 
    822   /* Terminate DEVICE.  */
    823   nul_terminate (device);
    824 
    825   if (! *device || ! check_device (device))
    826     {
    827       errnum = ERR_FILE_NOT_FOUND;
    828       return 1;
    829     }
    830 
    831   assign_device_name (current_drive, device);
    832 
    833   return 0;
    834 }
    835 
    836 static struct builtin builtin_device =
    837 {
    838   "device",
    839   device_func,
    840   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
    841   "device DRIVE DEVICE",
    842   "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command"
    843   " can be used only in the grub shell."
    844 };
    845 #endif /* GRUB_UTIL */
    846 
    847 
    848 #ifdef SUPPORT_NETBOOT
    850 /* dhcp */
    851 static int
    852 dhcp_func (char *arg, int flags)
    853 {
    854   /* For now, this is an alias for bootp.  */
    855   return bootp_func (arg, flags);
    856 }
    857 
    858 static struct builtin builtin_dhcp =
    859 {
    860   "dhcp",
    861   dhcp_func,
    862   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
    863   "dhcp",
    864   "Initialize a network device via DHCP."
    865 };
    866 #endif /* SUPPORT_NETBOOT */
    867 
    868 
    869 /* displayapm */
    871 static int
    872 displayapm_func (char *arg, int flags)
    873 {
    874   if (mbi.flags & MB_INFO_APM_TABLE)
    875     {
    876       grub_printf ("APM BIOS information:\n"
    877 		   " Version:          0x%x\n"
    878 		   " 32-bit CS:        0x%x\n"
    879 		   " Offset:           0x%x\n"
    880 		   " 16-bit CS:        0x%x\n"
    881 		   " 16-bit DS:        0x%x\n"
    882 		   " 32-bit CS length: 0x%x\n"
    883 		   " 16-bit CS length: 0x%x\n"
    884 		   " 16-bit DS length: 0x%x\n",
    885 		   (unsigned) apm_bios_info.version,
    886 		   (unsigned) apm_bios_info.cseg,
    887 		   apm_bios_info.offset,
    888 		   (unsigned) apm_bios_info.cseg_16,
    889 		   (unsigned) apm_bios_info.dseg_16,
    890 		   (unsigned) apm_bios_info.cseg_len,
    891 		   (unsigned) apm_bios_info.cseg_16_len,
    892 		   (unsigned) apm_bios_info.dseg_16_len);
    893     }
    894   else
    895     {
    896       grub_printf ("No APM BIOS found or probe failed\n");
    897     }
    898 
    899   return 0;
    900 }
    901 
    902 static struct builtin builtin_displayapm =
    903 {
    904   "displayapm",
    905   displayapm_func,
    906   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
    907   "displayapm",
    908   "Display APM BIOS information."
    909 };
    910 
    911 
    912 /* displaymem */
    914 static int
    915 displaymem_func (char *arg, int flags)
    916 {
    917   if (get_eisamemsize () != -1)
    918     grub_printf (" EISA Memory BIOS Interface is present\n");
    919   if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0
    920       || *((int *) SCRATCHADDR) != 0)
    921     grub_printf (" Address Map BIOS Interface is present\n");
    922 
    923   grub_printf (" Lower memory: %uK, "
    924 	       "Upper memory (to first chipset hole): %uK\n",
    925 	       mbi.mem_lower, mbi.mem_upper);
    926 
    927   if (mbi.flags & MB_INFO_MEM_MAP)
    928     {
    929       struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
    930       int end_addr = mbi.mmap_addr + mbi.mmap_length;
    931 
    932       grub_printf (" [Address Range Descriptor entries "
    933 		   "immediately follow (values are 64-bit)]\n");
    934       while (end_addr > (int) map)
    935 	{
    936 	  char *str;
    937 
    938 	  if (map->Type == MB_ARD_MEMORY)
    939 	    str = "Usable RAM";
    940 	  else
    941 	    str = "Reserved";
    942 	  grub_printf ("   %s:  Base Address:  0x%x X 4GB + 0x%x,\n"
    943 		       "      Length:   0x%x X 4GB + 0x%x bytes\n",
    944 		       str,
    945 		       (unsigned long) (map->BaseAddr >> 32),
    946 		       (unsigned long) (map->BaseAddr & 0xFFFFFFFF),
    947 		       (unsigned long) (map->Length >> 32),
    948 		       (unsigned long) (map->Length & 0xFFFFFFFF));
    949 
    950 	  map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size));
    951 	}
    952     }
    953 
    954   return 0;
    955 }
    956 
    957 static struct builtin builtin_displaymem =
    958 {
    959   "displaymem",
    960   displaymem_func,
    961   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
    962   "displaymem",
    963   "Display what GRUB thinks the system address space map of the"
    964   " machine is, including all regions of physical RAM installed."
    965 };
    966 
    967 
    968 /* dump FROM TO */
    970 #ifdef GRUB_UTIL
    971 static int
    972 dump_func (char *arg, int flags)
    973 {
    974   char *from, *to;
    975   FILE *fp;
    976   char c;
    977 
    978   from = arg;
    979   to = skip_to (0, arg);
    980   if (! *from || ! *to)
    981     {
    982       errnum = ERR_BAD_ARGUMENT;
    983       return 1;
    984     }
    985 
    986   nul_terminate (from);
    987   nul_terminate (to);
    988 
    989   if (! grub_open (from))
    990     return 1;
    991 
    992   fp = fopen (to, "w");
    993   if (! fp)
    994     {
    995       errnum = ERR_WRITE;
    996       return 1;
    997     }
    998 
    999   while (grub_read (&c, 1))
   1000     if (fputc (c, fp) == EOF)
   1001       {
   1002 	errnum = ERR_WRITE;
   1003 	fclose (fp);
   1004 	return 1;
   1005       }
   1006 
   1007   if (fclose (fp) == EOF)
   1008     {
   1009       errnum = ERR_WRITE;
   1010       return 1;
   1011     }
   1012 
   1013   grub_close ();
   1014   return 0;
   1015 }
   1016 
   1017 static struct builtin builtin_dump =
   1018   {
   1019     "dump",
   1020     dump_func,
   1021     BUILTIN_CMDLINE,
   1022     "dump FROM TO",
   1023     "Dump the contents of the file FROM to the file TO. FROM must be"
   1024     " a GRUB file and TO must be an OS file."
   1025   };
   1026 #endif /* GRUB_UTIL */
   1027 
   1028 
   1029 static char embed_info[32];
   1031 /* embed */
   1032 /* Embed a Stage 1.5 in the first cylinder after MBR or in the
   1033    bootloader block in a FFS.  */
   1034 static int
   1035 embed_func (char *arg, int flags)
   1036 {
   1037   char *stage1_5;
   1038   char *device;
   1039   char *stage1_5_buffer = (char *) RAW_ADDR (0x100000);
   1040   int len, size;
   1041   int sector;
   1042 
   1043   stage1_5 = arg;
   1044   device = skip_to (0, stage1_5);
   1045 
   1046   /* Open a Stage 1.5.  */
   1047   if (! grub_open (stage1_5))
   1048     return 1;
   1049 
   1050   /* Read the whole of the Stage 1.5.  */
   1051   len = grub_read (stage1_5_buffer, -1);
   1052   grub_close ();
   1053 
   1054   if (errnum)
   1055     return 1;
   1056 
   1057   size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE;
   1058 
   1059   /* Get the device where the Stage 1.5 will be embedded.  */
   1060   set_device (device);
   1061   if (errnum)
   1062     return 1;
   1063 
   1064   if (current_partition == 0xFFFFFF)
   1065     {
   1066       /* Embed it after the MBR.  */
   1067 
   1068       char mbr[SECTOR_SIZE];
   1069       char ezbios_check[2*SECTOR_SIZE];
   1070       int i;
   1071 
   1072       /* Open the partition.  */
   1073       if (! open_partition ())
   1074 	return 1;
   1075 
   1076       /* No floppy has MBR.  */
   1077       if (! (current_drive & 0x80))
   1078 	{
   1079 	  errnum = ERR_DEV_VALUES;
   1080 	  return 1;
   1081 	}
   1082 
   1083       /* Read the MBR of CURRENT_DRIVE.  */
   1084       if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr))
   1085 	return 1;
   1086 
   1087       /* Sanity check.  */
   1088       if (! PC_MBR_CHECK_SIG (mbr))
   1089 	{
   1090 	  errnum = ERR_BAD_PART_TABLE;
   1091 	  return 1;
   1092 	}
   1093 
   1094       /* Check if the disk can store the Stage 1.5.  */
   1095       for (i = 0; i < 4; i++)
   1096 	if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size)
   1097 	  {
   1098 	    errnum = ERR_NO_DISK_SPACE;
   1099 	    return 1;
   1100 	  }
   1101 
   1102       /* Check for EZ-BIOS signature. It should be in the third
   1103        * sector, but due to remapping it can appear in the second, so
   1104        * load and check both.
   1105        */
   1106       if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check))
   1107 	return 1;
   1108 
   1109       if (! memcmp (ezbios_check + 3, "AERMH", 5)
   1110 	  || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5))
   1111 	{
   1112 	  /* The space after the MBR is used by EZ-BIOS which we must
   1113 	   * not overwrite.
   1114 	   */
   1115 	  errnum = ERR_NO_DISK_SPACE;
   1116 	  return 1;
   1117 	}
   1118 
   1119       sector = 1;
   1120     }
   1121   else
   1122     {
   1123       /* Embed it in the bootloader block in the filesystem.  */
   1124       int start_sector;
   1125 
   1126       /* Open the partition.  */
   1127       if (! open_device ())
   1128 	return 1;
   1129 
   1130       /* Check if the current slice supports embedding.  */
   1131       if (fsys_table[fsys_type].embed_func == 0
   1132 	  || ! fsys_table[fsys_type].embed_func (&start_sector, size))
   1133 	{
   1134 	  errnum = ERR_DEV_VALUES;
   1135 	  return 1;
   1136 	}
   1137 
   1138       sector = part_start + start_sector;
   1139     }
   1140 
   1141   /* Clear the cache.  */
   1142   buf_track = -1;
   1143 
   1144   /* Now perform the embedding.  */
   1145   if (! devwrite (sector - part_start, size, stage1_5_buffer))
   1146     return 1;
   1147 
   1148   grub_printf (" %d sectors are embedded.\n", size);
   1149   grub_sprintf (embed_info, "%d+%d", sector - part_start, size);
   1150   return 0;
   1151 }
   1152 
   1153 static struct builtin builtin_embed =
   1154 {
   1155   "embed",
   1156   embed_func,
   1157   BUILTIN_CMDLINE,
   1158   "embed STAGE1_5 DEVICE",
   1159   "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE"
   1160   " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition."
   1161   " Print the number of sectors which STAGE1_5 occupies if successful."
   1162 };
   1163 
   1164 
   1165 /* fallback */
   1167 static int
   1168 fallback_func (char *arg, int flags)
   1169 {
   1170   int i = 0;
   1171 
   1172   while (*arg)
   1173     {
   1174       int entry;
   1175       int j;
   1176 
   1177       if (! safe_parse_maxint (&arg, &entry))
   1178 	return 1;
   1179 
   1180       /* Remove duplications to prevent infinite looping.  */
   1181       for (j = 0; j < i; j++)
   1182 	if (entry == fallback_entries[j])
   1183 	  break;
   1184       if (j != i)
   1185 	continue;
   1186 
   1187       fallback_entries[i++] = entry;
   1188       if (i == MAX_FALLBACK_ENTRIES)
   1189 	break;
   1190 
   1191       arg = skip_to (0, arg);
   1192     }
   1193 
   1194   if (i < MAX_FALLBACK_ENTRIES)
   1195     fallback_entries[i] = -1;
   1196 
   1197   fallback_entryno = (i == 0) ? -1 : 0;
   1198 
   1199   return 0;
   1200 }
   1201 
   1202 static struct builtin builtin_fallback =
   1203 {
   1204   "fallback",
   1205   fallback_func,
   1206   BUILTIN_MENU,
   1207 #if 0
   1208   "fallback NUM...",
   1209   "Go into unattended boot mode: if the default boot entry has any"
   1210   " errors, instead of waiting for the user to do anything, it"
   1211   " immediately starts over using the NUM entry (same numbering as the"
   1212   " `default' command). This obviously won't help if the machine"
   1213   " was rebooted by a kernel that GRUB loaded."
   1214 #endif
   1215 };
   1216 
   1217 
   1218 /* find */
   1220 /* Search for the filename ARG in all of partitions.  */
   1221 static int
   1222 find_func (char *arg, int flags)
   1223 {
   1224   char *filename = arg;
   1225   unsigned long drive;
   1226   unsigned long tmp_drive = saved_drive;
   1227   unsigned long tmp_partition = saved_partition;
   1228   int got_file = 0;
   1229 
   1230   /* Floppies.  */
   1231   for (drive = 0; drive < 8; drive++)
   1232     {
   1233       current_drive = drive;
   1234       current_partition = 0xFFFFFF;
   1235 
   1236       if (open_device ())
   1237 	{
   1238 	  saved_drive = current_drive;
   1239 	  saved_partition = current_partition;
   1240 	  if (grub_open (filename))
   1241 	    {
   1242 	      grub_close ();
   1243 	      grub_printf (" (fd%d)\n", drive);
   1244 	      got_file = 1;
   1245 	    }
   1246 	}
   1247 
   1248       errnum = ERR_NONE;
   1249     }
   1250 
   1251   /* Hard disks.  */
   1252   for (drive = 0x80; drive < 0x88; drive++)
   1253     {
   1254       unsigned long part = 0xFFFFFF;
   1255       unsigned long start, len, offset, ext_offset;
   1256       int type, entry;
   1257       char buf[SECTOR_SIZE];
   1258 
   1259       current_drive = drive;
   1260       while (next_partition (drive, 0xFFFFFF, &part, &type,
   1261 			     &start, &len, &offset, &entry,
   1262 			     &ext_offset, buf))
   1263 	{
   1264 	  if (type != PC_SLICE_TYPE_NONE
   1265 	      && ! IS_PC_SLICE_TYPE_BSD (type)
   1266 	      && ! IS_PC_SLICE_TYPE_EXTENDED (type))
   1267 	    {
   1268 	      current_partition = part;
   1269 	      if (open_device ())
   1270 		{
   1271 		  saved_drive = current_drive;
   1272 		  saved_partition = current_partition;
   1273 		  if (grub_open (filename))
   1274 		    {
   1275 		      int bsd_part = (part >> 8) & 0xFF;
   1276 		      int pc_slice = part >> 16;
   1277 
   1278 		      grub_close ();
   1279 
   1280 		      if (bsd_part == 0xFF)
   1281 			grub_printf (" (hd%d,%d)\n",
   1282 				     drive - 0x80, pc_slice);
   1283 		      else
   1284 			grub_printf (" (hd%d,%d,%c)\n",
   1285 				     drive - 0x80, pc_slice, bsd_part + 'a');
   1286 
   1287 		      got_file = 1;
   1288 		    }
   1289 		}
   1290 	    }
   1291 
   1292 	  /* We want to ignore any error here.  */
   1293 	  errnum = ERR_NONE;
   1294 	}
   1295 
   1296       /* next_partition always sets ERRNUM in the last call, so clear
   1297 	 it.  */
   1298       errnum = ERR_NONE;
   1299     }
   1300 
   1301   saved_drive = tmp_drive;
   1302   saved_partition = tmp_partition;
   1303 
   1304   if (got_file)
   1305     {
   1306       errnum = ERR_NONE;
   1307       return 0;
   1308     }
   1309 
   1310   errnum = ERR_FILE_NOT_FOUND;
   1311   return 1;
   1312 }
   1313 
   1314 static struct builtin builtin_find =
   1315 {
   1316   "find",
   1317   find_func,
   1318   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   1319   "find FILENAME",
   1320   "Search for the filename FILENAME in all of partitions and print the list of"
   1321   " the devices which contain the file."
   1322 };
   1323 
   1324 
   1325 /* fstest */
   1327 static int
   1328 fstest_func (char *arg, int flags)
   1329 {
   1330   if (disk_read_hook)
   1331     {
   1332       disk_read_hook = NULL;
   1333       printf (" Filesystem tracing is now off\n");
   1334     }
   1335   else
   1336     {
   1337       disk_read_hook = disk_read_print_func;
   1338       printf (" Filesystem tracing is now on\n");
   1339     }
   1340 
   1341   return 0;
   1342 }
   1343 
   1344 static struct builtin builtin_fstest =
   1345 {
   1346   "fstest",
   1347   fstest_func,
   1348   BUILTIN_CMDLINE,
   1349   "fstest",
   1350   "Toggle filesystem test mode."
   1351 };
   1352 
   1353 
   1354 /* geometry */
   1356 static int
   1357 geometry_func (char *arg, int flags)
   1358 {
   1359   struct geometry geom;
   1360   char *msg;
   1361   char *device = arg;
   1362 #ifdef GRUB_UTIL
   1363   char *ptr;
   1364 #endif
   1365 
   1366   /* Get the device number.  */
   1367   set_device (device);
   1368   if (errnum)
   1369     return 1;
   1370 
   1371   /* Check for the geometry.  */
   1372   if (get_diskinfo (current_drive, &geom))
   1373     {
   1374       errnum = ERR_NO_DISK;
   1375       return 1;
   1376     }
   1377 
   1378   /* Attempt to read the first sector, because some BIOSes turns out not
   1379      to support LBA even though they set the bit 0 in the support
   1380      bitmap, only after reading something actually.  */
   1381   if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
   1382     {
   1383       errnum = ERR_READ;
   1384       return 1;
   1385     }
   1386 
   1387 #ifdef GRUB_UTIL
   1388   ptr = skip_to (0, device);
   1389   if (*ptr)
   1390     {
   1391       char *cylinder, *head, *sector, *total_sector;
   1392       int num_cylinder, num_head, num_sector, num_total_sector;
   1393 
   1394       cylinder = ptr;
   1395       head = skip_to (0, cylinder);
   1396       sector = skip_to (0, head);
   1397       total_sector = skip_to (0, sector);
   1398       if (! safe_parse_maxint (&cylinder, &num_cylinder)
   1399 	  || ! safe_parse_maxint (&head, &num_head)
   1400 	  || ! safe_parse_maxint (&sector, &num_sector))
   1401 	return 1;
   1402 
   1403       disks[current_drive].cylinders = num_cylinder;
   1404       disks[current_drive].heads = num_head;
   1405       disks[current_drive].sectors = num_sector;
   1406 
   1407       if (safe_parse_maxint (&total_sector, &num_total_sector))
   1408 	disks[current_drive].total_sectors = num_total_sector;
   1409       else
   1410 	disks[current_drive].total_sectors
   1411 	  = num_cylinder * num_head * num_sector;
   1412       errnum = 0;
   1413 
   1414       geom = disks[current_drive];
   1415       buf_drive = -1;
   1416     }
   1417 #endif /* GRUB_UTIL */
   1418 
   1419 #ifdef GRUB_UTIL
   1420   msg = device_map[current_drive];
   1421 #else
   1422   if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
   1423     msg = "LBA";
   1424   else
   1425     msg = "CHS";
   1426 #endif
   1427 
   1428   grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, "
   1429 	       "The number of sectors = %d, %s\n",
   1430 	       current_drive,
   1431 	       geom.cylinders, geom.heads, geom.sectors,
   1432 	       geom.total_sectors, msg);
   1433   real_open_partition (1);
   1434 
   1435   return 0;
   1436 }
   1437 
   1438 static struct builtin builtin_geometry =
   1439 {
   1440   "geometry",
   1441   geometry_func,
   1442   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   1443   "geometry DRIVE [CYLINDER HEAD SECTOR [TOTAL_SECTOR]]",
   1444   "Print the information for a drive DRIVE. In the grub shell, you can"
   1445   " set the geometry of the drive arbitrarily. The number of the cylinders,"
   1446   " the one of the heads, the one of the sectors and the one of the total"
   1447   " sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR,"
   1448   " respectively. If you omit TOTAL_SECTOR, then it will be calculated based"
   1449   " on the C/H/S values automatically."
   1450 };
   1451 
   1452 
   1453 /* halt */
   1455 static int
   1456 halt_func (char *arg, int flags)
   1457 {
   1458   int no_apm;
   1459 
   1460   no_apm = (grub_memcmp (arg, "--no-apm", 8) == 0);
   1461   grub_halt (no_apm);
   1462 
   1463   /* Never reach here.  */
   1464   return 1;
   1465 }
   1466 
   1467 static struct builtin builtin_halt =
   1468 {
   1469   "halt",
   1470   halt_func,
   1471   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   1472   "halt [--no-apm]",
   1473   "Halt your system. If APM is avaiable on it, turn off the power using"
   1474   " the APM BIOS, unless you specify the option `--no-apm'."
   1475 };
   1476 
   1477 
   1478 /* help */
   1480 #define MAX_SHORT_DOC_LEN	39
   1481 #define MAX_LONG_DOC_LEN	66
   1482 
   1483 static int
   1484 help_func (char *arg, int flags)
   1485 {
   1486   int all = 0;
   1487 
   1488   if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0)
   1489     {
   1490       all = 1;
   1491       arg = skip_to (0, arg);
   1492     }
   1493 
   1494   if (! *arg)
   1495     {
   1496       /* Invoked with no argument. Print the list of the short docs.  */
   1497       struct builtin **builtin;
   1498       int left = 1;
   1499 
   1500       for (builtin = builtin_table; *builtin != 0; builtin++)
   1501 	{
   1502 	  int len;
   1503 	  int i;
   1504 
   1505 	  /* If this cannot be used in the command-line interface,
   1506 	     skip this.  */
   1507 	  if (! ((*builtin)->flags & BUILTIN_CMDLINE))
   1508 	    continue;
   1509 
   1510 	  /* If this doesn't need to be listed automatically and "--all"
   1511 	     is not specified, skip this.  */
   1512 	  if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST))
   1513 	    continue;
   1514 
   1515 	  len = grub_strlen ((*builtin)->short_doc);
   1516 	  /* If the length of SHORT_DOC is too long, truncate it.  */
   1517 	  if (len > MAX_SHORT_DOC_LEN - 1)
   1518 	    len = MAX_SHORT_DOC_LEN - 1;
   1519 
   1520 	  for (i = 0; i < len; i++)
   1521 	    grub_putchar ((*builtin)->short_doc[i]);
   1522 
   1523 	  for (; i < MAX_SHORT_DOC_LEN; i++)
   1524 	    grub_putchar (' ');
   1525 
   1526 	  if (! left)
   1527 	    grub_putchar ('\n');
   1528 
   1529 	  left = ! left;
   1530 	}
   1531 
   1532       /* If the last entry was at the left column, no newline was printed
   1533 	 at the end.  */
   1534       if (! left)
   1535 	grub_putchar ('\n');
   1536     }
   1537   else
   1538     {
   1539       /* Invoked with one or more patterns.  */
   1540       do
   1541 	{
   1542 	  struct builtin **builtin;
   1543 	  char *next_arg;
   1544 
   1545 	  /* Get the next argument.  */
   1546 	  next_arg = skip_to (0, arg);
   1547 
   1548 	  /* Terminate ARG.  */
   1549 	  nul_terminate (arg);
   1550 
   1551 	  for (builtin = builtin_table; *builtin; builtin++)
   1552 	    {
   1553 	      /* Skip this if this is only for the configuration file.  */
   1554 	      if (! ((*builtin)->flags & BUILTIN_CMDLINE))
   1555 		continue;
   1556 
   1557 	      if (substring (arg, (*builtin)->name) < 1)
   1558 		{
   1559 		  char *doc = (*builtin)->long_doc;
   1560 
   1561 		  /* At first, print the name and the short doc.  */
   1562 		  grub_printf ("%s: %s\n",
   1563 			       (*builtin)->name, (*builtin)->short_doc);
   1564 
   1565 		  /* Print the long doc.  */
   1566 		  while (*doc)
   1567 		    {
   1568 		      int len = grub_strlen (doc);
   1569 		      int i;
   1570 
   1571 		      /* If LEN is too long, fold DOC.  */
   1572 		      if (len > MAX_LONG_DOC_LEN)
   1573 			{
   1574 			  /* Fold this line at the position of a space.  */
   1575 			  for (len = MAX_LONG_DOC_LEN; len > 0; len--)
   1576 			    if (doc[len - 1] == ' ')
   1577 			      break;
   1578 			}
   1579 
   1580 		      grub_printf ("    ");
   1581 		      for (i = 0; i < len; i++)
   1582 			grub_putchar (*doc++);
   1583 		      grub_putchar ('\n');
   1584 		    }
   1585 		}
   1586 	    }
   1587 
   1588 	  arg = next_arg;
   1589 	}
   1590       while (*arg);
   1591     }
   1592 
   1593   return 0;
   1594 }
   1595 
   1596 static struct builtin builtin_help =
   1597 {
   1598   "help",
   1599   help_func,
   1600   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   1601   "help [--all] [PATTERN ...]",
   1602   "Display helpful information about builtin commands. Not all commands"
   1603   " aren't shown without the option `--all'."
   1604 };
   1605 
   1606 
   1607 /* hiddenmenu */
   1609 static int
   1610 hiddenmenu_func (char *arg, int flags)
   1611 {
   1612   show_menu = 0;
   1613   return 0;
   1614 }
   1615 
   1616 static struct builtin builtin_hiddenmenu =
   1617 {
   1618   "hiddenmenu",
   1619   hiddenmenu_func,
   1620   BUILTIN_MENU,
   1621 #if 0
   1622   "hiddenmenu",
   1623   "Hide the menu."
   1624 #endif
   1625 };
   1626 
   1627 
   1628 /* hide */
   1630 static int
   1631 hide_func (char *arg, int flags)
   1632 {
   1633   if (! set_device (arg))
   1634     return 1;
   1635 
   1636   if (! set_partition_hidden_flag (1))
   1637     return 1;
   1638 
   1639   return 0;
   1640 }
   1641 
   1642 static struct builtin builtin_hide =
   1643 {
   1644   "hide",
   1645   hide_func,
   1646   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   1647   "hide PARTITION",
   1648   "Hide PARTITION by setting the \"hidden\" bit in"
   1649   " its partition type code."
   1650 };
   1651 
   1652 
   1653 #ifdef SUPPORT_NETBOOT
   1655 /* ifconfig */
   1656 static int
   1657 ifconfig_func (char *arg, int flags)
   1658 {
   1659   char *svr = 0, *ip = 0, *gw = 0, *sm = 0;
   1660 
   1661   if (! eth_probe ())
   1662     {
   1663       grub_printf ("No ethernet card found.\n");
   1664       errnum = ERR_DEV_VALUES;
   1665       return 1;
   1666     }
   1667 
   1668   while (*arg)
   1669     {
   1670       if (! grub_memcmp ("--server=", arg, sizeof ("--server=") - 1))
   1671 	svr = arg + sizeof("--server=") - 1;
   1672       else if (! grub_memcmp ("--address=", arg, sizeof ("--address=") - 1))
   1673 	ip = arg + sizeof ("--address=") - 1;
   1674       else if (! grub_memcmp ("--gateway=", arg, sizeof ("--gateway=") - 1))
   1675 	gw = arg + sizeof ("--gateway=") - 1;
   1676       else if (! grub_memcmp ("--mask=", arg, sizeof("--mask=") - 1))
   1677 	sm = arg + sizeof ("--mask=") - 1;
   1678       else
   1679 	{
   1680 	  errnum = ERR_BAD_ARGUMENT;
   1681 	  return 1;
   1682 	}
   1683 
   1684       arg = skip_to (0, arg);
   1685     }
   1686 
   1687   if (! ifconfig (ip, sm, gw, svr))
   1688     {
   1689       errnum = ERR_BAD_ARGUMENT;
   1690       return 1;
   1691     }
   1692 
   1693   print_network_configuration ();
   1694   return 0;
   1695 }
   1696 
   1697 static struct builtin builtin_ifconfig =
   1698 {
   1699   "ifconfig",
   1700   ifconfig_func,
   1701   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   1702   "ifconfig [--address=IP] [--gateway=IP] [--mask=MASK] [--server=IP]",
   1703   "Configure the IP address, the netmask, the gateway and the server"
   1704   " address or print current network configuration."
   1705 };
   1706 #endif /* SUPPORT_NETBOOT */
   1707 
   1708 
   1709 /* impsprobe */
   1711 static int
   1712 impsprobe_func (char *arg, int flags)
   1713 {
   1714 #ifdef GRUB_UTIL
   1715   /* In the grub shell, we cannot probe IMPS.  */
   1716   errnum = ERR_UNRECOGNIZED;
   1717   return 1;
   1718 #else /* ! GRUB_UTIL */
   1719   if (!imps_probe ())
   1720     printf (" No MPS information found or probe failed\n");
   1721 
   1722   return 0;
   1723 #endif /* ! GRUB_UTIL */
   1724 }
   1725 
   1726 static struct builtin builtin_impsprobe =
   1727 {
   1728   "impsprobe",
   1729   impsprobe_func,
   1730   BUILTIN_CMDLINE,
   1731   "impsprobe",
   1732   "Probe the Intel Multiprocessor Specification 1.1 or 1.4"
   1733   " configuration table and boot the various CPUs which are found into"
   1734   " a tight loop."
   1735 };
   1736 
   1737 
   1738 /* initrd */
   1740 static int
   1741 initrd_func (char *arg, int flags)
   1742 {
   1743   switch (kernel_type)
   1744     {
   1745     case KERNEL_TYPE_LINUX:
   1746     case KERNEL_TYPE_BIG_LINUX:
   1747       if (! load_initrd (arg))
   1748 	return 1;
   1749       break;
   1750 
   1751     default:
   1752       errnum = ERR_NEED_LX_KERNEL;
   1753       return 1;
   1754     }
   1755 
   1756   return 0;
   1757 }
   1758 
   1759 static struct builtin builtin_initrd =
   1760 {
   1761   "initrd",
   1762   initrd_func,
   1763   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   1764   "initrd FILE [ARG ...]",
   1765   "Load an initial ramdisk FILE for a Linux format boot image and set the"
   1766   " appropriate parameters in the Linux setup area in memory."
   1767 };
   1768 
   1769 
   1770 /* install */
   1772 static int
   1773 install_func (char *arg, int flags)
   1774 {
   1775   char *stage1_file, *dest_dev, *file, *addr;
   1776   char *stage1_buffer = (char *) RAW_ADDR (0x100000);
   1777   char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
   1778   char *old_sect = stage2_buffer + SECTOR_SIZE;
   1779   char *stage2_first_buffer = old_sect + SECTOR_SIZE;
   1780   char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
   1781   /* XXX: Probably SECTOR_SIZE is reasonable.  */
   1782   char *config_filename = stage2_second_buffer + SECTOR_SIZE;
   1783   char *dummy = config_filename + SECTOR_SIZE;
   1784   int new_drive = GRUB_INVALID_DRIVE;
   1785   int dest_drive, dest_partition, dest_sector;
   1786   int src_drive, src_partition, src_part_start;
   1787   int i;
   1788   struct geometry dest_geom, src_geom;
   1789   int saved_sector;
   1790   int stage2_first_sector, stage2_second_sector;
   1791   char *ptr;
   1792   int installaddr, installlist;
   1793   /* Point to the location of the name of a configuration file in Stage 2.  */
   1794   char *config_file_location;
   1795   /* If FILE is a Stage 1.5?  */
   1796   int is_stage1_5 = 0;
   1797   /* Must call grub_close?  */
   1798   int is_open = 0;
   1799   /* If LBA is forced?  */
   1800   int is_force_lba = 0;
   1801   /* Was the last sector full? */
   1802   int last_length = SECTOR_SIZE;
   1803 
   1804 #ifdef GRUB_UTIL
   1805   /* If the Stage 2 is in a partition mounted by an OS, this will store
   1806      the filename under the OS.  */
   1807   char *stage2_os_file = 0;
   1808 #endif /* GRUB_UTIL */
   1809 
   1810   auto void disk_read_savesect_func (int sector, int offset, int length);
   1811   auto void disk_read_blocklist_func (int sector, int offset, int length);
   1812 
   1813   /* Save the first sector of Stage2 in STAGE2_SECT.  */
   1814   auto void disk_read_savesect_func (int sector, int offset, int length)
   1815     {
   1816       if (debug)
   1817 	printf ("[%d]", sector);
   1818 
   1819       /* ReiserFS has files which sometimes contain data not aligned
   1820          on sector boundaries.  Returning an error is better than
   1821          silently failing. */
   1822       if (offset != 0 || length != SECTOR_SIZE)
   1823 	errnum = ERR_UNALIGNED;
   1824 
   1825       saved_sector = sector;
   1826     }
   1827 
   1828   /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
   1829      INSTALLSECT.  */
   1830   auto void disk_read_blocklist_func (int sector, int offset, int length)
   1831     {
   1832       if (debug)
   1833 	printf("[%d]", sector);
   1834 
   1835       if (offset != 0 || last_length != SECTOR_SIZE)
   1836 	{
   1837 	  /* We found a non-sector-aligned data block. */
   1838 	  errnum = ERR_UNALIGNED;
   1839 	  return;
   1840 	}
   1841 
   1842       last_length = length;
   1843 
   1844       if (*((unsigned long *) (installlist - 4))
   1845 	  + *((unsigned short *) installlist) != sector
   1846 	  || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
   1847 	{
   1848 	  installlist -= 8;
   1849 
   1850 	  if (*((unsigned long *) (installlist - 8)))
   1851 	    errnum = ERR_WONT_FIT;
   1852 	  else
   1853 	    {
   1854 	      *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
   1855 	      *((unsigned long *) (installlist - 4)) = sector;
   1856 	    }
   1857 	}
   1858 
   1859       *((unsigned short *) installlist) += 1;
   1860       installaddr += 512;
   1861     }
   1862 
   1863   /* First, check the GNU-style long option.  */
   1864   while (1)
   1865     {
   1866       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
   1867 	{
   1868 	  is_force_lba = 1;
   1869 	  arg = skip_to (0, arg);
   1870 	}
   1871 #ifdef GRUB_UTIL
   1872       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
   1873 	{
   1874 	  stage2_os_file = arg + sizeof ("--stage2=") - 1;
   1875 	  arg = skip_to (0, arg);
   1876 	  nul_terminate (stage2_os_file);
   1877 	}
   1878 #endif /* GRUB_UTIL */
   1879       else
   1880 	break;
   1881     }
   1882 
   1883   stage1_file = arg;
   1884   dest_dev = skip_to (0, stage1_file);
   1885   if (*dest_dev == 'd')
   1886     {
   1887       new_drive = 0;
   1888       dest_dev = skip_to (0, dest_dev);
   1889     }
   1890   file = skip_to (0, dest_dev);
   1891   addr = skip_to (0, file);
   1892 
   1893   /* Get the installation address.  */
   1894   if (! safe_parse_maxint (&addr, &installaddr))
   1895     {
   1896       /* ADDR is not specified.  */
   1897       installaddr = 0;
   1898       ptr = addr;
   1899       errnum = 0;
   1900     }
   1901   else
   1902     ptr = skip_to (0, addr);
   1903 
   1904 #ifndef NO_DECOMPRESSION
   1905   /* Do not decompress Stage 1 or Stage 2.  */
   1906   no_decompression = 1;
   1907 #endif
   1908 
   1909   /* Read Stage 1.  */
   1910   is_open = grub_open (stage1_file);
   1911   if (! is_open
   1912       || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE)
   1913     goto fail;
   1914 
   1915   /* Read the old sector from DEST_DEV.  */
   1916   if (! set_device (dest_dev)
   1917       || ! open_partition ()
   1918       || ! devread (0, 0, SECTOR_SIZE, old_sect))
   1919     goto fail;
   1920 
   1921   /* Store the information for the destination device.  */
   1922   dest_drive = current_drive;
   1923   dest_partition = current_partition;
   1924   dest_geom = buf_geom;
   1925   dest_sector = part_start;
   1926 
   1927   /* Copy the possible DOS BPB, 59 bytes at byte offset 3.  */
   1928   grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET,
   1929 		old_sect + BOOTSEC_BPB_OFFSET,
   1930 		BOOTSEC_BPB_LENGTH);
   1931 
   1932   /* If for a hard disk, copy the possible MBR/extended part table.  */
   1933   if (dest_drive & 0x80)
   1934     grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC,
   1935 		  old_sect + STAGE1_WINDOWS_NT_MAGIC,
   1936 		  STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC);
   1937 
   1938   /* Check for the version and the signature of Stage 1.  */
   1939   if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
   1940       || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET))
   1941 	  != BOOTSEC_SIGNATURE))
   1942     {
   1943       errnum = ERR_BAD_VERSION;
   1944       goto fail;
   1945     }
   1946 
   1947   /* This below is not true any longer. But should we leave this alone?  */
   1948 
   1949   /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe
   1950      routine.  */
   1951   if (! (dest_drive & 0x80)
   1952       && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80
   1953 	  || stage1_buffer[BOOTSEC_PART_OFFSET] == 0))
   1954     {
   1955       errnum = ERR_BAD_VERSION;
   1956       goto fail;
   1957     }
   1958 
   1959   grub_close ();
   1960 
   1961   /* Open Stage 2.  */
   1962   is_open = grub_open (file);
   1963   if (! is_open)
   1964     goto fail;
   1965 
   1966   src_drive = current_drive;
   1967   src_partition = current_partition;
   1968   src_part_start = part_start;
   1969   src_geom = buf_geom;
   1970 
   1971   if (! new_drive)
   1972     new_drive = src_drive;
   1973   else if (src_drive != dest_drive)
   1974     grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
   1975 		 " be installed on a\ndifferent drive than the drive where"
   1976 		 " the Stage 2 resides.\n");
   1977 
   1978   /* Set the boot drive.  */
   1979   *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
   1980 
   1981   /* Set the "force LBA" flag.  */
   1982   *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba;
   1983 
   1984   /* If DEST_DRIVE is a hard disk, enable the workaround, which is
   1985      for buggy BIOSes which don't pass boot drive correctly. Instead,
   1986      they pass 0x00 or 0x01 even when booted from 0x80.  */
   1987   if (dest_drive & BIOS_FLAG_FIXED_DISK)
   1988     /* Replace the jmp (2 bytes) with double nop's.  */
   1989     *((unsigned short *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK))
   1990       = 0x9090;
   1991 
   1992   /* Read the first sector of Stage 2.  */
   1993   disk_read_hook = disk_read_savesect_func;
   1994   if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
   1995     goto fail;
   1996 
   1997   stage2_first_sector = saved_sector;
   1998 
   1999   /* Read the second sector of Stage 2.  */
   2000   if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
   2001     goto fail;
   2002 
   2003   stage2_second_sector = saved_sector;
   2004 
   2005   /* Check for the version of Stage 2.  */
   2006   if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
   2007       != COMPAT_VERSION)
   2008     {
   2009       errnum = ERR_BAD_VERSION;
   2010       goto fail;
   2011     }
   2012 
   2013   /* Check for the Stage 2 id.  */
   2014   if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2)
   2015     is_stage1_5 = 1;
   2016 
   2017   /* If INSTALLADDR is not specified explicitly in the command-line,
   2018      determine it by the Stage 2 id.  */
   2019   if (! installaddr)
   2020     {
   2021       if (! is_stage1_5)
   2022 	/* Stage 2.  */
   2023 	installaddr = 0x8000;
   2024       else
   2025 	/* Stage 1.5.  */
   2026 	installaddr = 0x2000;
   2027     }
   2028 
   2029   *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
   2030     = stage2_first_sector;
   2031   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
   2032     = installaddr;
   2033   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
   2034     = installaddr >> 4;
   2035 
   2036   i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
   2037   while (*((unsigned long *) i))
   2038     {
   2039       if (i < (int) stage2_first_buffer
   2040 	  || (*((int *) (i - 4)) & 0x80000000)
   2041 	  || *((unsigned short *) i) >= 0xA00
   2042 	  || *((short *) (i + 2)) == 0)
   2043 	{
   2044 	  errnum = ERR_BAD_VERSION;
   2045 	  goto fail;
   2046 	}
   2047 
   2048       *((int *) i) = 0;
   2049       *((int *) (i - 4)) = 0;
   2050       i -= 8;
   2051     }
   2052 
   2053   installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
   2054   installaddr += SECTOR_SIZE;
   2055 
   2056   /* Read the whole of Stage2 except for the first sector.  */
   2057   grub_seek (SECTOR_SIZE);
   2058 
   2059   disk_read_hook = disk_read_blocklist_func;
   2060   if (! grub_read (dummy, -1))
   2061     goto fail;
   2062 
   2063   disk_read_hook = 0;
   2064 
   2065   /* Find a string for the configuration filename.  */
   2066   config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS;
   2067   while (*(config_file_location++))
   2068     ;
   2069 
   2070   /* Set the "force LBA" flag for Stage2.  */
   2071   *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA))
   2072     = is_force_lba;
   2073 
   2074   if (*ptr == 'p')
   2075     {
   2076       *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
   2077 	= src_partition;
   2078       if (is_stage1_5)
   2079 	{
   2080 	  /* Reset the device information in FILE if it is a Stage 1.5.  */
   2081 	  unsigned long device = 0xFFFFFFFF;
   2082 
   2083 	  grub_memmove (config_file_location, (char *) &device,
   2084 			sizeof (device));
   2085 	}
   2086 
   2087       ptr = skip_to (0, ptr);
   2088     }
   2089 
   2090   if (*ptr)
   2091     {
   2092       grub_strcpy (config_filename, ptr);
   2093       nul_terminate (config_filename);
   2094 
   2095       if (! is_stage1_5)
   2096 	/* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION.  */
   2097 	grub_strcpy (config_file_location, ptr);
   2098       else
   2099 	{
   2100 	  char *real_config;
   2101 	  unsigned long device;
   2102 
   2103 	  /* Translate the external device syntax to the internal device
   2104 	     syntax.  */
   2105 	  if (! (real_config = set_device (ptr)))
   2106 	    {
   2107 	      /* The Stage 2 PTR does not contain the device name, so
   2108 		 use the root device instead.  */
   2109 	      errnum = ERR_NONE;
   2110 	      current_drive = saved_drive;
   2111 	      current_partition = saved_partition;
   2112 	      real_config = ptr;
   2113 	    }
   2114 
   2115 	  if (current_drive == src_drive)
   2116 	    {
   2117 	      /* If the drive where the Stage 2 resides is the same as
   2118 		 the one where the Stage 1.5 resides, do not embed the
   2119 		 drive number.  */
   2120 	      current_drive = GRUB_INVALID_DRIVE;
   2121 	    }
   2122 
   2123 	  device = (current_drive << 24) | current_partition;
   2124 	  grub_memmove (config_file_location, (char *) &device,
   2125 			sizeof (device));
   2126 	  grub_strcpy (config_file_location + sizeof (device),
   2127 		       real_config);
   2128 	}
   2129 
   2130       /* If a Stage 1.5 is used, then we need to modify the Stage2.  */
   2131       if (is_stage1_5)
   2132 	{
   2133 	  char *real_config_filename = skip_to (0, ptr);
   2134 
   2135 	  is_open = grub_open (config_filename);
   2136 	  if (! is_open)
   2137 	    goto fail;
   2138 
   2139 	  /* Skip the first sector.  */
   2140 	  grub_seek (SECTOR_SIZE);
   2141 
   2142 	  disk_read_hook = disk_read_savesect_func;
   2143 	  if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
   2144 	    goto fail;
   2145 
   2146 	  disk_read_hook = 0;
   2147 	  grub_close ();
   2148 	  is_open = 0;
   2149 
   2150 	  /* Sanity check.  */
   2151 	  if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2)
   2152 	    {
   2153 	      errnum = ERR_BAD_VERSION;
   2154 	      goto fail;
   2155 	    }
   2156 
   2157 	  /* Set the "force LBA" flag for Stage2.  */
   2158 	  *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba;
   2159 
   2160 	  /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2.  */
   2161 	  if (*real_config_filename)
   2162 	    {
   2163 	      /* Specified */
   2164 	      char *location;
   2165 
   2166 	      /* Find a string for the configuration filename.  */
   2167 	      location = stage2_buffer + STAGE2_VER_STR_OFFS;
   2168 	      while (*(location++))
   2169 		;
   2170 
   2171 	      /* Copy the name.  */
   2172 	      grub_strcpy (location, real_config_filename);
   2173 	    }
   2174 
   2175 	  /* Write it to the disk.  */
   2176 	  buf_track = -1;
   2177 
   2178 #ifdef GRUB_UTIL
   2179 	  /* In the grub shell, access the Stage 2 via the OS filesystem
   2180 	     service, if possible.  */
   2181 	  if (stage2_os_file)
   2182 	    {
   2183 	      FILE *fp;
   2184 
   2185 	      fp = fopen (stage2_os_file, "r+");
   2186 	      if (! fp)
   2187 		{
   2188 		  errnum = ERR_FILE_NOT_FOUND;
   2189 		  goto fail;
   2190 		}
   2191 
   2192 	      if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
   2193 		{
   2194 		  fclose (fp);
   2195 		  errnum = ERR_BAD_VERSION;
   2196 		  goto fail;
   2197 		}
   2198 
   2199 	      if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp)
   2200 		  != SECTOR_SIZE)
   2201 		{
   2202 		  fclose (fp);
   2203 		  errnum = ERR_WRITE;
   2204 		  goto fail;
   2205 		}
   2206 
   2207 	      fclose (fp);
   2208 	    }
   2209 	  else
   2210 #endif /* GRUB_UTIL */
   2211 	    {
   2212 	      if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
   2213 		goto fail;
   2214 	    }
   2215 	}
   2216     }
   2217 
   2218   /* Clear the cache.  */
   2219   buf_track = -1;
   2220 
   2221   /* Write the modified sectors of Stage2 to the disk.  */
   2222 #ifdef GRUB_UTIL
   2223   if (! is_stage1_5 && stage2_os_file)
   2224     {
   2225       FILE *fp;
   2226 
   2227       fp = fopen (stage2_os_file, "r+");
   2228       if (! fp)
   2229 	{
   2230 	  errnum = ERR_FILE_NOT_FOUND;
   2231 	  goto fail;
   2232 	}
   2233 
   2234       if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
   2235 	{
   2236 	  fclose (fp);
   2237 	  errnum = ERR_WRITE;
   2238 	  goto fail;
   2239 	}
   2240 
   2241       if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
   2242 	{
   2243 	  fclose (fp);
   2244 	  errnum = ERR_WRITE;
   2245 	  goto fail;
   2246 	}
   2247 
   2248       fclose (fp);
   2249     }
   2250   else
   2251 #endif /* GRUB_UTIL */
   2252     {
   2253       /* The first.  */
   2254       current_drive = src_drive;
   2255       current_partition = src_partition;
   2256 
   2257       if (! open_partition ())
   2258 	goto fail;
   2259 
   2260       if (! devwrite (stage2_first_sector - src_part_start, 1,
   2261 		      stage2_first_buffer))
   2262 	goto fail;
   2263 
   2264       if (! devwrite (stage2_second_sector - src_part_start, 1,
   2265 		      stage2_second_buffer))
   2266 	goto fail;
   2267     }
   2268 
   2269   /* Write the modified sector of Stage 1 to the disk.  */
   2270   current_drive = dest_drive;
   2271   current_partition = dest_partition;
   2272   if (! open_partition ())
   2273     goto fail;
   2274 
   2275   devwrite (0, 1, stage1_buffer);
   2276 
   2277  fail:
   2278   if (is_open)
   2279     grub_close ();
   2280 
   2281   disk_read_hook = 0;
   2282 
   2283 #ifndef NO_DECOMPRESSION
   2284   no_decompression = 0;
   2285 #endif
   2286 
   2287   return errnum;
   2288 }
   2289 
   2290 static struct builtin builtin_install =
   2291 {
   2292   "install",
   2293   install_func,
   2294   BUILTIN_CMDLINE,
   2295   "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
   2296   "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2"
   2297   " as a Stage 2. If the option `d' is present, the Stage 1 will always"
   2298   " look for the disk where STAGE2 was installed, rather than using"
   2299   " the booting drive. The Stage 2 will be loaded at address ADDR, which"
   2300   " will be determined automatically if you don't specify it. If"
   2301   " the option `p' or CONFIG_FILE is present, then the first block"
   2302   " of Stage 2 is patched with new values of the partition and name"
   2303   " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
   2304   " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage"
   2305   " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
   2306   " patched with the configuration filename REAL_CONFIG_FILE."
   2307   " If the option `--force-lba' is specified, disable some sanity checks"
   2308   " for LBA mode. If the option `--stage2' is specified, rewrite the Stage"
   2309   " 2 via your OS's filesystem instead of the raw device."
   2310 };
   2311 
   2312 
   2313 /* ioprobe */
   2315 static int
   2316 ioprobe_func (char *arg, int flags)
   2317 {
   2318 #ifdef GRUB_UTIL
   2319 
   2320   errnum = ERR_UNRECOGNIZED;
   2321   return 1;
   2322 
   2323 #else /* ! GRUB_UTIL */
   2324 
   2325   unsigned short *port;
   2326 
   2327   /* Get the drive number.  */
   2328   set_device (arg);
   2329   if (errnum)
   2330     return 1;
   2331 
   2332   /* Clean out IO_MAP.  */
   2333   grub_memset ((char *) io_map, 0, IO_MAP_SIZE * sizeof (unsigned short));
   2334 
   2335   /* Track the int13 handler.  */
   2336   track_int13 (current_drive);
   2337 
   2338   /* Print out the result.  */
   2339   for (port = io_map; *port != 0; port++)
   2340     grub_printf (" 0x%x", (unsigned int) *port);
   2341 
   2342   return 0;
   2343 
   2344 #endif /* ! GRUB_UTIL */
   2345 }
   2346 
   2347 static struct builtin builtin_ioprobe =
   2348 {
   2349   "ioprobe",
   2350   ioprobe_func,
   2351   BUILTIN_CMDLINE,
   2352   "ioprobe DRIVE",
   2353   "Probe I/O ports used for the drive DRIVE."
   2354 };
   2355 
   2356 
   2357 /* kernel */
   2359 static int
   2360 kernel_func (char *arg, int flags)
   2361 {
   2362   int len;
   2363   kernel_t suggested_type = KERNEL_TYPE_NONE;
   2364   unsigned long load_flags = 0;
   2365 
   2366 #ifndef AUTO_LINUX_MEM_OPT
   2367   load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
   2368 #endif
   2369 
   2370   /* Deal with GNU-style long options.  */
   2371   while (1)
   2372     {
   2373       /* If the option `--type=TYPE' is specified, convert the string to
   2374 	 a kernel type.  */
   2375       if (grub_memcmp (arg, "--type=", 7) == 0)
   2376 	{
   2377 	  arg += 7;
   2378 
   2379 	  if (grub_memcmp (arg, "netbsd", 6) == 0)
   2380 	    suggested_type = KERNEL_TYPE_NETBSD;
   2381 	  else if (grub_memcmp (arg, "freebsd", 7) == 0)
   2382 	    suggested_type = KERNEL_TYPE_FREEBSD;
   2383 	  else if (grub_memcmp (arg, "openbsd", 7) == 0)
   2384 	    /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's
   2385 	       point of view.  */
   2386 	    suggested_type = KERNEL_TYPE_NETBSD;
   2387 	  else if (grub_memcmp (arg, "linux", 5) == 0)
   2388 	    suggested_type = KERNEL_TYPE_LINUX;
   2389 	  else if (grub_memcmp (arg, "biglinux", 8) == 0)
   2390 	    suggested_type = KERNEL_TYPE_BIG_LINUX;
   2391 	  else if (grub_memcmp (arg, "multiboot", 9) == 0)
   2392 	    suggested_type = KERNEL_TYPE_MULTIBOOT;
   2393 	  else
   2394 	    {
   2395 	      errnum = ERR_BAD_ARGUMENT;
   2396 	      return 1;
   2397 	    }
   2398 	}
   2399       /* If the `--no-mem-option' is specified, don't pass a Linux's mem
   2400 	 option automatically. If the kernel is another type, this flag
   2401 	 has no effect.  */
   2402     else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
   2403         load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
   2404     else if (grub_memcmp(arg, "--use-cmd-line", 14) == 0) {
   2405         if (!cmdline_loaded) {
   2406             errnum = ERR_BAD_ARGUMENT;
   2407             return 1;
   2408         }
   2409     }
   2410       else
   2411 	break;
   2412 
   2413       /* Try the next.  */
   2414       arg = skip_to (0, arg);
   2415     }
   2416 
   2417   if (!cmdline_loaded) {
   2418     len = grub_strlen (arg);
   2419 
   2420     /* Reset MB_CMDLINE.  */
   2421     mb_cmdline = (char *) MB_CMDLINE_BUF;
   2422     if (len + 1 > MB_CMDLINE_BUFLEN)
   2423       {
   2424         errnum = ERR_WONT_FIT;
   2425         return 1;
   2426       }
   2427     grub_memmove (mb_cmdline, arg, len + 1);
   2428   } else {
   2429     len = grub_strlen(mb_cmdline);
   2430   }
   2431 
   2432 
   2433   /* Copy the command-line to MB_CMDLINE.  */
   2434   kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags);
   2435   if (kernel_type == KERNEL_TYPE_NONE)
   2436     return 1;
   2437 
   2438   mb_cmdline += len + 1;
   2439 
   2440   return 0;
   2441 }
   2442 
   2443 static struct builtin builtin_kernel =
   2444 {
   2445   "kernel",
   2446   kernel_func,
   2447   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   2448   "kernel [--no-mem-option] [--type=TYPE] [--use-cmd-line] FILE [ARG ...]",
   2449   "Attempt to load the primary boot image from FILE. The rest of the"
   2450   " line is passed verbatim as the \"kernel command line\".  Any modules"
   2451   " must be reloaded after using this command. The option --type is used"
   2452   " to suggest what type of kernel to be loaded. TYPE must be either of"
   2453   " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
   2454   " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
   2455   " Linux's mem option automatically. If the option --use-cmd-line is"
   2456   " provided, then GRUB ignores the rest of the line, and instead passes"
   2457   " the command line loaded with \"cmdline\" command to the kernel."
   2458 };
   2459 
   2460 
   2461 /* cmdline */
   2463 static int
   2464 cmdline_func (char *arg, int flags)
   2465 {
   2466   int len;
   2467 
   2468   if (!grub_open(arg))
   2469     return 1;
   2470 
   2471   if (filemax > MB_CMDLINE_BUFLEN) {
   2472       grub_close();
   2473       errnum = ERR_WONT_FIT;
   2474       return 1;
   2475   }
   2476 
   2477   if (!(len = grub_read (mb_cmdline, MB_CMDLINE_BUFLEN - 1))) {
   2478       grub_close();
   2479       return 1;
   2480   }
   2481 
   2482   grub_close();
   2483 
   2484   mb_cmdline[len] = 0;
   2485   grub_printf("Loaded kernel cmdline args: %s\n", mb_cmdline);
   2486   cmdline_loaded = 1;
   2487   return 0;
   2488 }
   2489 
   2490 static struct builtin builtin_cmdline =
   2491 {
   2492   "cmdline",
   2493   cmdline_func,
   2494   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   2495   "cmdline FILE",
   2496   "Attempt to load a file that contains the default kernel command line."
   2497 };
   2498 
   2499 
   2500 /* lock */
   2502 static int
   2503 lock_func (char *arg, int flags)
   2504 {
   2505   if (! auth && password)
   2506     {
   2507       errnum = ERR_PRIVILEGED;
   2508       return 1;
   2509     }
   2510 
   2511   return 0;
   2512 }
   2513 
   2514 static struct builtin builtin_lock =
   2515 {
   2516   "lock",
   2517   lock_func,
   2518   BUILTIN_CMDLINE,
   2519   "lock",
   2520   "Break a command execution unless the user is authenticated."
   2521 };
   2522 
   2523 
   2524 /* makeactive */
   2526 static int
   2527 makeactive_func (char *arg, int flags)
   2528 {
   2529   if (! make_saved_active ())
   2530     return 1;
   2531 
   2532   return 0;
   2533 }
   2534 
   2535 static struct builtin builtin_makeactive =
   2536 {
   2537   "makeactive",
   2538   makeactive_func,
   2539   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   2540   "makeactive",
   2541   "Set the active partition on the root disk to GRUB's root device."
   2542   " This command is limited to _primary_ PC partitions on a hard disk."
   2543 };
   2544 
   2545 
   2546 /* map */
   2548 /* Map FROM_DRIVE to TO_DRIVE.  */
   2549 static int
   2550 map_func (char *arg, int flags)
   2551 {
   2552   char *to_drive;
   2553   char *from_drive;
   2554   unsigned long to, from;
   2555   int i;
   2556 
   2557   to_drive = arg;
   2558   from_drive = skip_to (0, arg);
   2559 
   2560   /* Get the drive number for TO_DRIVE.  */
   2561   set_device (to_drive);
   2562   if (errnum)
   2563     return 1;
   2564   to = current_drive;
   2565 
   2566   /* Get the drive number for FROM_DRIVE.  */
   2567   set_device (from_drive);
   2568   if (errnum)
   2569     return 1;
   2570   from = current_drive;
   2571 
   2572   /* Search for an empty slot in BIOS_DRIVE_MAP.  */
   2573   for (i = 0; i < DRIVE_MAP_SIZE; i++)
   2574     {
   2575       /* Perhaps the user wants to override the map.  */
   2576       if ((bios_drive_map[i] & 0xff) == from)
   2577 	break;
   2578 
   2579       if (! bios_drive_map[i])
   2580 	break;
   2581     }
   2582 
   2583   if (i == DRIVE_MAP_SIZE)
   2584     {
   2585       errnum = ERR_WONT_FIT;
   2586       return 1;
   2587     }
   2588 
   2589   if (to == from)
   2590     /* If TO is equal to FROM, delete the entry.  */
   2591     grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i + 1],
   2592 		  sizeof (unsigned short) * (DRIVE_MAP_SIZE - i));
   2593   else
   2594     bios_drive_map[i] = from | (to << 8);
   2595 
   2596   return 0;
   2597 }
   2598 
   2599 static struct builtin builtin_map =
   2600 {
   2601   "map",
   2602   map_func,
   2603   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   2604   "map TO_DRIVE FROM_DRIVE",
   2605   "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
   2606   " when you chain-load some operating systems, such as DOS, if such an"
   2607   " OS resides at a non-first drive."
   2608 };
   2609 
   2610 
   2611 #ifdef USE_MD5_PASSWORDS
   2613 /* md5crypt */
   2614 static int
   2615 md5crypt_func (char *arg, int flags)
   2616 {
   2617   char crypted[36];
   2618   char key[32];
   2619   unsigned int seed;
   2620   int i;
   2621   const char *const seedchars =
   2622     "./0123456789ABCDEFGHIJKLMNOPQRST"
   2623     "UVWXYZabcdefghijklmnopqrstuvwxyz";
   2624 
   2625   /* First create a salt.  */
   2626 
   2627   /* The magical prefix.  */
   2628   grub_memset (crypted, 0, sizeof (crypted));
   2629   grub_memmove (crypted, "$1$", 3);
   2630 
   2631   /* Create the length of a salt.  */
   2632   seed = currticks ();
   2633 
   2634   /* Generate a salt.  */
   2635   for (i = 0; i < 8 && seed; i++)
   2636     {
   2637       /* FIXME: This should be more random.  */
   2638       crypted[3 + i] = seedchars[seed & 0x3f];
   2639       seed >>= 6;
   2640     }
   2641 
   2642   /* A salt must be terminated with `$', if it is less than 8 chars.  */
   2643   crypted[3 + i] = '$';
   2644 
   2645 #ifdef DEBUG_MD5CRYPT
   2646   grub_printf ("salt = %s\n", crypted);
   2647 #endif
   2648 
   2649   /* Get a password.  */
   2650   grub_memset (key, 0, sizeof (key));
   2651   get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
   2652 
   2653   /* Crypt the key.  */
   2654   make_md5_password (key, crypted);
   2655 
   2656   grub_printf ("Encrypted: %s\n", crypted);
   2657   return 0;
   2658 }
   2659 
   2660 static struct builtin builtin_md5crypt =
   2661 {
   2662   "md5crypt",
   2663   md5crypt_func,
   2664   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   2665   "md5crypt",
   2666   "Generate a password in MD5 format."
   2667 };
   2668 #endif /* USE_MD5_PASSWORDS */
   2669 
   2670 
   2671 /* module */
   2673 static int
   2674 module_func (char *arg, int flags)
   2675 {
   2676   int len = grub_strlen (arg);
   2677 
   2678   switch (kernel_type)
   2679     {
   2680     case KERNEL_TYPE_MULTIBOOT:
   2681       if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN)
   2682 	{
   2683 	  errnum = ERR_WONT_FIT;
   2684 	  return 1;
   2685 	}
   2686       grub_memmove (mb_cmdline, arg, len + 1);
   2687       if (! load_module (arg, mb_cmdline))
   2688 	return 1;
   2689       mb_cmdline += len + 1;
   2690       break;
   2691 
   2692     case KERNEL_TYPE_LINUX:
   2693     case KERNEL_TYPE_BIG_LINUX:
   2694       if (! load_initrd (arg))
   2695 	return 1;
   2696       break;
   2697 
   2698     default:
   2699       errnum = ERR_NEED_MB_KERNEL;
   2700       return 1;
   2701     }
   2702 
   2703   return 0;
   2704 }
   2705 
   2706 static struct builtin builtin_module =
   2707 {
   2708   "module",
   2709   module_func,
   2710   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   2711   "module FILE [ARG ...]",
   2712   "Load a boot module FILE for a Multiboot format boot image (no"
   2713   " interpretation of the file contents is made, so users of this"
   2714   " command must know what the kernel in question expects). The"
   2715   " rest of the line is passed as the \"module command line\", like"
   2716   " the `kernel' command."
   2717 };
   2718 
   2719 
   2720 /* modulenounzip */
   2722 static int
   2723 modulenounzip_func (char *arg, int flags)
   2724 {
   2725   int ret;
   2726 
   2727 #ifndef NO_DECOMPRESSION
   2728   no_decompression = 1;
   2729 #endif
   2730 
   2731   ret = module_func (arg, flags);
   2732 
   2733 #ifndef NO_DECOMPRESSION
   2734   no_decompression = 0;
   2735 #endif
   2736 
   2737   return ret;
   2738 }
   2739 
   2740 static struct builtin builtin_modulenounzip =
   2741 {
   2742   "modulenounzip",
   2743   modulenounzip_func,
   2744   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   2745   "modulenounzip FILE [ARG ...]",
   2746   "The same as `module', except that automatic decompression is"
   2747   " disabled."
   2748 };
   2749 
   2750 
   2751 /* pager [on|off] */
   2753 static int
   2754 pager_func (char *arg, int flags)
   2755 {
   2756   /* If ARG is empty, toggle the flag.  */
   2757   if (! *arg)
   2758     use_pager = ! use_pager;
   2759   else if (grub_memcmp (arg, "on", 2) == 0)
   2760     use_pager = 1;
   2761   else if (grub_memcmp (arg, "off", 3) == 0)
   2762     use_pager = 0;
   2763   else
   2764     {
   2765       errnum = ERR_BAD_ARGUMENT;
   2766       return 1;
   2767     }
   2768 
   2769   grub_printf (" Internal pager is now %s\n", use_pager ? "on" : "off");
   2770   return 0;
   2771 }
   2772 
   2773 static struct builtin builtin_pager =
   2774 {
   2775   "pager",
   2776   pager_func,
   2777   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   2778   "pager [FLAG]",
   2779   "Toggle pager mode with no argument. If FLAG is given and its value"
   2780   " is `on', turn on the mode. If FLAG is `off', turn off the mode."
   2781 };
   2782 
   2783 
   2784 /* partnew PART TYPE START LEN */
   2786 static int
   2787 partnew_func (char *arg, int flags)
   2788 {
   2789   int new_type, new_start, new_len;
   2790   int start_cl, start_ch, start_dh;
   2791   int end_cl, end_ch, end_dh;
   2792   int entry;
   2793   char mbr[512];
   2794 
   2795   /* Convert a LBA address to a CHS address in the INT 13 format.  */
   2796   auto void lba_to_chs (int lba, int *cl, int *ch, int *dh);
   2797   void lba_to_chs (int lba, int *cl, int *ch, int *dh)
   2798     {
   2799       int cylinder, head, sector;
   2800 
   2801       sector = lba % buf_geom.sectors + 1;
   2802       head = (lba / buf_geom.sectors) % buf_geom.heads;
   2803       cylinder = lba / (buf_geom.sectors * buf_geom.heads);
   2804 
   2805       if (cylinder >= buf_geom.cylinders)
   2806 	cylinder = buf_geom.cylinders - 1;
   2807 
   2808       *cl = sector | ((cylinder & 0x300) >> 2);
   2809       *ch = cylinder & 0xFF;
   2810       *dh = head;
   2811     }
   2812 
   2813   /* Get the drive and the partition.  */
   2814   if (! set_device (arg))
   2815     return 1;
   2816 
   2817   /* The drive must be a hard disk.  */
   2818   if (! (current_drive & 0x80))
   2819     {
   2820       errnum = ERR_BAD_ARGUMENT;
   2821       return 1;
   2822     }
   2823 
   2824   /* The partition must a primary partition.  */
   2825   if ((current_partition >> 16) > 3
   2826       || (current_partition & 0xFFFF) != 0xFFFF)
   2827     {
   2828       errnum = ERR_BAD_ARGUMENT;
   2829       return 1;
   2830     }
   2831 
   2832   entry = current_partition >> 16;
   2833 
   2834   /* Get the new partition type.  */
   2835   arg = skip_to (0, arg);
   2836   if (! safe_parse_maxint (&arg, &new_type))
   2837     return 1;
   2838 
   2839   /* The partition type is unsigned char.  */
   2840   if (new_type > 0xFF)
   2841     {
   2842       errnum = ERR_BAD_ARGUMENT;
   2843       return 1;
   2844     }
   2845 
   2846   /* Get the new partition start.  */
   2847   arg = skip_to (0, arg);
   2848   if (! safe_parse_maxint (&arg, &new_start))
   2849     return 1;
   2850 
   2851   /* Get the new partition length.  */
   2852   arg = skip_to (0, arg);
   2853   if (! safe_parse_maxint (&arg, &new_len))
   2854     return 1;
   2855 
   2856   /* Read the MBR.  */
   2857   if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr))
   2858     return 1;
   2859 
   2860   /* Check if the new partition will fit in the disk.  */
   2861   if (new_start + new_len > buf_geom.total_sectors)
   2862     {
   2863       errnum = ERR_GEOM;
   2864       return 1;
   2865     }
   2866 
   2867   /* Store the partition information in the MBR.  */
   2868   lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
   2869   lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
   2870 
   2871   PC_SLICE_FLAG (mbr, entry) = 0;
   2872   PC_SLICE_HEAD (mbr, entry) = start_dh;
   2873   PC_SLICE_SEC (mbr, entry) = start_cl;
   2874   PC_SLICE_CYL (mbr, entry) = start_ch;
   2875   PC_SLICE_TYPE (mbr, entry) = new_type;
   2876   PC_SLICE_EHEAD (mbr, entry) = end_dh;
   2877   PC_SLICE_ESEC (mbr, entry) = end_cl;
   2878   PC_SLICE_ECYL (mbr, entry) = end_ch;
   2879   PC_SLICE_START (mbr, entry) = new_start;
   2880   PC_SLICE_LENGTH (mbr, entry) = new_len;
   2881 
   2882   /* Make sure that the MBR has a valid signature.  */
   2883   PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
   2884 
   2885   /* Write back the MBR to the disk.  */
   2886   buf_track = -1;
   2887   if (! rawwrite (current_drive, 0, mbr))
   2888     return 1;
   2889 
   2890   return 0;
   2891 }
   2892 
   2893 static struct builtin builtin_partnew =
   2894 {
   2895   "partnew",
   2896   partnew_func,
   2897   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   2898   "partnew PART TYPE START LEN",
   2899   "Create a primary partition at the starting address START with the"
   2900   " length LEN, with the type TYPE. START and LEN are in sector units."
   2901 };
   2902 
   2903 
   2904 /* parttype PART TYPE */
   2906 static int
   2907 parttype_func (char *arg, int flags)
   2908 {
   2909   int new_type;
   2910   unsigned long part = 0xFFFFFF;
   2911   unsigned long start, len, offset, ext_offset;
   2912   int entry, type;
   2913   char mbr[512];
   2914 
   2915   /* Get the drive and the partition.  */
   2916   if (! set_device (arg))
   2917     return 1;
   2918 
   2919   /* The drive must be a hard disk.  */
   2920   if (! (current_drive & 0x80))
   2921     {
   2922       errnum = ERR_BAD_ARGUMENT;
   2923       return 1;
   2924     }
   2925 
   2926   /* The partition must be a PC slice.  */
   2927   if ((current_partition >> 16) == 0xFF
   2928       || (current_partition & 0xFFFF) != 0xFFFF)
   2929     {
   2930       errnum = ERR_BAD_ARGUMENT;
   2931       return 1;
   2932     }
   2933 
   2934   /* Get the new partition type.  */
   2935   arg = skip_to (0, arg);
   2936   if (! safe_parse_maxint (&arg, &new_type))
   2937     return 1;
   2938 
   2939   /* The partition type is unsigned char.  */
   2940   if (new_type > 0xFF)
   2941     {
   2942       errnum = ERR_BAD_ARGUMENT;
   2943       return 1;
   2944     }
   2945 
   2946   /* Look for the partition.  */
   2947   while (next_partition (current_drive, 0xFFFFFF, &part, &type,
   2948 			 &start, &len, &offset, &entry,
   2949 			 &ext_offset, mbr))
   2950     {
   2951       if (part == current_partition)
   2952 	{
   2953 	  /* Found.  */
   2954 
   2955 	  /* Set the type to NEW_TYPE.  */
   2956 	  PC_SLICE_TYPE (mbr, entry) = new_type;
   2957 
   2958 	  /* Write back the MBR to the disk.  */
   2959 	  buf_track = -1;
   2960 	  if (! rawwrite (current_drive, offset, mbr))
   2961 	    return 1;
   2962 
   2963 	  /* Succeed.  */
   2964 	  return 0;
   2965 	}
   2966     }
   2967 
   2968   /* The partition was not found.  ERRNUM was set by next_partition.  */
   2969   return 1;
   2970 }
   2971 
   2972 static struct builtin builtin_parttype =
   2973 {
   2974   "parttype",
   2975   parttype_func,
   2976   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   2977   "parttype PART TYPE",
   2978   "Change the type of the partition PART to TYPE."
   2979 };
   2980 
   2981 
   2982 /* password */
   2984 static int
   2985 password_func (char *arg, int flags)
   2986 {
   2987   int len;
   2988   password_t type = PASSWORD_PLAIN;
   2989 
   2990 #ifdef USE_MD5_PASSWORDS
   2991   if (grub_memcmp (arg, "--md5", 5) == 0)
   2992     {
   2993       type = PASSWORD_MD5;
   2994       arg = skip_to (0, arg);
   2995     }
   2996 #endif
   2997   if (grub_memcmp (arg, "--", 2) == 0)
   2998     {
   2999       type = PASSWORD_UNSUPPORTED;
   3000       arg = skip_to (0, arg);
   3001     }
   3002 
   3003   if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
   3004     {
   3005       /* Do password check! */
   3006       char entered[32];
   3007 
   3008       /* Wipe out any previously entered password */
   3009       entered[0] = 0;
   3010       get_cmdline ("Password: ", entered, 31, '*', 0);
   3011 
   3012       nul_terminate (arg);
   3013       if (check_password (entered, arg, type) != 0)
   3014 	{
   3015 	  errnum = ERR_PRIVILEGED;
   3016 	  return 1;
   3017 	}
   3018     }
   3019   else
   3020     {
   3021       len = grub_strlen (arg);
   3022 
   3023       /* PASSWORD NUL NUL ... */
   3024       if (len + 2 > PASSWORD_BUFLEN)
   3025 	{
   3026 	  errnum = ERR_WONT_FIT;
   3027 	  return 1;
   3028 	}
   3029 
   3030       /* Copy the password and clear the rest of the buffer.  */
   3031       password = (char *) PASSWORD_BUF;
   3032       grub_memmove (password, arg, len);
   3033       grub_memset (password + len, 0, PASSWORD_BUFLEN - len);
   3034       password_type = type;
   3035     }
   3036   return 0;
   3037 }
   3038 
   3039 static struct builtin builtin_password =
   3040 {
   3041   "password",
   3042   password_func,
   3043   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
   3044   "password [--md5] PASSWD [FILE]",
   3045   "If used in the first section of a menu file, disable all"
   3046   " interactive editing control (menu entry editor and"
   3047   " command line). If the password PASSWD is entered, it loads the"
   3048   " FILE as a new config file and restarts the GRUB Stage 2. If you"
   3049   " omit the argument FILE, then GRUB just unlocks privileged"
   3050   " instructions.  You can also use it in the script section, in"
   3051   " which case it will ask for the password, before continueing."
   3052   " The option --md5 tells GRUB that PASSWD is encrypted with"
   3053   " md5crypt."
   3054 };
   3055 
   3056 
   3057 /* pause */
   3059 static int
   3060 pause_func (char *arg, int flags)
   3061 {
   3062   printf("%s\n", arg);
   3063 
   3064   /* If ESC is returned, then abort this entry.  */
   3065   if (ASCII_CHAR (getkey ()) == 27)
   3066     return 1;
   3067 
   3068   return 0;
   3069 }
   3070 
   3071 static struct builtin builtin_pause =
   3072 {
   3073   "pause",
   3074   pause_func,
   3075   BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
   3076   "pause [MESSAGE ...]",
   3077   "Print MESSAGE, then wait until a key is pressed."
   3078 };
   3079 
   3080 
   3081 #ifdef GRUB_UTIL
   3083 /* quit */
   3084 static int
   3085 quit_func (char *arg, int flags)
   3086 {
   3087   stop ();
   3088 
   3089   /* Never reach here.  */
   3090   return 0;
   3091 }
   3092 
   3093 static struct builtin builtin_quit =
   3094 {
   3095   "quit",
   3096   quit_func,
   3097   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   3098   "quit",
   3099   "Exit from the GRUB shell."
   3100 };
   3101 #endif /* GRUB_UTIL */
   3102 
   3103 
   3104 #ifdef SUPPORT_NETBOOT
   3106 /* rarp */
   3107 static int
   3108 rarp_func (char *arg, int flags)
   3109 {
   3110   if (! rarp ())
   3111     {
   3112       if (errnum == ERR_NONE)
   3113 	errnum = ERR_DEV_VALUES;
   3114 
   3115       return 1;
   3116     }
   3117 
   3118   /* Notify the configuration.  */
   3119   print_network_configuration ();
   3120   return 0;
   3121 }
   3122 
   3123 static struct builtin builtin_rarp =
   3124 {
   3125   "rarp",
   3126   rarp_func,
   3127   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   3128   "rarp",
   3129   "Initialize a network device via RARP."
   3130 };
   3131 #endif /* SUPPORT_NETBOOT */
   3132 
   3133 
   3134 static int
   3136 read_func (char *arg, int flags)
   3137 {
   3138   int addr;
   3139 
   3140   if (! safe_parse_maxint (&arg, &addr))
   3141     return 1;
   3142 
   3143   grub_printf ("Address 0x%x: Value 0x%x\n",
   3144 	       addr, *((unsigned *) RAW_ADDR (addr)));
   3145   return 0;
   3146 }
   3147 
   3148 static struct builtin builtin_read =
   3149 {
   3150   "read",
   3151   read_func,
   3152   BUILTIN_CMDLINE,
   3153   "read ADDR",
   3154   "Read a 32-bit value from memory at address ADDR and"
   3155   " display it in hex format."
   3156 };
   3157 
   3158 
   3159 /* reboot */
   3161 static int
   3162 reboot_func (char *arg, int flags)
   3163 {
   3164   grub_reboot ();
   3165 
   3166   /* Never reach here.  */
   3167   return 1;
   3168 }
   3169 
   3170 static struct builtin builtin_reboot =
   3171 {
   3172   "reboot",
   3173   reboot_func,
   3174   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   3175   "reboot",
   3176   "Reboot your system."
   3177 };
   3178 
   3179 
   3180 /* Print the root device information.  */
   3182 static void
   3183 print_root_device (void)
   3184 {
   3185   if (saved_drive == NETWORK_DRIVE)
   3186     {
   3187       /* Network drive.  */
   3188       grub_printf (" (nd):");
   3189     }
   3190   else if (saved_drive & 0x80)
   3191     {
   3192       /* Hard disk drive.  */
   3193       grub_printf (" (hd%d", saved_drive - 0x80);
   3194 
   3195       if ((saved_partition & 0xFF0000) != 0xFF0000)
   3196 	grub_printf (",%d", saved_partition >> 16);
   3197 
   3198       if ((saved_partition & 0x00FF00) != 0x00FF00)
   3199 	grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a');
   3200 
   3201       grub_printf ("):");
   3202     }
   3203   else
   3204     {
   3205       /* Floppy disk drive.  */
   3206       grub_printf (" (fd%d):", saved_drive);
   3207     }
   3208 
   3209   /* Print the filesystem information.  */
   3210   current_partition = saved_partition;
   3211   current_drive = saved_drive;
   3212   print_fsys_type ();
   3213 }
   3214 
   3215 static int
   3216 real_root_func (char *arg, int attempt_mount)
   3217 {
   3218   int hdbias = 0;
   3219   char *biasptr;
   3220   char *next;
   3221 
   3222   /* If ARG is empty, just print the current root device.  */
   3223   if (! *arg)
   3224     {
   3225       print_root_device ();
   3226       return 0;
   3227     }
   3228 
   3229   /* Call set_device to get the drive and the partition in ARG.  */
   3230   next = set_device (arg);
   3231   if (! next)
   3232     return 1;
   3233 
   3234   /* Ignore ERR_FSYS_MOUNT.  */
   3235   if (attempt_mount)
   3236     {
   3237       if (! open_device () && errnum != ERR_FSYS_MOUNT)
   3238 	return 1;
   3239     }
   3240   else
   3241     {
   3242       /* This is necessary, because the location of a partition table
   3243 	 must be set appropriately.  */
   3244       if (open_partition ())
   3245 	{
   3246 	  set_bootdev (0);
   3247 	  if (errnum)
   3248 	    return 1;
   3249 	}
   3250     }
   3251 
   3252   /* Clear ERRNUM.  */
   3253   errnum = 0;
   3254   saved_partition = current_partition;
   3255   saved_drive = current_drive;
   3256 
   3257   if (attempt_mount)
   3258     {
   3259       /* BSD and chainloading evil hacks !!  */
   3260       biasptr = skip_to (0, next);
   3261       safe_parse_maxint (&biasptr, &hdbias);
   3262       errnum = 0;
   3263       bootdev = set_bootdev (hdbias);
   3264       if (errnum)
   3265 	return 1;
   3266 
   3267       /* Print the type of the filesystem.  */
   3268       print_fsys_type ();
   3269     }
   3270 
   3271   return 0;
   3272 }
   3273 
   3274 static int
   3275 root_func (char *arg, int flags)
   3276 {
   3277   return real_root_func (arg, 1);
   3278 }
   3279 
   3280 static struct builtin builtin_root =
   3281 {
   3282   "root",
   3283   root_func,
   3284   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   3285   "root [DEVICE [HDBIAS]]",
   3286   "Set the current \"root device\" to the device DEVICE, then"
   3287   " attempt to mount it to get the partition size (for passing the"
   3288   " partition descriptor in `ES:ESI', used by some chain-loaded"
   3289   " bootloaders), the BSD drive-type (for booting BSD kernels using"
   3290   " their native boot format), and correctly determine "
   3291   " the PC partition where a BSD sub-partition is located. The"
   3292   " optional HDBIAS parameter is a number to tell a BSD kernel"
   3293   " how many BIOS drive numbers are on controllers before the current"
   3294   " one. For example, if there is an IDE disk and a SCSI disk, and your"
   3295   " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."
   3296 };
   3297 
   3298 
   3299 /* rootnoverify */
   3301 static int
   3302 rootnoverify_func (char *arg, int flags)
   3303 {
   3304   return real_root_func (arg, 0);
   3305 }
   3306 
   3307 static struct builtin builtin_rootnoverify =
   3308 {
   3309   "rootnoverify",
   3310   rootnoverify_func,
   3311   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   3312   "rootnoverify [DEVICE [HDBIAS]]",
   3313   "Similar to `root', but don't attempt to mount the partition. This"
   3314   " is useful for when an OS is outside of the area of the disk that"
   3315   " GRUB can read, but setting the correct root device is still"
   3316   " desired. Note that the items mentioned in `root' which"
   3317   " derived from attempting the mount will NOT work correctly."
   3318 };
   3319 
   3320 
   3321 /* savedefault */
   3323 static int
   3324 savedefault_func (char *arg, int flags)
   3325 {
   3326 #if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
   3327   unsigned long tmp_drive = saved_drive;
   3328   unsigned long tmp_partition = saved_partition;
   3329   char *default_file = (char *) DEFAULT_FILE_BUF;
   3330   char buf[10];
   3331   char sect[SECTOR_SIZE];
   3332   int entryno;
   3333   int sector_count = 0;
   3334   int saved_sectors[2];
   3335   int saved_offsets[2];
   3336   int saved_lengths[2];
   3337 
   3338   /* Save sector information about at most two sectors.  */
   3339   auto void disk_read_savesect_func (int sector, int offset, int length);
   3340   void disk_read_savesect_func (int sector, int offset, int length)
   3341     {
   3342       if (sector_count < 2)
   3343 	{
   3344 	  saved_sectors[sector_count] = sector;
   3345 	  saved_offsets[sector_count] = offset;
   3346 	  saved_lengths[sector_count] = length;
   3347 	}
   3348       sector_count++;
   3349     }
   3350 
   3351   /* This command is only useful when you boot an entry from the menu
   3352      interface.  */
   3353   if (! (flags & BUILTIN_SCRIPT))
   3354     {
   3355       errnum = ERR_UNRECOGNIZED;
   3356       return 1;
   3357     }
   3358 
   3359   /* Determine a saved entry number.  */
   3360   if (*arg)
   3361     {
   3362       if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0)
   3363 	{
   3364 	  int i;
   3365 	  int index = 0;
   3366 
   3367 	  for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
   3368 	    {
   3369 	      if (fallback_entries[i] < 0)
   3370 		break;
   3371 	      if (fallback_entries[i] == current_entryno)
   3372 		{
   3373 		  index = i + 1;
   3374 		  break;
   3375 		}
   3376 	    }
   3377 
   3378 	  if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0)
   3379 	    {
   3380 	      /* This is the last.  */
   3381 	      errnum = ERR_BAD_ARGUMENT;
   3382 	      return 1;
   3383 	    }
   3384 
   3385 	  entryno = fallback_entries[index];
   3386 	}
   3387       else if (! safe_parse_maxint (&arg, &entryno))
   3388 	return 1;
   3389     }
   3390   else
   3391     entryno = current_entryno;
   3392 
   3393   /* Open the default file.  */
   3394   saved_drive = boot_drive;
   3395   saved_partition = install_partition;
   3396   if (grub_open (default_file))
   3397     {
   3398       int len;
   3399 
   3400       disk_read_hook = disk_read_savesect_func;
   3401       len = grub_read (buf, sizeof (buf));
   3402       disk_read_hook = 0;
   3403       grub_close ();
   3404 
   3405       if (len != sizeof (buf))
   3406 	{
   3407 	  /* This is too small. Do not modify the file manually, please!  */
   3408 	  errnum = ERR_READ;
   3409 	  goto fail;
   3410 	}
   3411 
   3412       if (sector_count > 2)
   3413 	{
   3414 	  /* Is this possible?! Too fragmented!  */
   3415 	  errnum = ERR_FSYS_CORRUPT;
   3416 	  goto fail;
   3417 	}
   3418 
   3419       /* Set up a string to be written.  */
   3420       grub_memset (buf, '\n', sizeof (buf));
   3421       grub_sprintf (buf, "%d", entryno);
   3422 
   3423       if (saved_lengths[0] < sizeof (buf))
   3424 	{
   3425 	  /* The file is anchored to another file and the first few bytes
   3426 	     are spanned in two sectors. Uggh...  */
   3427 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
   3428 			 sect))
   3429 	    goto fail;
   3430 	  grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]);
   3431 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
   3432 	    goto fail;
   3433 
   3434 	  if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE,
   3435 			 sect))
   3436 	    goto fail;
   3437 	  grub_memmove (sect + saved_offsets[1],
   3438 			buf + saved_lengths[0],
   3439 			sizeof (buf) - saved_lengths[0]);
   3440 	  if (! rawwrite (current_drive, saved_sectors[1], sect))
   3441 	    goto fail;
   3442 	}
   3443       else
   3444 	{
   3445 	  /* This is a simple case. It fits into a single sector.  */
   3446 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
   3447 			 sect))
   3448 	    goto fail;
   3449 	  grub_memmove (sect + saved_offsets[0], buf, sizeof (buf));
   3450 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
   3451 	    goto fail;
   3452 	}
   3453 
   3454       /* Clear the cache.  */
   3455       buf_track = -1;
   3456     }
   3457 
   3458  fail:
   3459   saved_drive = tmp_drive;
   3460   saved_partition = tmp_partition;
   3461   return errnum;
   3462 #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
   3463   errnum = ERR_UNRECOGNIZED;
   3464   return 1;
   3465 #endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
   3466 }
   3467 
   3468 static struct builtin builtin_savedefault =
   3469 {
   3470   "savedefault",
   3471   savedefault_func,
   3472   BUILTIN_CMDLINE,
   3473   "savedefault [NUM | `fallback']",
   3474   "Save the current entry as the default boot entry if no argument is"
   3475   " specified. If a number is specified, this number is saved. If"
   3476   " `fallback' is used, next fallback entry is saved."
   3477 };
   3478 
   3479 
   3480 #ifdef SUPPORT_SERIAL
   3482 /* serial */
   3483 static int
   3484 serial_func (char *arg, int flags)
   3485 {
   3486   unsigned short port = serial_hw_get_port (0);
   3487   unsigned int speed = 9600;
   3488   int word_len = UART_8BITS_WORD;
   3489   int parity = UART_NO_PARITY;
   3490   int stop_bit_len = UART_1_STOP_BIT;
   3491 
   3492   /* Process GNU-style long options.
   3493      FIXME: We should implement a getopt-like function, to avoid
   3494      duplications.  */
   3495   while (1)
   3496     {
   3497       if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
   3498 	{
   3499 	  char *p = arg + sizeof ("--unit=") - 1;
   3500 	  int unit;
   3501 
   3502 	  if (! safe_parse_maxint (&p, &unit))
   3503 	    return 1;
   3504 
   3505 	  if (unit < 0 || unit > 3)
   3506 	    {
   3507 	      errnum = ERR_DEV_VALUES;
   3508 	      return 1;
   3509 	    }
   3510 
   3511 	  port = serial_hw_get_port (unit);
   3512 	}
   3513       else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0)
   3514 	{
   3515 	  char *p = arg + sizeof ("--speed=") - 1;
   3516 	  int num;
   3517 
   3518 	  if (! safe_parse_maxint (&p, &num))
   3519 	    return 1;
   3520 
   3521 	  speed = (unsigned int) num;
   3522 	}
   3523       else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
   3524 	{
   3525 	  char *p = arg + sizeof ("--port=") - 1;
   3526 	  int num;
   3527 
   3528 	  if (! safe_parse_maxint (&p, &num))
   3529 	    return 1;
   3530 
   3531 	  port = (unsigned short) num;
   3532 	}
   3533       else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
   3534 	{
   3535 	  char *p = arg + sizeof ("--word=") - 1;
   3536 	  int len;
   3537 
   3538 	  if (! safe_parse_maxint (&p, &len))
   3539 	    return 1;
   3540 
   3541 	  switch (len)
   3542 	    {
   3543 	    case 5: word_len = UART_5BITS_WORD; break;
   3544 	    case 6: word_len = UART_6BITS_WORD; break;
   3545 	    case 7: word_len = UART_7BITS_WORD; break;
   3546 	    case 8: word_len = UART_8BITS_WORD; break;
   3547 	    default:
   3548 	      errnum = ERR_BAD_ARGUMENT;
   3549 	      return 1;
   3550 	    }
   3551 	}
   3552       else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
   3553 	{
   3554 	  char *p = arg + sizeof ("--stop=") - 1;
   3555 	  int len;
   3556 
   3557 	  if (! safe_parse_maxint (&p, &len))
   3558 	    return 1;
   3559 
   3560 	  switch (len)
   3561 	    {
   3562 	    case 1: stop_bit_len = UART_1_STOP_BIT; break;
   3563 	    case 2: stop_bit_len = UART_2_STOP_BITS; break;
   3564 	    default:
   3565 	      errnum = ERR_BAD_ARGUMENT;
   3566 	      return 1;
   3567 	    }
   3568 	}
   3569       else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
   3570 	{
   3571 	  char *p = arg + sizeof ("--parity=") - 1;
   3572 
   3573 	  if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
   3574 	    parity = UART_NO_PARITY;
   3575 	  else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
   3576 	    parity = UART_ODD_PARITY;
   3577 	  else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
   3578 	    parity = UART_EVEN_PARITY;
   3579 	  else
   3580 	    {
   3581 	      errnum = ERR_BAD_ARGUMENT;
   3582 	      return 1;
   3583 	    }
   3584 	}
   3585 # ifdef GRUB_UTIL
   3586       /* In the grub shell, don't use any port number but open a tty
   3587 	 device instead.  */
   3588       else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
   3589 	{
   3590 	  char *p = arg + sizeof ("--device=") - 1;
   3591 	  char dev[256];	/* XXX */
   3592 	  char *q = dev;
   3593 
   3594 	  while (*p && ! grub_isspace (*p))
   3595 	    *q++ = *p++;
   3596 
   3597 	  *q = 0;
   3598 	  serial_set_device (dev);
   3599 	}
   3600 # endif /* GRUB_UTIL */
   3601       else
   3602 	break;
   3603 
   3604       arg = skip_to (0, arg);
   3605     }
   3606 
   3607   /* Initialize the serial unit.  */
   3608   if (! serial_hw_init (port, speed, word_len, parity, stop_bit_len))
   3609     {
   3610       errnum = ERR_BAD_ARGUMENT;
   3611       return 1;
   3612     }
   3613 
   3614   return 0;
   3615 }
   3616 
   3617 static struct builtin builtin_serial =
   3618 {
   3619   "serial",
   3620   serial_func,
   3621   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   3622   "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
   3623   "Initialize a serial device. UNIT is a digit that specifies which serial"
   3624   " device is used (e.g. 0 == COM1). If you need to specify the port number,"
   3625   " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
   3626   " PARITY is the type of parity, which is one of `no', `odd' and `even'."
   3627   " STOP is the length of stop bit(s). The option --device can be used only"
   3628   " in the grub shell, which specifies the file name of a tty device. The"
   3629   " default values are COM1, 9600, 8N1."
   3630 };
   3631 #endif /* SUPPORT_SERIAL */
   3632 
   3633 
   3634 /* setkey */
   3636 struct keysym
   3637 {
   3638   char *unshifted_name;			/* the name in unshifted state */
   3639   char *shifted_name;			/* the name in shifted state */
   3640   unsigned char unshifted_ascii;	/* the ascii code in unshifted state */
   3641   unsigned char shifted_ascii;		/* the ascii code in shifted state */
   3642   unsigned char keycode;		/* keyboard scancode */
   3643 };
   3644 
   3645 /* The table for key symbols. If the "shifted" member of an entry is
   3646    NULL, the entry does not have shifted state.  */
   3647 static struct keysym keysym_table[] =
   3648 {
   3649   {"escape",		0,		0x1b,	0,	0x01},
   3650   {"1",			"exclam",	'1',	'!',	0x02},
   3651   {"2",			"at",		'2',	'@',	0x03},
   3652   {"3",			"numbersign",	'3',	'#',	0x04},
   3653   {"4",			"dollar",	'4',	'$',	0x05},
   3654   {"5",			"percent",	'5',	'%',	0x06},
   3655   {"6",			"caret",	'6',	'^',	0x07},
   3656   {"7",			"ampersand",	'7',	'&',	0x08},
   3657   {"8",			"asterisk",	'8',	'*',	0x09},
   3658   {"9",			"parenleft",	'9',	'(',	0x0a},
   3659   {"0",			"parenright",	'0',	')',	0x0b},
   3660   {"minus",		"underscore",	'-',	'_',	0x0c},
   3661   {"equal",		"plus",		'=',	'+',	0x0d},
   3662   {"backspace",		0,		'\b',	0,	0x0e},
   3663   {"tab",		0,		'\t',	0,	0x0f},
   3664   {"q",			"Q",		'q',	'Q',	0x10},
   3665   {"w",			"W",		'w',	'W',	0x11},
   3666   {"e",			"E",		'e',	'E',	0x12},
   3667   {"r",			"R",		'r',	'R',	0x13},
   3668   {"t",			"T",		't',	'T',	0x14},
   3669   {"y",			"Y",		'y',	'Y',	0x15},
   3670   {"u",			"U",		'u',	'U',	0x16},
   3671   {"i",			"I",		'i',	'I',	0x17},
   3672   {"o",			"O",		'o',	'O',	0x18},
   3673   {"p",			"P",		'p',	'P',	0x19},
   3674   {"bracketleft",	"braceleft",	'[',	'{',	0x1a},
   3675   {"bracketright",	"braceright",	']',	'}',	0x1b},
   3676   {"enter",		0,		'\n',	0,	0x1c},
   3677   {"control",		0,		0,	0,	0x1d},
   3678   {"a",			"A",		'a',	'A',	0x1e},
   3679   {"s",			"S",		's',	'S',	0x1f},
   3680   {"d",			"D",		'd',	'D',	0x20},
   3681   {"f",			"F",		'f',	'F',	0x21},
   3682   {"g",			"G",		'g',	'G',	0x22},
   3683   {"h",			"H",		'h',	'H',	0x23},
   3684   {"j",			"J",		'j',	'J',	0x24},
   3685   {"k",			"K",		'k',	'K',	0x25},
   3686   {"l",			"L",		'l',	'L',	0x26},
   3687   {"semicolon",		"colon",	';',	':',	0x27},
   3688   {"quote",		"doublequote",	'\'',	'"',	0x28},
   3689   {"backquote",		"tilde",	'`',	'~',	0x29},
   3690   {"shift",		0,		0,	0,	0x2a},
   3691   {"backslash",		"bar",		'\\',	'|',	0x2b},
   3692   {"z",			"Z",		'z',	'Z',	0x2c},
   3693   {"x",			"X",		'x',	'X',	0x2d},
   3694   {"c",			"C",		'c',	'C',	0x2e},
   3695   {"v",			"V",		'v',	'V',	0x2f},
   3696   {"b",			"B",		'b',	'B',	0x30},
   3697   {"n",			"N",		'n',	'N',	0x31},
   3698   {"m",			"M",		'm',	'M',	0x32},
   3699   {"comma",		"less",		',',	'<',	0x33},
   3700   {"period",		"greater",	'.',	'>',	0x34},
   3701   {"slash",		"question",	'/',	'?',	0x35},
   3702   {"alt",		0,		0,	0,	0x38},
   3703   {"space",		0,		' ',	0,	0x39},
   3704   {"capslock",		0,		0,	0,	0x3a},
   3705   {"F1",		0,		0,	0,	0x3b},
   3706   {"F2",		0,		0,	0,	0x3c},
   3707   {"F3",		0,		0,	0,	0x3d},
   3708   {"F4",		0,		0,	0,	0x3e},
   3709   {"F5",		0,		0,	0,	0x3f},
   3710   {"F6",		0,		0,	0,	0x40},
   3711   {"F7",		0,		0,	0,	0x41},
   3712   {"F8",		0,		0,	0,	0x42},
   3713   {"F9",		0,		0,	0,	0x43},
   3714   {"F10",		0,		0,	0,	0x44},
   3715   /* Caution: do not add NumLock here! we cannot deal with it properly.  */
   3716   {"delete",		0,		0x7f,	0,	0x53}
   3717 };
   3718 
   3719 static int
   3720 setkey_func (char *arg, int flags)
   3721 {
   3722   char *to_key, *from_key;
   3723   int to_code, from_code;
   3724   int map_in_interrupt = 0;
   3725 
   3726   auto int find_key_code (char *key);
   3727   auto int find_ascii_code (char *key);
   3728 
   3729   auto int find_key_code (char *key)
   3730     {
   3731       int i;
   3732 
   3733       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
   3734 	{
   3735 	  if (keysym_table[i].unshifted_name &&
   3736 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
   3737 	    return keysym_table[i].keycode;
   3738 	  else if (keysym_table[i].shifted_name &&
   3739 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
   3740 	    return keysym_table[i].keycode;
   3741 	}
   3742 
   3743       return 0;
   3744     }
   3745 
   3746   auto int find_ascii_code (char *key)
   3747     {
   3748       int i;
   3749 
   3750       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
   3751 	{
   3752 	  if (keysym_table[i].unshifted_name &&
   3753 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
   3754 	    return keysym_table[i].unshifted_ascii;
   3755 	  else if (keysym_table[i].shifted_name &&
   3756 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
   3757 	    return keysym_table[i].shifted_ascii;
   3758 	}
   3759 
   3760       return 0;
   3761     }
   3762 
   3763   to_key = arg;
   3764   from_key = skip_to (0, to_key);
   3765 
   3766   if (! *to_key)
   3767     {
   3768       /* If the user specifies no argument, reset the key mappings.  */
   3769       grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
   3770       grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
   3771 
   3772       return 0;
   3773     }
   3774   else if (! *from_key)
   3775     {
   3776       /* The user must specify two arguments or zero argument.  */
   3777       errnum = ERR_BAD_ARGUMENT;
   3778       return 1;
   3779     }
   3780 
   3781   nul_terminate (to_key);
   3782   nul_terminate (from_key);
   3783 
   3784   to_code = find_ascii_code (to_key);
   3785   from_code = find_ascii_code (from_key);
   3786   if (! to_code || ! from_code)
   3787     {
   3788       map_in_interrupt = 1;
   3789       to_code = find_key_code (to_key);
   3790       from_code = find_key_code (from_key);
   3791       if (! to_code || ! from_code)
   3792 	{
   3793 	  errnum = ERR_BAD_ARGUMENT;
   3794 	  return 1;
   3795 	}
   3796     }
   3797 
   3798   if (map_in_interrupt)
   3799     {
   3800       int i;
   3801 
   3802       /* Find an empty slot.  */
   3803       for (i = 0; i < KEY_MAP_SIZE; i++)
   3804 	{
   3805 	  if ((bios_key_map[i] & 0xff) == from_code)
   3806 	    /* Perhaps the user wants to overwrite the map.  */
   3807 	    break;
   3808 
   3809 	  if (! bios_key_map[i])
   3810 	    break;
   3811 	}
   3812 
   3813       if (i == KEY_MAP_SIZE)
   3814 	{
   3815 	  errnum = ERR_WONT_FIT;
   3816 	  return 1;
   3817 	}
   3818 
   3819       if (to_code == from_code)
   3820 	/* If TO is equal to FROM, delete the entry.  */
   3821 	grub_memmove ((char *) &bios_key_map[i],
   3822 		      (char *) &bios_key_map[i + 1],
   3823 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
   3824       else
   3825 	bios_key_map[i] = (to_code << 8) | from_code;
   3826 
   3827       /* Ugly but should work.  */
   3828       unset_int15_handler ();
   3829       set_int15_handler ();
   3830     }
   3831   else
   3832     {
   3833       int i;
   3834 
   3835       /* Find an empty slot.  */
   3836       for (i = 0; i < KEY_MAP_SIZE; i++)
   3837 	{
   3838 	  if ((ascii_key_map[i] & 0xff) == from_code)
   3839 	    /* Perhaps the user wants to overwrite the map.  */
   3840 	    break;
   3841 
   3842 	  if (! ascii_key_map[i])
   3843 	    break;
   3844 	}
   3845 
   3846       if (i == KEY_MAP_SIZE)
   3847 	{
   3848 	  errnum = ERR_WONT_FIT;
   3849 	  return 1;
   3850 	}
   3851 
   3852       if (to_code == from_code)
   3853 	/* If TO is equal to FROM, delete the entry.  */
   3854 	grub_memmove ((char *) &ascii_key_map[i],
   3855 		      (char *) &ascii_key_map[i + 1],
   3856 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
   3857       else
   3858 	ascii_key_map[i] = (to_code << 8) | from_code;
   3859     }
   3860 
   3861   return 0;
   3862 }
   3863 
   3864 static struct builtin builtin_setkey =
   3865 {
   3866   "setkey",
   3867   setkey_func,
   3868   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   3869   "setkey [TO_KEY FROM_KEY]",
   3870   "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
   3871   " A key must be an alphabet, a digit, or one of these: escape, exclam,"
   3872   " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft,"
   3873   " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft,"
   3874   " braceleft, bracketright, braceright, enter, control, semicolon, colon,"
   3875   " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
   3876   " less, period, greater, slash, question, alt, space, capslock, FX (X"
   3877   " is a digit), and delete. If no argument is specified, reset key"
   3878   " mappings."
   3879 };
   3880 
   3881 
   3882 /* setup */
   3884 static int
   3885 setup_func (char *arg, int flags)
   3886 {
   3887   /* Point to the string of the installed drive/partition.  */
   3888   char *install_ptr;
   3889   /* Point to the string of the drive/parition where the GRUB images
   3890      reside.  */
   3891   char *image_ptr;
   3892   unsigned long installed_drive, installed_partition;
   3893   unsigned long image_drive, image_partition;
   3894   unsigned long tmp_drive, tmp_partition;
   3895   char stage1[64];
   3896   char stage2[64];
   3897   char config_filename[64];
   3898   char real_config_filename[64];
   3899   char cmd_arg[256];
   3900   char device[16];
   3901   char *buffer = (char *) RAW_ADDR (0x100000);
   3902   int is_force_lba = 0;
   3903   char *stage2_arg = 0;
   3904   char *prefix = 0;
   3905 
   3906   auto int check_file (char *file);
   3907   auto void sprint_device (int drive, int partition);
   3908   auto int embed_stage1_5 (char * stage1_5, int drive, int partition);
   3909 
   3910   /* Check if the file FILE exists like Autoconf.  */
   3911   int check_file (char *file)
   3912     {
   3913       int ret;
   3914 
   3915       grub_printf (" Checking if \"%s\" exists... ", file);
   3916       ret = grub_open (file);
   3917       if (ret)
   3918 	{
   3919 	  grub_close ();
   3920 	  grub_printf ("yes\n");
   3921 	}
   3922       else
   3923 	grub_printf ("no\n");
   3924 
   3925       return ret;
   3926     }
   3927 
   3928   /* Construct a device name in DEVICE.  */
   3929   void sprint_device (int drive, int partition)
   3930     {
   3931       grub_sprintf (device, "(%cd%d",
   3932 		    (drive & 0x80) ? 'h' : 'f',
   3933 		    drive & ~0x80);
   3934       if ((partition & 0xFF0000) != 0xFF0000)
   3935 	{
   3936 	  char tmp[16];
   3937 	  grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
   3938 	  grub_strncat (device, tmp, 256);
   3939 	}
   3940       if ((partition & 0x00FF00) != 0x00FF00)
   3941 	{
   3942 	  char tmp[16];
   3943 	  grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
   3944 	  grub_strncat (device, tmp, 256);
   3945 	}
   3946       grub_strncat (device, ")", 256);
   3947     }
   3948 
   3949   int embed_stage1_5 (char *stage1_5, int drive, int partition)
   3950     {
   3951       /* We install GRUB into the MBR, so try to embed the
   3952 	 Stage 1.5 in the sectors right after the MBR.  */
   3953       sprint_device (drive, partition);
   3954       grub_sprintf (cmd_arg, "%s %s", stage1_5, device);
   3955 
   3956       /* Notify what will be run.  */
   3957       grub_printf (" Running \"embed %s\"... ", cmd_arg);
   3958 
   3959       embed_func (cmd_arg, flags);
   3960       if (! errnum)
   3961 	{
   3962 	  /* Construct the blocklist representation.  */
   3963 	  grub_sprintf (buffer, "%s%s", device, embed_info);
   3964 	  grub_printf ("succeeded\n");
   3965 	  return 1;
   3966 	}
   3967       else
   3968 	{
   3969 	  grub_printf ("failed (this is not fatal)\n");
   3970 	  return 0;
   3971 	}
   3972     }
   3973 
   3974   struct stage1_5_map {
   3975     char *fsys;
   3976     char *name;
   3977   };
   3978   struct stage1_5_map stage1_5_map[] =
   3979   {
   3980     {"ext2fs",   "/e2fs_stage1_5"},
   3981     {"fat",      "/fat_stage1_5"},
   3982     {"ufs2",     "/ufs2_stage1_5"},
   3983     {"ffs",      "/ffs_stage1_5"},
   3984     {"iso9660",  "/iso9660_stage1_5"},
   3985     {"jfs",      "/jfs_stage1_5"},
   3986     {"minix",    "/minix_stage1_5"},
   3987     {"reiserfs", "/reiserfs_stage1_5"},
   3988     {"vstafs",   "/vstafs_stage1_5"},
   3989     {"xfs",      "/xfs_stage1_5"}
   3990   };
   3991 
   3992   tmp_drive = saved_drive;
   3993   tmp_partition = saved_partition;
   3994 
   3995   /* Check if the user specifies --force-lba.  */
   3996   while (1)
   3997     {
   3998       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
   3999 	{
   4000 	  is_force_lba = 1;
   4001 	  arg = skip_to (0, arg);
   4002 	}
   4003       else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) == 0)
   4004 	{
   4005 	  prefix = arg + sizeof ("--prefix=") - 1;
   4006 	  arg = skip_to (0, arg);
   4007 	  nul_terminate (prefix);
   4008 	}
   4009 #ifdef GRUB_UTIL
   4010       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
   4011 	{
   4012 	  stage2_arg = arg;
   4013 	  arg = skip_to (0, arg);
   4014 	  nul_terminate (stage2_arg);
   4015 	}
   4016 #endif /* GRUB_UTIL */
   4017       else
   4018 	break;
   4019     }
   4020 
   4021   install_ptr = arg;
   4022   image_ptr = skip_to (0, install_ptr);
   4023 
   4024   /* Make sure that INSTALL_PTR is valid.  */
   4025   set_device (install_ptr);
   4026   if (errnum)
   4027     return 1;
   4028 
   4029   installed_drive = current_drive;
   4030   installed_partition = current_partition;
   4031 
   4032   /* Mount the drive pointed by IMAGE_PTR.  */
   4033   if (*image_ptr)
   4034     {
   4035       /* If the drive/partition where the images reside is specified,
   4036 	 get the drive and the partition.  */
   4037       set_device (image_ptr);
   4038       if (errnum)
   4039 	return 1;
   4040     }
   4041   else
   4042     {
   4043       /* If omitted, use SAVED_PARTITION and SAVED_DRIVE.  */
   4044       current_drive = saved_drive;
   4045       current_partition = saved_partition;
   4046     }
   4047 
   4048   image_drive = saved_drive = current_drive;
   4049   image_partition = saved_partition = current_partition;
   4050 
   4051   /* Open it.  */
   4052   if (! open_device ())
   4053     goto fail;
   4054 
   4055   /* Check if stage1 exists. If the user doesn't specify the option
   4056      `--prefix', attempt /boot/grub and /grub.  */
   4057   /* NOTE: It is dangerous to run this command without `--prefix' in the
   4058      grub shell, since that affects `--stage2'.  */
   4059   if (! prefix)
   4060     {
   4061       prefix = "/boot/grub";
   4062       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
   4063       if (! check_file (stage1))
   4064 	{
   4065 	  errnum = ERR_NONE;
   4066 	  prefix = "/grub";
   4067 	  grub_sprintf (stage1, "%s%s", prefix, "/stage1");
   4068 	  if (! check_file (stage1))
   4069 	    goto fail;
   4070 	}
   4071     }
   4072   else
   4073     {
   4074       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
   4075       if (! check_file (stage1))
   4076 	goto fail;
   4077     }
   4078 
   4079   /* The prefix was determined.  */
   4080   grub_sprintf (stage2, "%s%s", prefix, "/stage2");
   4081   grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst");
   4082   *real_config_filename = 0;
   4083 
   4084   /* Check if stage2 exists.  */
   4085   if (! check_file (stage2))
   4086     goto fail;
   4087 
   4088   {
   4089     char *fsys = fsys_table[fsys_type].name;
   4090     int i;
   4091     int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]);
   4092 
   4093     /* Iterate finding the same filesystem name as FSYS.  */
   4094     for (i = 0; i < size; i++)
   4095       if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0)
   4096 	{
   4097 	  /* OK, check if the Stage 1.5 exists.  */
   4098 	  char stage1_5[64];
   4099 
   4100 	  grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name);
   4101 	  if (check_file (stage1_5))
   4102 	    {
   4103 	      if (embed_stage1_5 (stage1_5,
   4104 				    installed_drive, installed_partition)
   4105 		  || embed_stage1_5 (stage1_5,
   4106 				     image_drive, image_partition))
   4107 		{
   4108 		  grub_strcpy (real_config_filename, config_filename);
   4109 		  sprint_device (image_drive, image_partition);
   4110 		  grub_sprintf (config_filename, "%s%s", device, stage2);
   4111 		  grub_strcpy (stage2, buffer);
   4112 		}
   4113 	    }
   4114 	  errnum = 0;
   4115 	  break;
   4116 	}
   4117   }
   4118 
   4119   /* Construct a string that is used by the command "install" as its
   4120      arguments.  */
   4121   sprint_device (installed_drive, installed_partition);
   4122 
   4123 #if 1
   4124   /* Don't embed a drive number unnecessarily.  */
   4125   grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s",
   4126 		is_force_lba? "--force-lba " : "",
   4127 		stage2_arg? stage2_arg : "",
   4128 		stage2_arg? " " : "",
   4129 		stage1,
   4130 		(installed_drive != image_drive) ? "d " : "",
   4131 		device,
   4132 		stage2,
   4133 		config_filename,
   4134 		real_config_filename);
   4135 #else /* NOT USED */
   4136   /* This code was used, because we belived some BIOSes had a problem
   4137      that they didn't pass a booting drive correctly. It turned out,
   4138      however, stage1 could trash a booting drive when checking LBA support,
   4139      because some BIOSes modified the register %dx in INT 13H, AH=48H.
   4140      So it becamed unclear whether GRUB should use a pre-defined booting
   4141      drive or not. If the problem still exists, it would be necessary to
   4142      switch back to this code.  */
   4143   grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s",
   4144 		is_force_lba? "--force-lba " : "",
   4145 		stage2_arg? stage2_arg : "",
   4146 		stage2_arg? " " : "",
   4147 		stage1,
   4148 		device,
   4149 		stage2,
   4150 		config_filename,
   4151 		real_config_filename);
   4152 #endif /* NOT USED */
   4153 
   4154   /* Notify what will be run.  */
   4155   grub_printf (" Running \"install %s\"... ", cmd_arg);
   4156 
   4157   /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical
   4158      with IMAGE_DRIVE and IMAGE_PARTITION, respectively.  */
   4159   saved_drive = image_drive;
   4160   saved_partition = image_partition;
   4161 
   4162   /* Run the command.  */
   4163   if (! install_func (cmd_arg, flags))
   4164     grub_printf ("succeeded\nDone.\n");
   4165   else
   4166     grub_printf ("failed\n");
   4167 
   4168  fail:
   4169   saved_drive = tmp_drive;
   4170   saved_partition = tmp_partition;
   4171   return errnum;
   4172 }
   4173 
   4174 static struct builtin builtin_setup =
   4175 {
   4176   "setup",
   4177   setup_func,
   4178   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   4179   "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
   4180   "Set up the installation of GRUB automatically. This command uses"
   4181   " the more flexible command \"install\" in the backend and installs"
   4182   " GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified,"
   4183   " then find the GRUB images in the device IMAGE_DEVICE, otherwise"
   4184   " use the current \"root device\", which can be set by the command"
   4185   " \"root\". If you know that your BIOS should support LBA but GRUB"
   4186   " doesn't work in LBA mode, specify the option `--force-lba'."
   4187   " If you install GRUB under the grub shell and you cannot unmount the"
   4188   " partition where GRUB images reside, specify the option `--stage2'"
   4189   " to tell GRUB the file name under your OS."
   4190 };
   4191 
   4192 
   4193 #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
   4195 /* terminal */
   4196 static int
   4197 terminal_func (char *arg, int flags)
   4198 {
   4199   /* The index of the default terminal in TERM_TABLE.  */
   4200   int default_term = -1;
   4201   struct term_entry *prev_term = current_term;
   4202   int to = -1;
   4203   int lines = 0;
   4204   int no_message = 0;
   4205   unsigned long term_flags = 0;
   4206   /* XXX: Assume less than 32 terminals.  */
   4207   unsigned long term_bitmap = 0;
   4208 
   4209   /* Get GNU-style long options.  */
   4210   while (1)
   4211     {
   4212       if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0)
   4213 	term_flags |= TERM_DUMB;
   4214       else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0)
   4215 	/* ``--no-echo'' implies ``--no-edit''.  */
   4216 	term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT);
   4217       else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0)
   4218 	term_flags |= TERM_NO_EDIT;
   4219       else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0)
   4220 	{
   4221 	  char *val = arg + sizeof ("--timeout=") - 1;
   4222 
   4223 	  if (! safe_parse_maxint (&val, &to))
   4224 	    return 1;
   4225 	}
   4226       else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0)
   4227 	{
   4228 	  char *val = arg + sizeof ("--lines=") - 1;
   4229 
   4230 	  if (! safe_parse_maxint (&val, &lines))
   4231 	    return 1;
   4232 
   4233 	  /* Probably less than four is meaningless....  */
   4234 	  if (lines < 4)
   4235 	    {
   4236 	      errnum = ERR_BAD_ARGUMENT;
   4237 	      return 1;
   4238 	    }
   4239 	}
   4240       else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0)
   4241 	no_message = 1;
   4242       else
   4243 	break;
   4244 
   4245       arg = skip_to (0, arg);
   4246     }
   4247 
   4248   /* If no argument is specified, show current setting.  */
   4249   if (! *arg)
   4250     {
   4251       grub_printf ("%s%s%s%s\n",
   4252 		   current_term->name,
   4253 		   current_term->flags & TERM_DUMB ? " (dumb)" : "",
   4254 		   current_term->flags & TERM_NO_EDIT ? " (no edit)" : "",
   4255 		   current_term->flags & TERM_NO_ECHO ? " (no echo)" : "");
   4256       return 0;
   4257     }
   4258 
   4259   while (*arg)
   4260     {
   4261       int i;
   4262       char *next = skip_to (0, arg);
   4263 
   4264       nul_terminate (arg);
   4265 
   4266       for (i = 0; term_table[i].name; i++)
   4267 	{
   4268 	  if (grub_strcmp (arg, term_table[i].name) == 0)
   4269 	    {
   4270 	      if (term_table[i].flags & TERM_NEED_INIT)
   4271 		{
   4272 		  errnum = ERR_DEV_NEED_INIT;
   4273 		  return 1;
   4274 		}
   4275 
   4276 	      if (default_term < 0)
   4277 		default_term = i;
   4278 
   4279 	      term_bitmap |= (1 << i);
   4280 	      break;
   4281 	    }
   4282 	}
   4283 
   4284       if (! term_table[i].name)
   4285 	{
   4286 	  errnum = ERR_BAD_ARGUMENT;
   4287 	  return 1;
   4288 	}
   4289 
   4290       arg = next;
   4291     }
   4292 
   4293   /* If multiple terminals are specified, wait until the user pushes any
   4294      key on one of the terminals.  */
   4295   if (term_bitmap & ~(1 << default_term))
   4296     {
   4297       int time1, time2 = -1;
   4298 
   4299       /* XXX: Disable the pager.  */
   4300       count_lines = -1;
   4301 
   4302       /* Get current time.  */
   4303       while ((time1 = getrtsecs ()) == 0xFF)
   4304 	;
   4305 
   4306       /* Wait for a key input.  */
   4307       while (to)
   4308 	{
   4309 	  int i;
   4310 
   4311 	  for (i = 0; term_table[i].name; i++)
   4312 	    {
   4313 	      if (term_bitmap & (1 << i))
   4314 		{
   4315 		  if (term_table[i].checkkey () >= 0)
   4316 		    {
   4317 		      (void) term_table[i].getkey ();
   4318 		      default_term = i;
   4319 
   4320 		      goto end;
   4321 		    }
   4322 		}
   4323 	    }
   4324 
   4325 	  /* Prompt the user, once per sec.  */
   4326 	  if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
   4327 	    {
   4328 	      if (! no_message)
   4329 		{
   4330 		  /* Need to set CURRENT_TERM to each of selected
   4331 		     terminals.  */
   4332 		  for (i = 0; term_table[i].name; i++)
   4333 		    if (term_bitmap & (1 << i))
   4334 		      {
   4335 			current_term = term_table + i;
   4336 			grub_printf ("\rPress any key to continue.\n");
   4337 		      }
   4338 
   4339 		  /* Restore CURRENT_TERM.  */
   4340 		  current_term = prev_term;
   4341 		}
   4342 
   4343 	      time2 = time1;
   4344 	      if (to > 0)
   4345 		to--;
   4346 	    }
   4347 	}
   4348     }
   4349 
   4350  end:
   4351   current_term = term_table + default_term;
   4352   current_term->flags = term_flags;
   4353 
   4354   if (lines)
   4355     max_lines = lines;
   4356   else
   4357     /* 24 would be a good default value.  */
   4358     max_lines = 24;
   4359 
   4360   /* If the interface is currently the command-line,
   4361      restart it to repaint the screen.  */
   4362   if (current_term != prev_term && (flags & BUILTIN_CMDLINE))
   4363     grub_longjmp (restart_cmdline_env, 0);
   4364 
   4365   return 0;
   4366 }
   4367 
   4368 static struct builtin builtin_terminal =
   4369 {
   4370   "terminal",
   4371   terminal_func,
   4372   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   4373   "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules]",
   4374   "Select a terminal. When multiple terminals are specified, wait until"
   4375   " you push any key to continue. If both console and serial are specified,"
   4376   " the terminal to which you input a key first will be selected. If no"
   4377   " argument is specified, print current setting. The option --dumb"
   4378   " specifies that your terminal is dumb, otherwise, vt100-compatibility"
   4379   " is assumed. If you specify --no-echo, input characters won't be echoed."
   4380   " If you specify --no-edit, the BASH-like editing feature will be disabled."
   4381   " If --timeout is present, this command will wait at most for SECS"
   4382   " seconds. The option --lines specifies the maximum number of lines."
   4383   " The option --silent is used to suppress messages."
   4384 };
   4385 #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */
   4386 
   4387 
   4388 #ifdef SUPPORT_SERIAL
   4390 static int
   4391 terminfo_func (char *arg, int flags)
   4392 {
   4393   struct terminfo term;
   4394 
   4395   if (*arg)
   4396     {
   4397       struct
   4398       {
   4399 	const char *name;
   4400 	char *var;
   4401       }
   4402       options[] =
   4403 	{
   4404 	  {"--name=", term.name},
   4405 	  {"--cursor-address=", term.cursor_address},
   4406 	  {"--clear-screen=", term.clear_screen},
   4407 	  {"--enter-standout-mode=", term.enter_standout_mode},
   4408 	  {"--exit-standout-mode=", term.exit_standout_mode}
   4409 	};
   4410 
   4411       grub_memset (&term, 0, sizeof (term));
   4412 
   4413       while (*arg)
   4414 	{
   4415 	  int i;
   4416 	  char *next = skip_to (0, arg);
   4417 
   4418 	  nul_terminate (arg);
   4419 
   4420 	  for (i = 0; i < sizeof (options) / sizeof (options[0]); i++)
   4421 	    {
   4422 	      const char *name = options[i].name;
   4423 	      int len = grub_strlen (name);
   4424 
   4425 	      if (! grub_memcmp (arg, name, len))
   4426 		{
   4427 		  grub_strcpy (options[i].var, ti_unescape_string (arg + len));
   4428 		  break;
   4429 		}
   4430 	    }
   4431 
   4432 	  if (i == sizeof (options) / sizeof (options[0]))
   4433 	    {
   4434 	      errnum = ERR_BAD_ARGUMENT;
   4435 	      return errnum;
   4436 	    }
   4437 
   4438 	  arg = next;
   4439 	}
   4440 
   4441       if (term.name[0] == 0 || term.cursor_address[0] == 0)
   4442 	{
   4443 	  errnum = ERR_BAD_ARGUMENT;
   4444 	  return errnum;
   4445 	}
   4446 
   4447       ti_set_term (&term);
   4448     }
   4449   else
   4450     {
   4451       /* No option specifies printing out current settings.  */
   4452       ti_get_term (&term);
   4453 
   4454       grub_printf ("name=%s\n",
   4455 		   ti_escape_string (term.name));
   4456       grub_printf ("cursor_address=%s\n",
   4457 		   ti_escape_string (term.cursor_address));
   4458       grub_printf ("clear_screen=%s\n",
   4459 		   ti_escape_string (term.clear_screen));
   4460       grub_printf ("enter_standout_mode=%s\n",
   4461 		   ti_escape_string (term.enter_standout_mode));
   4462       grub_printf ("exit_standout_mode=%s\n",
   4463 		   ti_escape_string (term.exit_standout_mode));
   4464     }
   4465 
   4466   return 0;
   4467 }
   4468 
   4469 static struct builtin builtin_terminfo =
   4470 {
   4471   "terminfo",
   4472   terminfo_func,
   4473   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   4474   "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]"
   4475   " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]",
   4476 
   4477   "Define the capabilities of your terminal. Use this command to"
   4478   " define escape sequences, if it is not vt100-compatible."
   4479   " You may use \\e for ESC and ^X for a control character."
   4480   " If no option is specified, the current settings are printed."
   4481 };
   4482 #endif /* SUPPORT_SERIAL */
   4483 
   4484 
   4485 /* testload */
   4487 static int
   4488 testload_func (char *arg, int flags)
   4489 {
   4490   int i;
   4491 
   4492   kernel_type = KERNEL_TYPE_NONE;
   4493 
   4494   if (! grub_open (arg))
   4495     return 1;
   4496 
   4497   disk_read_hook = disk_read_print_func;
   4498 
   4499   /* Perform filesystem test on the specified file.  */
   4500   /* Read whole file first. */
   4501   grub_printf ("Whole file: ");
   4502 
   4503   grub_read ((char *) RAW_ADDR (0x100000), -1);
   4504 
   4505   /* Now compare two sections of the file read differently.  */
   4506 
   4507   for (i = 0; i < 0x10ac0; i++)
   4508     {
   4509       *((unsigned char *) RAW_ADDR (0x200000 + i)) = 0;
   4510       *((unsigned char *) RAW_ADDR (0x300000 + i)) = 1;
   4511     }
   4512 
   4513   /* First partial read.  */
   4514   grub_printf ("\nPartial read 1: ");
   4515 
   4516   grub_seek (0);
   4517   grub_read ((char *) RAW_ADDR (0x200000), 0x7);
   4518   grub_read ((char *) RAW_ADDR (0x200007), 0x100);
   4519   grub_read ((char *) RAW_ADDR (0x200107), 0x10);
   4520   grub_read ((char *) RAW_ADDR (0x200117), 0x999);
   4521   grub_read ((char *) RAW_ADDR (0x200ab0), 0x10);
   4522   grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000);
   4523 
   4524   /* Second partial read.  */
   4525   grub_printf ("\nPartial read 2: ");
   4526 
   4527   grub_seek (0);
   4528   grub_read ((char *) RAW_ADDR (0x300000), 0x10000);
   4529   grub_read ((char *) RAW_ADDR (0x310000), 0x10);
   4530   grub_read ((char *) RAW_ADDR (0x310010), 0x7);
   4531   grub_read ((char *) RAW_ADDR (0x310017), 0x10);
   4532   grub_read ((char *) RAW_ADDR (0x310027), 0x999);
   4533   grub_read ((char *) RAW_ADDR (0x3109c0), 0x100);
   4534 
   4535   grub_printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
   4536 	       *((int *) RAW_ADDR (0x200000)),
   4537 	       *((int *) RAW_ADDR (0x200004)),
   4538 	       *((int *) RAW_ADDR (0x200008)),
   4539 	       *((int *) RAW_ADDR (0x20000c)));
   4540 
   4541   grub_printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
   4542 	       *((int *) RAW_ADDR (0x300000)),
   4543 	       *((int *) RAW_ADDR (0x300004)),
   4544 	       *((int *) RAW_ADDR (0x300008)),
   4545 	       *((int *) RAW_ADDR (0x30000c)));
   4546 
   4547   for (i = 0; i < 0x10ac0; i++)
   4548     if (*((unsigned char *) RAW_ADDR (0x200000 + i))
   4549 	!= *((unsigned char *) RAW_ADDR (0x300000 + i)))
   4550       break;
   4551 
   4552   grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos);
   4553   disk_read_hook = 0;
   4554   grub_close ();
   4555   return 0;
   4556 }
   4557 
   4558 static struct builtin builtin_testload =
   4559 {
   4560   "testload",
   4561   testload_func,
   4562   BUILTIN_CMDLINE,
   4563   "testload FILE",
   4564   "Read the entire contents of FILE in several different ways and"
   4565   " compares them, to test the filesystem code. The output is somewhat"
   4566   " cryptic, but if no errors are reported and the final `i=X,"
   4567   " filepos=Y' reading has X and Y equal, then it is definitely"
   4568   " consistent, and very likely works correctly subject to a"
   4569   " consistent offset error. If this test succeeds, then a good next"
   4570   " step is to try loading a kernel."
   4571 };
   4572 
   4573 
   4574 /* testvbe MODE */
   4576 static int
   4577 testvbe_func (char *arg, int flags)
   4578 {
   4579   int mode_number;
   4580   struct vbe_controller controller;
   4581   struct vbe_mode mode;
   4582 
   4583   if (! *arg)
   4584     {
   4585       errnum = ERR_BAD_ARGUMENT;
   4586       return 1;
   4587     }
   4588 
   4589   if (! safe_parse_maxint (&arg, &mode_number))
   4590     return 1;
   4591 
   4592   /* Preset `VBE2'.  */
   4593   grub_memmove (controller.signature, "VBE2", 4);
   4594 
   4595   /* Detect VBE BIOS.  */
   4596   if (get_vbe_controller_info (&controller) != 0x004F)
   4597     {
   4598       grub_printf (" VBE BIOS is not present.\n");
   4599       return 0;
   4600     }
   4601 
   4602   if (controller.version < 0x0200)
   4603     {
   4604       grub_printf (" VBE version %d.%d is not supported.\n",
   4605 		   (int) (controller.version >> 8),
   4606 		   (int) (controller.version & 0xFF));
   4607       return 0;
   4608     }
   4609 
   4610   if (get_vbe_mode_info (mode_number, &mode) != 0x004F
   4611       || (mode.mode_attributes & 0x0091) != 0x0091)
   4612     {
   4613       grub_printf (" Mode 0x%x is not supported.\n", mode_number);
   4614       return 0;
   4615     }
   4616 
   4617   /* Now trip to the graphics mode.  */
   4618   if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
   4619     {
   4620       grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
   4621       return 0;
   4622     }
   4623 
   4624   /* Draw something on the screen...  */
   4625   {
   4626     unsigned char *base_buf = (unsigned char *) mode.phys_base;
   4627     int scanline = controller.version >= 0x0300
   4628       ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline;
   4629     /* FIXME: this assumes that any depth is a modulo of 8.  */
   4630     int bpp = mode.bits_per_pixel / 8;
   4631     int width = mode.x_resolution;
   4632     int height = mode.y_resolution;
   4633     int x, y;
   4634     unsigned color = 0;
   4635 
   4636     /* Iterate drawing on the screen, until the user hits any key.  */
   4637     while (checkkey () == -1)
   4638       {
   4639 	for (y = 0; y < height; y++)
   4640 	  {
   4641 	    unsigned char *line_buf = base_buf + scanline * y;
   4642 
   4643 	    for (x = 0; x < width; x++)
   4644 	      {
   4645 		unsigned char *buf = line_buf + bpp * x;
   4646 		int i;
   4647 
   4648 		for (i = 0; i < bpp; i++, buf++)
   4649 		  *buf = (color >> (i * 8)) & 0xff;
   4650 	      }
   4651 
   4652 	    color++;
   4653 	  }
   4654       }
   4655 
   4656     /* Discard the input.  */
   4657     getkey ();
   4658   }
   4659 
   4660   /* Back to the default text mode.  */
   4661   if (set_vbe_mode (0x03) != 0x004F)
   4662     {
   4663       /* Why?!  */
   4664       grub_reboot ();
   4665     }
   4666 
   4667   return 0;
   4668 }
   4669 
   4670 static struct builtin builtin_testvbe =
   4671 {
   4672   "testvbe",
   4673   testvbe_func,
   4674   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   4675   "testvbe MODE",
   4676   "Test the VBE mode MODE. Hit any key to return."
   4677 };
   4678 
   4679 
   4680 #ifdef SUPPORT_NETBOOT
   4682 /* tftpserver */
   4683 static int
   4684 tftpserver_func (char *arg, int flags)
   4685 {
   4686   if (! *arg || ! ifconfig (0, 0, 0, arg))
   4687     {
   4688       errnum = ERR_BAD_ARGUMENT;
   4689       return 1;
   4690     }
   4691 
   4692   print_network_configuration ();
   4693   return 0;
   4694 }
   4695 
   4696 static struct builtin builtin_tftpserver =
   4697 {
   4698   "tftpserver",
   4699   tftpserver_func,
   4700   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   4701   "tftpserver IPADDR",
   4702   "Override the TFTP server address."
   4703 };
   4704 #endif /* SUPPORT_NETBOOT */
   4705 
   4706 
   4707 /* timeout */
   4709 static int
   4710 timeout_func (char *arg, int flags)
   4711 {
   4712   if (! safe_parse_maxint (&arg, &grub_timeout))
   4713     return 1;
   4714 
   4715   return 0;
   4716 }
   4717 
   4718 static struct builtin builtin_timeout =
   4719 {
   4720   "timeout",
   4721   timeout_func,
   4722   BUILTIN_MENU,
   4723 #if 0
   4724   "timeout SEC",
   4725   "Set a timeout, in SEC seconds, before automatically booting the"
   4726   " default entry (normally the first entry defined)."
   4727 #endif
   4728 };
   4729 
   4730 
   4731 /* title */
   4733 static int
   4734 title_func (char *arg, int flags)
   4735 {
   4736   /* This function is not actually used at least currently.  */
   4737   return 0;
   4738 }
   4739 
   4740 static struct builtin builtin_title =
   4741 {
   4742   "title",
   4743   title_func,
   4744   BUILTIN_TITLE,
   4745 #if 0
   4746   "title [NAME ...]",
   4747   "Start a new boot entry, and set its name to the contents of the"
   4748   " rest of the line, starting with the first non-space character."
   4749 #endif
   4750 };
   4751 
   4752 
   4753 /* unhide */
   4755 static int
   4756 unhide_func (char *arg, int flags)
   4757 {
   4758   if (! set_device (arg))
   4759     return 1;
   4760 
   4761   if (! set_partition_hidden_flag (0))
   4762     return 1;
   4763 
   4764   return 0;
   4765 }
   4766 
   4767 static struct builtin builtin_unhide =
   4768 {
   4769   "unhide",
   4770   unhide_func,
   4771   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
   4772   "unhide PARTITION",
   4773   "Unhide PARTITION by clearing the \"hidden\" bit in its"
   4774   " partition type code."
   4775 };
   4776 
   4777 
   4778 /* uppermem */
   4780 static int
   4781 uppermem_func (char *arg, int flags)
   4782 {
   4783   if (! safe_parse_maxint (&arg, (int *) &mbi.mem_upper))
   4784     return 1;
   4785 
   4786   mbi.flags &= ~MB_INFO_MEM_MAP;
   4787   return 0;
   4788 }
   4789 
   4790 static struct builtin builtin_uppermem =
   4791 {
   4792   "uppermem",
   4793   uppermem_func,
   4794   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   4795   "uppermem KBYTES",
   4796   "Force GRUB to assume that only KBYTES kilobytes of upper memory are"
   4797   " installed.  Any system address range maps are discarded."
   4798 };
   4799 
   4800 
   4801 /* vbeprobe */
   4803 static int
   4804 vbeprobe_func (char *arg, int flags)
   4805 {
   4806   struct vbe_controller controller;
   4807   unsigned short *mode_list;
   4808   int mode_number = -1;
   4809 
   4810   auto unsigned long vbe_far_ptr_to_linear (unsigned long);
   4811 
   4812   unsigned long vbe_far_ptr_to_linear (unsigned long ptr)
   4813     {
   4814       unsigned short seg = (ptr >> 16);
   4815       unsigned short off = (ptr & 0xFFFF);
   4816 
   4817       return (seg << 4) + off;
   4818     }
   4819 
   4820   if (*arg)
   4821     {
   4822       if (! safe_parse_maxint (&arg, &mode_number))
   4823 	return 1;
   4824     }
   4825 
   4826   /* Set the signature to `VBE2', to obtain VBE 3.0 information.  */
   4827   grub_memmove (controller.signature, "VBE2", 4);
   4828 
   4829   if (get_vbe_controller_info (&controller) != 0x004F)
   4830     {
   4831       grub_printf (" VBE BIOS is not present.\n");
   4832       return 0;
   4833     }
   4834 
   4835   /* Check the version.  */
   4836   if (controller.version < 0x0200)
   4837     {
   4838       grub_printf (" VBE version %d.%d is not supported.\n",
   4839 		   (int) (controller.version >> 8),
   4840 		   (int) (controller.version & 0xFF));
   4841       return 0;
   4842     }
   4843 
   4844   /* Print some information.  */
   4845   grub_printf (" VBE version %d.%d\n",
   4846 	       (int) (controller.version >> 8),
   4847 	       (int) (controller.version & 0xFF));
   4848 
   4849   /* Iterate probing modes.  */
   4850   for (mode_list
   4851 	 = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode);
   4852        *mode_list != 0xFFFF;
   4853        mode_list++)
   4854     {
   4855       struct vbe_mode mode;
   4856 
   4857       if (get_vbe_mode_info (*mode_list, &mode) != 0x004F)
   4858 	continue;
   4859 
   4860       /* Skip this, if this is not supported or linear frame buffer
   4861 	 mode is not support.  */
   4862       if ((mode.mode_attributes & 0x0081) != 0x0081)
   4863 	continue;
   4864 
   4865       if (mode_number == -1 || mode_number == *mode_list)
   4866 	{
   4867 	  char *model;
   4868 	  switch (mode.memory_model)
   4869 	    {
   4870 	    case 0x00: model = "Text"; break;
   4871 	    case 0x01: model = "CGA graphics"; break;
   4872 	    case 0x02: model = "Hercules graphics"; break;
   4873 	    case 0x03: model = "Planar"; break;
   4874 	    case 0x04: model = "Packed pixel"; break;
   4875 	    case 0x05: model = "Non-chain 4, 256 color"; break;
   4876 	    case 0x06: model = "Direct Color"; break;
   4877 	    case 0x07: model = "YUV"; break;
   4878 	    default: model = "Unknown"; break;
   4879 	    }
   4880 
   4881 	  grub_printf ("  0x%x: %s, %ux%ux%u\n",
   4882 		       (unsigned) *mode_list,
   4883 		       model,
   4884 		       (unsigned) mode.x_resolution,
   4885 		       (unsigned) mode.y_resolution,
   4886 		       (unsigned) mode.bits_per_pixel);
   4887 
   4888 	  if (mode_number != -1)
   4889 	    break;
   4890 	}
   4891     }
   4892 
   4893   if (mode_number != -1 && mode_number != *mode_list)
   4894     grub_printf ("  Mode 0x%x is not found or supported.\n", mode_number);
   4895 
   4896   return 0;
   4897 }
   4898 
   4899 static struct builtin builtin_vbeprobe =
   4900 {
   4901   "vbeprobe",
   4902   vbeprobe_func,
   4903   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
   4904   "vbeprobe [MODE]",
   4905   "Probe VBE information. If the mode number MODE is specified, show only"
   4906   " the information about only the mode."
   4907 };
   4908 
   4909 
   4910 /* The table of builtin commands. Sorted in dictionary order.  */
   4912 struct builtin *builtin_table[] =
   4913 {
   4914   &builtin_blocklist,
   4915   &builtin_boot,
   4916 #ifdef SUPPORT_NETBOOT
   4917   &builtin_bootp,
   4918 #endif /* SUPPORT_NETBOOT */
   4919   &builtin_cat,
   4920   &builtin_chainloader,
   4921   &builtin_cmdline,
   4922   &builtin_cmp,
   4923   &builtin_color,
   4924   &builtin_configfile,
   4925   &builtin_debug,
   4926   &builtin_default,
   4927 #ifdef GRUB_UTIL
   4928   &builtin_device,
   4929 #endif /* GRUB_UTIL */
   4930 #ifdef SUPPORT_NETBOOT
   4931   &builtin_dhcp,
   4932 #endif /* SUPPORT_NETBOOT */
   4933   &builtin_displayapm,
   4934   &builtin_displaymem,
   4935 #ifdef GRUB_UTIL
   4936   &builtin_dump,
   4937 #endif /* GRUB_UTIL */
   4938   &builtin_embed,
   4939   &builtin_fallback,
   4940   &builtin_find,
   4941   &builtin_fstest,
   4942   &builtin_geometry,
   4943   &builtin_halt,
   4944   &builtin_help,
   4945   &builtin_hiddenmenu,
   4946   &builtin_hide,
   4947 #ifdef SUPPORT_NETBOOT
   4948   &builtin_ifconfig,
   4949 #endif /* SUPPORT_NETBOOT */
   4950   &builtin_impsprobe,
   4951   &builtin_initrd,
   4952   &builtin_install,
   4953   &builtin_ioprobe,
   4954   &builtin_kernel,
   4955   &builtin_lock,
   4956   &builtin_makeactive,
   4957   &builtin_map,
   4958 #ifdef USE_MD5_PASSWORDS
   4959   &builtin_md5crypt,
   4960 #endif /* USE_MD5_PASSWORDS */
   4961   &builtin_module,
   4962   &builtin_modulenounzip,
   4963   &builtin_pager,
   4964   &builtin_partnew,
   4965   &builtin_parttype,
   4966   &builtin_password,
   4967   &builtin_pause,
   4968 #ifdef GRUB_UTIL
   4969   &builtin_quit,
   4970 #endif /* GRUB_UTIL */
   4971 #ifdef SUPPORT_NETBOOT
   4972   &builtin_rarp,
   4973 #endif /* SUPPORT_NETBOOT */
   4974   &builtin_read,
   4975   &builtin_reboot,
   4976   &builtin_root,
   4977   &builtin_rootnoverify,
   4978   &builtin_savedefault,
   4979 #ifdef SUPPORT_SERIAL
   4980   &builtin_serial,
   4981 #endif /* SUPPORT_SERIAL */
   4982   &builtin_setkey,
   4983   &builtin_setup,
   4984 #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
   4985   &builtin_terminal,
   4986 #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */
   4987 #ifdef SUPPORT_SERIAL
   4988   &builtin_terminfo,
   4989 #endif /* SUPPORT_SERIAL */
   4990   &builtin_testload,
   4991   &builtin_testvbe,
   4992 #ifdef SUPPORT_NETBOOT
   4993   &builtin_tftpserver,
   4994 #endif /* SUPPORT_NETBOOT */
   4995   &builtin_timeout,
   4996   &builtin_title,
   4997   &builtin_unhide,
   4998   &builtin_uppermem,
   4999   &builtin_vbeprobe,
   5000   0
   5001 };
   5002