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