17c478bd9Sstevel@tonic-gate /* builtins.c - the GRUB builtin commands */
27c478bd9Sstevel@tonic-gate /*
37c478bd9Sstevel@tonic-gate  *  GRUB  --  GRand Unified Bootloader
47c478bd9Sstevel@tonic-gate  *  Copyright (C) 1999,2000,2001,2002,2003,2004  Free Software Foundation, Inc.
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or modify
77c478bd9Sstevel@tonic-gate  *  it under the terms of the GNU General Public License as published by
87c478bd9Sstevel@tonic-gate  *  the Free Software Foundation; either version 2 of the License, or
97c478bd9Sstevel@tonic-gate  *  (at your option) any later version.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  *  This program is distributed in the hope that it will be useful,
127c478bd9Sstevel@tonic-gate  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
137c478bd9Sstevel@tonic-gate  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
147c478bd9Sstevel@tonic-gate  *  GNU General Public License for more details.
157c478bd9Sstevel@tonic-gate  *
167c478bd9Sstevel@tonic-gate  *  You should have received a copy of the GNU General Public License
177c478bd9Sstevel@tonic-gate  *  along with this program; if not, write to the Free Software
187c478bd9Sstevel@tonic-gate  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
197c478bd9Sstevel@tonic-gate  */
20342440ecSPrasad Singamsetty 
21eb2bd662Svikram /*
22eb2bd662Svikram  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23eb2bd662Svikram  * Use is subject to license terms.
24eb2bd662Svikram  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /* Include stdio.h before shared.h, because we can't define
277c478bd9Sstevel@tonic-gate    WITHOUT_LIBC_STUBS here.  */
287c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
297c478bd9Sstevel@tonic-gate # include <stdio.h>
307c478bd9Sstevel@tonic-gate #endif
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <shared.h>
337c478bd9Sstevel@tonic-gate #include <filesys.h>
347c478bd9Sstevel@tonic-gate #include <term.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
377c478bd9Sstevel@tonic-gate # include <grub.h>
387c478bd9Sstevel@tonic-gate #endif
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
417c478bd9Sstevel@tonic-gate # include <serial.h>
427c478bd9Sstevel@tonic-gate # include <terminfo.h>
437c478bd9Sstevel@tonic-gate #endif
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
467c478bd9Sstevel@tonic-gate # include <device.h>
477c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
487c478bd9Sstevel@tonic-gate # include <apic.h>
497c478bd9Sstevel@tonic-gate # include <smp-imps.h>
507c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
537c478bd9Sstevel@tonic-gate # include <md5.h>
547c478bd9Sstevel@tonic-gate #endif
557c478bd9Sstevel@tonic-gate 
56ae115bc7Smrj #include <cpu.h>
57ae115bc7Smrj 
587c478bd9Sstevel@tonic-gate /* The type of kernel loaded.  */
597c478bd9Sstevel@tonic-gate kernel_t kernel_type;
607c478bd9Sstevel@tonic-gate /* The boot device.  */
617c478bd9Sstevel@tonic-gate static int bootdev;
627c478bd9Sstevel@tonic-gate /* True when the debug mode is turned on, and false
637c478bd9Sstevel@tonic-gate    when it is turned off.  */
647c478bd9Sstevel@tonic-gate int debug = 0;
657c478bd9Sstevel@tonic-gate /* The default entry.  */
667c478bd9Sstevel@tonic-gate int default_entry = 0;
677c478bd9Sstevel@tonic-gate /* The fallback entry.  */
687c478bd9Sstevel@tonic-gate int fallback_entryno;
697c478bd9Sstevel@tonic-gate int fallback_entries[MAX_FALLBACK_ENTRIES];
707c478bd9Sstevel@tonic-gate /* The number of current entry.  */
717c478bd9Sstevel@tonic-gate int current_entryno;
727c478bd9Sstevel@tonic-gate /* The address for Multiboot command-line buffer.  */
737c478bd9Sstevel@tonic-gate static char *mb_cmdline;
747c478bd9Sstevel@tonic-gate /* The password.  */
757c478bd9Sstevel@tonic-gate char *password;
767c478bd9Sstevel@tonic-gate /* The password type.  */
777c478bd9Sstevel@tonic-gate password_t password_type;
787c478bd9Sstevel@tonic-gate /* The flag for indicating that the user is authoritative.  */
797c478bd9Sstevel@tonic-gate int auth = 0;
807c478bd9Sstevel@tonic-gate /* The timeout.  */
817c478bd9Sstevel@tonic-gate int grub_timeout = -1;
827c478bd9Sstevel@tonic-gate /* Whether to show the menu or not.  */
837c478bd9Sstevel@tonic-gate int show_menu = 1;
847c478bd9Sstevel@tonic-gate /* The BIOS drive map.  */
857c478bd9Sstevel@tonic-gate static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* Prototypes for allowing straightfoward calling of builtins functions
887c478bd9Sstevel@tonic-gate    inside other functions.  */
897c478bd9Sstevel@tonic-gate static int configfile_func (char *arg, int flags);
907c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
917c478bd9Sstevel@tonic-gate static void solaris_config_file (void);
927c478bd9Sstevel@tonic-gate #endif
937c478bd9Sstevel@tonic-gate 
94342440ecSPrasad Singamsetty static unsigned int min_mem64 = 0;
95342440ecSPrasad Singamsetty 
967c478bd9Sstevel@tonic-gate #if defined(__sun) && !defined(GRUB_UTIL)
977c478bd9Sstevel@tonic-gate extern void __enable_execute_stack (void *);
987c478bd9Sstevel@tonic-gate void
997c478bd9Sstevel@tonic-gate __enable_execute_stack (void *addr)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate #endif /* __sun && !GRUB_UTIL */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* Initialize the data for builtins.  */
1057c478bd9Sstevel@tonic-gate void
1067c478bd9Sstevel@tonic-gate init_builtins (void)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_NONE;
1097c478bd9Sstevel@tonic-gate   /* BSD and chainloading evil hacks!  */
1107c478bd9Sstevel@tonic-gate   bootdev = set_bootdev (0);
1117c478bd9Sstevel@tonic-gate   mb_cmdline = (char *) MB_CMDLINE_BUF;
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* Initialize the data for the configuration file.  */
1157c478bd9Sstevel@tonic-gate void
1167c478bd9Sstevel@tonic-gate init_config (void)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate   default_entry = 0;
1197c478bd9Sstevel@tonic-gate   password = 0;
1207c478bd9Sstevel@tonic-gate   fallback_entryno = -1;
1217c478bd9Sstevel@tonic-gate   fallback_entries[0] = -1;
1227c478bd9Sstevel@tonic-gate   grub_timeout = -1;
123b1b8ab34Slling   current_rootpool[0] = '\0';
124b1b8ab34Slling   current_bootfs[0] = '\0';
125e7cbe64fSgw   current_bootpath[0] = '\0';
126b1b8ab34Slling   current_bootfs_obj = 0;
127051aabe6Staylor   current_devid[0] = '\0';
128b1b8ab34Slling   is_zfs_mount = 0;
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /* Check a password for correctness.  Returns 0 if password was
1327c478bd9Sstevel@tonic-gate    correct, and a value != 0 for error, similarly to strcmp. */
1337c478bd9Sstevel@tonic-gate int
1347c478bd9Sstevel@tonic-gate check_password (char *entered, char* expected, password_t type)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate   switch (type)
1377c478bd9Sstevel@tonic-gate     {
1387c478bd9Sstevel@tonic-gate     case PASSWORD_PLAIN:
1397c478bd9Sstevel@tonic-gate       return strcmp (entered, expected);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
1427c478bd9Sstevel@tonic-gate     case PASSWORD_MD5:
1437c478bd9Sstevel@tonic-gate       return check_md5_password (entered, expected);
1447c478bd9Sstevel@tonic-gate #endif
1457c478bd9Sstevel@tonic-gate     default:
1467c478bd9Sstevel@tonic-gate       /* unsupported password type: be secure */
1477c478bd9Sstevel@tonic-gate       return 1;
1487c478bd9Sstevel@tonic-gate     }
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /* Print which sector is read when loading a file.  */
1527c478bd9Sstevel@tonic-gate static void
153342440ecSPrasad Singamsetty disk_read_print_func(unsigned int sector, int offset, int length)
1547c478bd9Sstevel@tonic-gate {
155342440ecSPrasad Singamsetty   grub_printf ("[%u,%d,%d]", sector, offset, length);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /* blocklist */
1607c478bd9Sstevel@tonic-gate static int
1617c478bd9Sstevel@tonic-gate blocklist_func (char *arg, int flags)
1627c478bd9Sstevel@tonic-gate {
1637c478bd9Sstevel@tonic-gate   char *dummy = (char *) RAW_ADDR (0x100000);
1641b8adde7SWilliam Kucharski   unsigned int start_sector = 0;
1657c478bd9Sstevel@tonic-gate   int num_sectors = 0;
1667c478bd9Sstevel@tonic-gate   int num_entries = 0;
1677c478bd9Sstevel@tonic-gate   int last_length = 0;
1687c478bd9Sstevel@tonic-gate 
1691b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
1701b8adde7SWilliam Kucharski       int length);
1711b8adde7SWilliam Kucharski 
1727c478bd9Sstevel@tonic-gate   /* Collect contiguous blocks into one entry as many as possible,
1737c478bd9Sstevel@tonic-gate      and print the blocklist notation on the screen.  */
1741b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
1751b8adde7SWilliam Kucharski       int length)
1767c478bd9Sstevel@tonic-gate     {
1777c478bd9Sstevel@tonic-gate       if (num_sectors > 0)
1787c478bd9Sstevel@tonic-gate 	{
1797c478bd9Sstevel@tonic-gate 	  if (start_sector + num_sectors == sector
1807c478bd9Sstevel@tonic-gate 	      && offset == 0 && last_length == SECTOR_SIZE)
1817c478bd9Sstevel@tonic-gate 	    {
1827c478bd9Sstevel@tonic-gate 	      num_sectors++;
1837c478bd9Sstevel@tonic-gate 	      last_length = length;
1847c478bd9Sstevel@tonic-gate 	      return;
1857c478bd9Sstevel@tonic-gate 	    }
1867c478bd9Sstevel@tonic-gate 	  else
1877c478bd9Sstevel@tonic-gate 	    {
1887c478bd9Sstevel@tonic-gate 	      if (last_length == SECTOR_SIZE)
1897c478bd9Sstevel@tonic-gate 		grub_printf ("%s%d+%d", num_entries ? "," : "",
1907c478bd9Sstevel@tonic-gate 			     start_sector - part_start, num_sectors);
1917c478bd9Sstevel@tonic-gate 	      else if (num_sectors > 1)
1927c478bd9Sstevel@tonic-gate 		grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
1937c478bd9Sstevel@tonic-gate 			     start_sector - part_start, num_sectors-1,
1947c478bd9Sstevel@tonic-gate 			     start_sector + num_sectors-1 - part_start,
1957c478bd9Sstevel@tonic-gate 			     last_length);
1967c478bd9Sstevel@tonic-gate 	      else
1977c478bd9Sstevel@tonic-gate 		grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
1987c478bd9Sstevel@tonic-gate 			     start_sector - part_start, last_length);
1997c478bd9Sstevel@tonic-gate 	      num_entries++;
2007c478bd9Sstevel@tonic-gate 	      num_sectors = 0;
2017c478bd9Sstevel@tonic-gate 	    }
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate       if (offset > 0)
2057c478bd9Sstevel@tonic-gate 	{
2061b8adde7SWilliam Kucharski 	  grub_printf("%s%u[%d-%d]", num_entries ? "," : "",
2077c478bd9Sstevel@tonic-gate 		      sector-part_start, offset, offset+length);
2087c478bd9Sstevel@tonic-gate 	  num_entries++;
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate       else
2117c478bd9Sstevel@tonic-gate 	{
2127c478bd9Sstevel@tonic-gate 	  start_sector = sector;
2137c478bd9Sstevel@tonic-gate 	  num_sectors = 1;
2147c478bd9Sstevel@tonic-gate 	  last_length = length;
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate     }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate   /* Open the file.  */
2197c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
2207c478bd9Sstevel@tonic-gate     return 1;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate   /* Print the device name.  */
2237c478bd9Sstevel@tonic-gate   grub_printf ("(%cd%d",
2247c478bd9Sstevel@tonic-gate 	       (current_drive & 0x80) ? 'h' : 'f',
2257c478bd9Sstevel@tonic-gate 	       current_drive & ~0x80);
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate   if ((current_partition & 0xFF0000) != 0xFF0000)
2287c478bd9Sstevel@tonic-gate     grub_printf (",%d", (current_partition >> 16) & 0xFF);
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate   if ((current_partition & 0x00FF00) != 0x00FF00)
2317c478bd9Sstevel@tonic-gate     grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate   grub_printf (")");
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate   /* Read in the whole file to DUMMY.  */
2367c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_blocklist_func;
2377c478bd9Sstevel@tonic-gate   if (! grub_read (dummy, -1))
2387c478bd9Sstevel@tonic-gate     goto fail;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate   /* The last entry may not be printed yet.  Don't check if it is a
2417c478bd9Sstevel@tonic-gate    * full sector, since it doesn't matter if we read too much. */
2427c478bd9Sstevel@tonic-gate   if (num_sectors > 0)
2437c478bd9Sstevel@tonic-gate     grub_printf ("%s%d+%d", num_entries ? "," : "",
2447c478bd9Sstevel@tonic-gate 		 start_sector - part_start, num_sectors);
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate   grub_printf ("\n");
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate  fail:
2497c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
2507c478bd9Sstevel@tonic-gate   grub_close ();
2517c478bd9Sstevel@tonic-gate   return errnum;
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate static struct builtin builtin_blocklist =
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate   "blocklist",
2577c478bd9Sstevel@tonic-gate   blocklist_func,
2587c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
2597c478bd9Sstevel@tonic-gate   "blocklist FILE",
2607c478bd9Sstevel@tonic-gate   "Print the blocklist notation of the file FILE."
2617c478bd9Sstevel@tonic-gate };
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate /* boot */
2647c478bd9Sstevel@tonic-gate static int
2657c478bd9Sstevel@tonic-gate boot_func (char *arg, int flags)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate   /* Clear the int15 handler if we can boot the kernel successfully.
2687c478bd9Sstevel@tonic-gate      This assumes that the boot code never fails only if KERNEL_TYPE is
2697c478bd9Sstevel@tonic-gate      not KERNEL_TYPE_NONE. Is this assumption is bad?  */
2707c478bd9Sstevel@tonic-gate   if (kernel_type != KERNEL_TYPE_NONE)
2717c478bd9Sstevel@tonic-gate     unset_int15_handler ();
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
2747c478bd9Sstevel@tonic-gate   /* Shut down the networking.  */
2757c478bd9Sstevel@tonic-gate   cleanup_net ();
2767c478bd9Sstevel@tonic-gate #endif
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate   switch (kernel_type)
2797c478bd9Sstevel@tonic-gate     {
2807c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_FREEBSD:
2817c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_NETBSD:
2827c478bd9Sstevel@tonic-gate       /* *BSD */
2837c478bd9Sstevel@tonic-gate       bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline);
2847c478bd9Sstevel@tonic-gate       break;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
2877c478bd9Sstevel@tonic-gate       /* Linux */
2887c478bd9Sstevel@tonic-gate       linux_boot ();
2897c478bd9Sstevel@tonic-gate       break;
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
2927c478bd9Sstevel@tonic-gate       /* Big Linux */
2937c478bd9Sstevel@tonic-gate       big_linux_boot ();
2947c478bd9Sstevel@tonic-gate       break;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_CHAINLOADER:
2977c478bd9Sstevel@tonic-gate       /* Chainloader */
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate       /* Check if we should set the int13 handler.  */
3007c478bd9Sstevel@tonic-gate       if (bios_drive_map[0] != 0)
3017c478bd9Sstevel@tonic-gate 	{
3027c478bd9Sstevel@tonic-gate 	  int i;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	  /* Search for SAVED_DRIVE.  */
3057c478bd9Sstevel@tonic-gate 	  for (i = 0; i < DRIVE_MAP_SIZE; i++)
3067c478bd9Sstevel@tonic-gate 	    {
3077c478bd9Sstevel@tonic-gate 	      if (! bios_drive_map[i])
3087c478bd9Sstevel@tonic-gate 		break;
3097c478bd9Sstevel@tonic-gate 	      else if ((bios_drive_map[i] & 0xFF) == saved_drive)
3107c478bd9Sstevel@tonic-gate 		{
3117c478bd9Sstevel@tonic-gate 		  /* Exchage SAVED_DRIVE with the mapped drive.  */
3127c478bd9Sstevel@tonic-gate 		  saved_drive = (bios_drive_map[i] >> 8) & 0xFF;
3137c478bd9Sstevel@tonic-gate 		  break;
3147c478bd9Sstevel@tonic-gate 		}
3157c478bd9Sstevel@tonic-gate 	    }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	  /* Set the handler. This is somewhat dangerous.  */
3187c478bd9Sstevel@tonic-gate 	  set_int13_handler (bios_drive_map);
3197c478bd9Sstevel@tonic-gate 	}
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate       gateA20 (0);
3227c478bd9Sstevel@tonic-gate       boot_drive = saved_drive;
3237c478bd9Sstevel@tonic-gate       chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr);
3247c478bd9Sstevel@tonic-gate       break;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_MULTIBOOT:
3277c478bd9Sstevel@tonic-gate       /* Multiboot */
3287c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
3297c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
3307c478bd9Sstevel@tonic-gate       if (current_drive == NETWORK_DRIVE) {
3317c478bd9Sstevel@tonic-gate     	/*
3327c478bd9Sstevel@tonic-gate 	 *  XXX Solaris hack: use drive_info to pass network information
3337c478bd9Sstevel@tonic-gate 	 *  Turn off the flag bit to the loader is technically
3347c478bd9Sstevel@tonic-gate 	 *  multiboot compliant.
3357c478bd9Sstevel@tonic-gate 	 */
3367c478bd9Sstevel@tonic-gate     	mbi.flags &= ~MB_INFO_DRIVE_INFO;
3377c478bd9Sstevel@tonic-gate   	mbi.drives_length = dhcpack_length;
3387c478bd9Sstevel@tonic-gate   	mbi.drives_addr = dhcpack_buf;
3397c478bd9Sstevel@tonic-gate       }
3407c478bd9Sstevel@tonic-gate #endif /* SOLARIS_NETBOOT */
3417c478bd9Sstevel@tonic-gate #endif
3427c478bd9Sstevel@tonic-gate       multi_boot ((int) entry_addr, (int) &mbi);
3437c478bd9Sstevel@tonic-gate       break;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate     default:
3467c478bd9Sstevel@tonic-gate       errnum = ERR_BOOT_COMMAND;
3477c478bd9Sstevel@tonic-gate       return 1;
3487c478bd9Sstevel@tonic-gate     }
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate   return 0;
3517c478bd9Sstevel@tonic-gate }
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate static struct builtin builtin_boot =
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate   "boot",
3567c478bd9Sstevel@tonic-gate   boot_func,
3577c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3587c478bd9Sstevel@tonic-gate   "boot",
3597c478bd9Sstevel@tonic-gate   "Boot the OS/chain-loader which has been loaded."
3607c478bd9Sstevel@tonic-gate };
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
3647c478bd9Sstevel@tonic-gate /* bootp */
3657c478bd9Sstevel@tonic-gate static int
3667c478bd9Sstevel@tonic-gate bootp_func (char *arg, int flags)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate   int with_configfile = 0;
3697c478bd9Sstevel@tonic-gate 
3707c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
3717c478bd9Sstevel@tonic-gate       == 0)
3727c478bd9Sstevel@tonic-gate     {
3737c478bd9Sstevel@tonic-gate       with_configfile = 1;
3747c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
3757c478bd9Sstevel@tonic-gate     }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate   if (! bootp ())
3787c478bd9Sstevel@tonic-gate     {
3797c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
3807c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate       return 1;
3837c478bd9Sstevel@tonic-gate     }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
3867c478bd9Sstevel@tonic-gate   print_network_configuration ();
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate   /* XXX: this can cause an endless loop, but there is no easy way to
3897c478bd9Sstevel@tonic-gate      detect such a loop unfortunately.  */
3907c478bd9Sstevel@tonic-gate   if (with_configfile)
3917c478bd9Sstevel@tonic-gate     configfile_func (config_file, flags);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate   return 0;
3947c478bd9Sstevel@tonic-gate }
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate static struct builtin builtin_bootp =
3977c478bd9Sstevel@tonic-gate {
3987c478bd9Sstevel@tonic-gate   "bootp",
3997c478bd9Sstevel@tonic-gate   bootp_func,
4007c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
4017c478bd9Sstevel@tonic-gate   "bootp [--with-configfile]",
4027c478bd9Sstevel@tonic-gate   "Initialize a network device via BOOTP. If the option `--with-configfile'"
4037c478bd9Sstevel@tonic-gate   " is given, try to load a configuration file specified by the 150 vendor"
4047c478bd9Sstevel@tonic-gate   " tag."
4057c478bd9Sstevel@tonic-gate };
4067c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /* cat */
4107c478bd9Sstevel@tonic-gate static int
4117c478bd9Sstevel@tonic-gate cat_func (char *arg, int flags)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate   char c;
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
4167c478bd9Sstevel@tonic-gate     return 1;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate   while (grub_read (&c, 1))
4197c478bd9Sstevel@tonic-gate     {
4207c478bd9Sstevel@tonic-gate       /* Because running "cat" with a binary file can confuse the terminal,
4217c478bd9Sstevel@tonic-gate 	 print only some characters as they are.  */
4227c478bd9Sstevel@tonic-gate       if (grub_isspace (c) || (c >= ' ' && c <= '~'))
4237c478bd9Sstevel@tonic-gate 	grub_putchar (c);
4247c478bd9Sstevel@tonic-gate       else
4257c478bd9Sstevel@tonic-gate 	grub_putchar ('?');
4267c478bd9Sstevel@tonic-gate     }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate   grub_close ();
4297c478bd9Sstevel@tonic-gate   return 0;
4307c478bd9Sstevel@tonic-gate }
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate static struct builtin builtin_cat =
4337c478bd9Sstevel@tonic-gate {
4347c478bd9Sstevel@tonic-gate   "cat",
4357c478bd9Sstevel@tonic-gate   cat_func,
4367c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4377c478bd9Sstevel@tonic-gate   "cat FILE",
4387c478bd9Sstevel@tonic-gate   "Print the contents of the file FILE."
4397c478bd9Sstevel@tonic-gate };
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate /* chainloader */
4437c478bd9Sstevel@tonic-gate static int
4447c478bd9Sstevel@tonic-gate chainloader_func (char *arg, int flags)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate   int force = 0;
4477c478bd9Sstevel@tonic-gate   char *file = arg;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate   /* If the option `--force' is specified?  */
4507c478bd9Sstevel@tonic-gate   if (substring ("--force", arg) <= 0)
4517c478bd9Sstevel@tonic-gate     {
4527c478bd9Sstevel@tonic-gate       force = 1;
4537c478bd9Sstevel@tonic-gate       file = skip_to (0, arg);
4547c478bd9Sstevel@tonic-gate     }
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate   /* Open the file.  */
4577c478bd9Sstevel@tonic-gate   if (! grub_open (file))
4587c478bd9Sstevel@tonic-gate     {
4597c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4607c478bd9Sstevel@tonic-gate       return 1;
4617c478bd9Sstevel@tonic-gate     }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate   /* Read the first block.  */
4647c478bd9Sstevel@tonic-gate   if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE)
4657c478bd9Sstevel@tonic-gate     {
4667c478bd9Sstevel@tonic-gate       grub_close ();
4677c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate       /* This below happens, if a file whose size is less than 512 bytes
4707c478bd9Sstevel@tonic-gate 	 is loaded.  */
4717c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
4727c478bd9Sstevel@tonic-gate 	errnum = ERR_EXEC_FORMAT;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate       return 1;
4757c478bd9Sstevel@tonic-gate     }
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate   /* If not loading it forcibly, check for the signature.  */
4787c478bd9Sstevel@tonic-gate   if (! force
4797c478bd9Sstevel@tonic-gate       && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET))
4807c478bd9Sstevel@tonic-gate 	  != BOOTSEC_SIGNATURE))
4817c478bd9Sstevel@tonic-gate     {
4827c478bd9Sstevel@tonic-gate       grub_close ();
4837c478bd9Sstevel@tonic-gate       errnum = ERR_EXEC_FORMAT;
4847c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4857c478bd9Sstevel@tonic-gate       return 1;
4867c478bd9Sstevel@tonic-gate     }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate   grub_close ();
4897c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_CHAINLOADER;
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate   /* XXX: Windows evil hack. For now, only the first five letters are
4927c478bd9Sstevel@tonic-gate      checked.  */
4937c478bd9Sstevel@tonic-gate   if (IS_PC_SLICE_TYPE_FAT (current_slice)
4947c478bd9Sstevel@tonic-gate       && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID,
4957c478bd9Sstevel@tonic-gate 			"MSWIN", 5))
4967c478bd9Sstevel@tonic-gate     *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS))
4977c478bd9Sstevel@tonic-gate       = part_start;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate   errnum = ERR_NONE;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate   return 0;
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate static struct builtin builtin_chainloader =
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate   "chainloader",
5077c478bd9Sstevel@tonic-gate   chainloader_func,
5087c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
5097c478bd9Sstevel@tonic-gate   "chainloader [--force] FILE",
5107c478bd9Sstevel@tonic-gate   "Load the chain-loader FILE. If --force is specified, then load it"
5117c478bd9Sstevel@tonic-gate   " forcibly, whether the boot loader signature is present or not."
5127c478bd9Sstevel@tonic-gate };
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate /* This function could be used to debug new filesystem code. Put a file
5167c478bd9Sstevel@tonic-gate    in the new filesystem and the same file in a well-tested filesystem.
5177c478bd9Sstevel@tonic-gate    Then, run "cmp" with the files. If no output is obtained, probably
5187c478bd9Sstevel@tonic-gate    the code is good, otherwise investigate what's wrong...  */
5197c478bd9Sstevel@tonic-gate /* cmp FILE1 FILE2 */
5207c478bd9Sstevel@tonic-gate static int
5217c478bd9Sstevel@tonic-gate cmp_func (char *arg, int flags)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate   /* The filenames.  */
5247c478bd9Sstevel@tonic-gate   char *file1, *file2;
5257c478bd9Sstevel@tonic-gate   /* The addresses.  */
5267c478bd9Sstevel@tonic-gate   char *addr1, *addr2;
5277c478bd9Sstevel@tonic-gate   int i;
5287c478bd9Sstevel@tonic-gate   /* The size of the file.  */
5297c478bd9Sstevel@tonic-gate   int size;
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate   /* Get the filenames from ARG.  */
5327c478bd9Sstevel@tonic-gate   file1 = arg;
5337c478bd9Sstevel@tonic-gate   file2 = skip_to (0, arg);
5347c478bd9Sstevel@tonic-gate   if (! *file1 || ! *file2)
5357c478bd9Sstevel@tonic-gate     {
5367c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
5377c478bd9Sstevel@tonic-gate       return 1;
5387c478bd9Sstevel@tonic-gate     }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate   /* Terminate the filenames for convenience.  */
5417c478bd9Sstevel@tonic-gate   nul_terminate (file1);
5427c478bd9Sstevel@tonic-gate   nul_terminate (file2);
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate   /* Read the whole data from FILE1.  */
5457c478bd9Sstevel@tonic-gate   addr1 = (char *) RAW_ADDR (0x100000);
5467c478bd9Sstevel@tonic-gate   if (! grub_open (file1))
5477c478bd9Sstevel@tonic-gate     return 1;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate   /* Get the size.  */
5507c478bd9Sstevel@tonic-gate   size = filemax;
5517c478bd9Sstevel@tonic-gate   if (grub_read (addr1, -1) != size)
5527c478bd9Sstevel@tonic-gate     {
5537c478bd9Sstevel@tonic-gate       grub_close ();
5547c478bd9Sstevel@tonic-gate       return 1;
5557c478bd9Sstevel@tonic-gate     }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate   grub_close ();
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate   /* Read the whole data from FILE2.  */
5607c478bd9Sstevel@tonic-gate   addr2 = addr1 + size;
5617c478bd9Sstevel@tonic-gate   if (! grub_open (file2))
5627c478bd9Sstevel@tonic-gate     return 1;
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate   /* Check if the size of FILE2 is equal to the one of FILE2.  */
5657c478bd9Sstevel@tonic-gate   if (size != filemax)
5667c478bd9Sstevel@tonic-gate     {
5677c478bd9Sstevel@tonic-gate       grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n",
5687c478bd9Sstevel@tonic-gate 		   size, file1, filemax, file2);
5697c478bd9Sstevel@tonic-gate       grub_close ();
5707c478bd9Sstevel@tonic-gate       return 0;
5717c478bd9Sstevel@tonic-gate     }
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate   if (! grub_read (addr2, -1))
5747c478bd9Sstevel@tonic-gate     {
5757c478bd9Sstevel@tonic-gate       grub_close ();
5767c478bd9Sstevel@tonic-gate       return 1;
5777c478bd9Sstevel@tonic-gate     }
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate   grub_close ();
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate   /* Now compare ADDR1 with ADDR2.  */
5827c478bd9Sstevel@tonic-gate   for (i = 0; i < size; i++)
5837c478bd9Sstevel@tonic-gate     {
5847c478bd9Sstevel@tonic-gate       if (addr1[i] != addr2[i])
5857c478bd9Sstevel@tonic-gate 	grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n",
5867c478bd9Sstevel@tonic-gate 		     i, (unsigned) addr1[i], file1,
5877c478bd9Sstevel@tonic-gate 		     (unsigned) addr2[i], file2);
5887c478bd9Sstevel@tonic-gate     }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate   return 0;
5917c478bd9Sstevel@tonic-gate }
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate static struct builtin builtin_cmp =
5947c478bd9Sstevel@tonic-gate {
5957c478bd9Sstevel@tonic-gate   "cmp",
5967c478bd9Sstevel@tonic-gate   cmp_func,
5977c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
5987c478bd9Sstevel@tonic-gate   "cmp FILE1 FILE2",
5997c478bd9Sstevel@tonic-gate   "Compare the file FILE1 with the FILE2 and inform the different values"
6007c478bd9Sstevel@tonic-gate   " if any."
6017c478bd9Sstevel@tonic-gate };
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate /* color */
6057c478bd9Sstevel@tonic-gate /* Set new colors used for the menu interface. Support two methods to
6067c478bd9Sstevel@tonic-gate    specify a color name: a direct integer representation and a symbolic
6077c478bd9Sstevel@tonic-gate    color name. An example of the latter is "blink-light-gray/blue".  */
6087c478bd9Sstevel@tonic-gate static int
6097c478bd9Sstevel@tonic-gate color_func (char *arg, int flags)
6107c478bd9Sstevel@tonic-gate {
6117c478bd9Sstevel@tonic-gate   char *normal;
6127c478bd9Sstevel@tonic-gate   char *highlight;
6137c478bd9Sstevel@tonic-gate   int new_normal_color;
6147c478bd9Sstevel@tonic-gate   int new_highlight_color;
6157c478bd9Sstevel@tonic-gate   static char *color_list[16] =
6167c478bd9Sstevel@tonic-gate   {
6177c478bd9Sstevel@tonic-gate     "black",
6187c478bd9Sstevel@tonic-gate     "blue",
6197c478bd9Sstevel@tonic-gate     "green",
6207c478bd9Sstevel@tonic-gate     "cyan",
6217c478bd9Sstevel@tonic-gate     "red",
6227c478bd9Sstevel@tonic-gate     "magenta",
6237c478bd9Sstevel@tonic-gate     "brown",
6247c478bd9Sstevel@tonic-gate     "light-gray",
6257c478bd9Sstevel@tonic-gate     "dark-gray",
6267c478bd9Sstevel@tonic-gate     "light-blue",
6277c478bd9Sstevel@tonic-gate     "light-green",
6287c478bd9Sstevel@tonic-gate     "light-cyan",
6297c478bd9Sstevel@tonic-gate     "light-red",
6307c478bd9Sstevel@tonic-gate     "light-magenta",
6317c478bd9Sstevel@tonic-gate     "yellow",
6327c478bd9Sstevel@tonic-gate     "white"
6337c478bd9Sstevel@tonic-gate   };
6347c478bd9Sstevel@tonic-gate 
6351b8adde7SWilliam Kucharski   auto int color_number (char *str);
6361b8adde7SWilliam Kucharski 
6377c478bd9Sstevel@tonic-gate   /* Convert the color name STR into the magical number.  */
6381b8adde7SWilliam Kucharski   auto int color_number (char *str)
6397c478bd9Sstevel@tonic-gate     {
6407c478bd9Sstevel@tonic-gate       char *ptr;
6417c478bd9Sstevel@tonic-gate       int i;
6427c478bd9Sstevel@tonic-gate       int color = 0;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate       /* Find the separator.  */
6457c478bd9Sstevel@tonic-gate       for (ptr = str; *ptr && *ptr != '/'; ptr++)
6467c478bd9Sstevel@tonic-gate 	;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate       /* If not found, return -1.  */
6497c478bd9Sstevel@tonic-gate       if (! *ptr)
6507c478bd9Sstevel@tonic-gate 	return -1;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate       /* Terminate the string STR.  */
6537c478bd9Sstevel@tonic-gate       *ptr++ = 0;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate       /* If STR contains the prefix "blink-", then set the `blink' bit
6567c478bd9Sstevel@tonic-gate 	 in COLOR.  */
6577c478bd9Sstevel@tonic-gate       if (substring ("blink-", str) <= 0)
6587c478bd9Sstevel@tonic-gate 	{
6597c478bd9Sstevel@tonic-gate 	  color = 0x80;
6607c478bd9Sstevel@tonic-gate 	  str += 6;
6617c478bd9Sstevel@tonic-gate 	}
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate       /* Search for the color name.  */
6647c478bd9Sstevel@tonic-gate       for (i = 0; i < 16; i++)
6657c478bd9Sstevel@tonic-gate 	if (grub_strcmp (color_list[i], str) == 0)
6667c478bd9Sstevel@tonic-gate 	  {
6677c478bd9Sstevel@tonic-gate 	    color |= i;
6687c478bd9Sstevel@tonic-gate 	    break;
6697c478bd9Sstevel@tonic-gate 	  }
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate       if (i == 16)
6727c478bd9Sstevel@tonic-gate 	return -1;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate       str = ptr;
6757c478bd9Sstevel@tonic-gate       nul_terminate (str);
6767c478bd9Sstevel@tonic-gate 
6777c478bd9Sstevel@tonic-gate       /* Search for the color name.  */
6787c478bd9Sstevel@tonic-gate       for (i = 0; i < 8; i++)
6797c478bd9Sstevel@tonic-gate 	if (grub_strcmp (color_list[i], str) == 0)
6807c478bd9Sstevel@tonic-gate 	  {
6817c478bd9Sstevel@tonic-gate 	    color |= i << 4;
6827c478bd9Sstevel@tonic-gate 	    break;
6837c478bd9Sstevel@tonic-gate 	  }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate       if (i == 8)
6867c478bd9Sstevel@tonic-gate 	return -1;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate       return color;
6897c478bd9Sstevel@tonic-gate     }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate   normal = arg;
6927c478bd9Sstevel@tonic-gate   highlight = skip_to (0, arg);
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate   new_normal_color = color_number (normal);
6957c478bd9Sstevel@tonic-gate   if (new_normal_color < 0 && ! safe_parse_maxint (&normal, &new_normal_color))
6967c478bd9Sstevel@tonic-gate     return 1;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate   /* The second argument is optional, so set highlight_color
6997c478bd9Sstevel@tonic-gate      to inverted NORMAL_COLOR.  */
7007c478bd9Sstevel@tonic-gate   if (! *highlight)
7017c478bd9Sstevel@tonic-gate     new_highlight_color = ((new_normal_color >> 4)
7027c478bd9Sstevel@tonic-gate 			   | ((new_normal_color & 0xf) << 4));
7037c478bd9Sstevel@tonic-gate   else
7047c478bd9Sstevel@tonic-gate     {
7057c478bd9Sstevel@tonic-gate       new_highlight_color = color_number (highlight);
7067c478bd9Sstevel@tonic-gate       if (new_highlight_color < 0
7077c478bd9Sstevel@tonic-gate 	  && ! safe_parse_maxint (&highlight, &new_highlight_color))
7087c478bd9Sstevel@tonic-gate 	return 1;
7097c478bd9Sstevel@tonic-gate     }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate   if (current_term->setcolor)
7127c478bd9Sstevel@tonic-gate     current_term->setcolor (new_normal_color, new_highlight_color);
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate   return 0;
7157c478bd9Sstevel@tonic-gate }
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate static struct builtin builtin_color =
7187c478bd9Sstevel@tonic-gate {
7197c478bd9Sstevel@tonic-gate   "color",
7207c478bd9Sstevel@tonic-gate   color_func,
7217c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
7227c478bd9Sstevel@tonic-gate   "color NORMAL [HIGHLIGHT]",
7237c478bd9Sstevel@tonic-gate   "Change the menu colors. The color NORMAL is used for most"
7247c478bd9Sstevel@tonic-gate   " lines in the menu, and the color HIGHLIGHT is used to highlight the"
7257c478bd9Sstevel@tonic-gate   " line where the cursor points. If you omit HIGHLIGHT, then the"
7267c478bd9Sstevel@tonic-gate   " inverted color of NORMAL is used for the highlighted line."
7277c478bd9Sstevel@tonic-gate   " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
7287c478bd9Sstevel@tonic-gate   " A symbolic color name must be one of these: black, blue, green,"
7297c478bd9Sstevel@tonic-gate   " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
7307c478bd9Sstevel@tonic-gate   " light-green, light-cyan, light-red, light-magenta, yellow and white."
7317c478bd9Sstevel@tonic-gate   " But only the first eight names can be used for BG. You can prefix"
7327c478bd9Sstevel@tonic-gate   " \"blink-\" to FG if you want a blinking foreground color."
7337c478bd9Sstevel@tonic-gate };
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate /* configfile */
7377c478bd9Sstevel@tonic-gate static int
7387c478bd9Sstevel@tonic-gate configfile_func (char *arg, int flags)
7397c478bd9Sstevel@tonic-gate {
7407c478bd9Sstevel@tonic-gate   char *new_config = config_file;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate   /* Check if the file ARG is present.  */
7437c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
7447c478bd9Sstevel@tonic-gate     return 1;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate   grub_close ();
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate   /* Copy ARG to CONFIG_FILE.  */
7497c478bd9Sstevel@tonic-gate   while ((*new_config++ = *arg++) != 0)
7507c478bd9Sstevel@tonic-gate     ;
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
7537c478bd9Sstevel@tonic-gate   /* Force to load the configuration file.  */
7547c478bd9Sstevel@tonic-gate   use_config_file = 1;
7557c478bd9Sstevel@tonic-gate #endif
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate   /* Make sure that the user will not be authoritative.  */
7587c478bd9Sstevel@tonic-gate   auth = 0;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate   /* Restart cmain.  */
7617c478bd9Sstevel@tonic-gate   grub_longjmp (restart_env, 0);
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate   /* Never reach here.  */
7647c478bd9Sstevel@tonic-gate   return 0;
7657c478bd9Sstevel@tonic-gate }
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate static struct builtin builtin_configfile =
7687c478bd9Sstevel@tonic-gate {
7697c478bd9Sstevel@tonic-gate   "configfile",
7707c478bd9Sstevel@tonic-gate   configfile_func,
7717c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
7727c478bd9Sstevel@tonic-gate   "configfile FILE",
7737c478bd9Sstevel@tonic-gate   "Load FILE as the configuration file."
7747c478bd9Sstevel@tonic-gate };
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /* debug */
7787c478bd9Sstevel@tonic-gate static int
7797c478bd9Sstevel@tonic-gate debug_func (char *arg, int flags)
7807c478bd9Sstevel@tonic-gate {
7817c478bd9Sstevel@tonic-gate   if (debug)
7827c478bd9Sstevel@tonic-gate     {
7837c478bd9Sstevel@tonic-gate       debug = 0;
7847c478bd9Sstevel@tonic-gate       grub_printf (" Debug mode is turned off\n");
7857c478bd9Sstevel@tonic-gate     }
7867c478bd9Sstevel@tonic-gate   else
7877c478bd9Sstevel@tonic-gate     {
7887c478bd9Sstevel@tonic-gate       debug = 1;
7897c478bd9Sstevel@tonic-gate       grub_printf (" Debug mode is turned on\n");
7907c478bd9Sstevel@tonic-gate     }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate   return 0;
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate static struct builtin builtin_debug =
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate   "debug",
7987c478bd9Sstevel@tonic-gate   debug_func,
7997c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
8007c478bd9Sstevel@tonic-gate   "debug",
8017c478bd9Sstevel@tonic-gate   "Turn on/off the debug mode."
8027c478bd9Sstevel@tonic-gate };
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate /* default */
8067c478bd9Sstevel@tonic-gate static int
8077c478bd9Sstevel@tonic-gate default_func (char *arg, int flags)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate #ifndef SUPPORT_DISKLESS
8107c478bd9Sstevel@tonic-gate   if (grub_strcmp (arg, "saved") == 0)
8117c478bd9Sstevel@tonic-gate     {
8127c478bd9Sstevel@tonic-gate       default_entry = saved_entryno;
8137c478bd9Sstevel@tonic-gate       return 0;
8147c478bd9Sstevel@tonic-gate     }
8157c478bd9Sstevel@tonic-gate #endif /* SUPPORT_DISKLESS */
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &default_entry))
8187c478bd9Sstevel@tonic-gate     return 1;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate   return 0;
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate static struct builtin builtin_default =
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate   "default",
8267c478bd9Sstevel@tonic-gate   default_func,
8277c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
8287c478bd9Sstevel@tonic-gate #if 0
8297c478bd9Sstevel@tonic-gate   "default [NUM | `saved']",
8307c478bd9Sstevel@tonic-gate   "Set the default entry to entry number NUM (if not specified, it is"
8317c478bd9Sstevel@tonic-gate   " 0, the first entry) or the entry number saved by savedefault."
8327c478bd9Sstevel@tonic-gate #endif
8337c478bd9Sstevel@tonic-gate };
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
8377c478bd9Sstevel@tonic-gate /* device */
8387c478bd9Sstevel@tonic-gate static int
8397c478bd9Sstevel@tonic-gate device_func (char *arg, int flags)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate   char *drive = arg;
8427c478bd9Sstevel@tonic-gate   char *device;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate   /* Get the drive number from DRIVE.  */
8457c478bd9Sstevel@tonic-gate   if (! set_device (drive))
8467c478bd9Sstevel@tonic-gate     return 1;
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate   /* Get the device argument.  */
8497c478bd9Sstevel@tonic-gate   device = skip_to (0, drive);
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate   /* Terminate DEVICE.  */
8527c478bd9Sstevel@tonic-gate   nul_terminate (device);
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate   if (! *device || ! check_device (device))
8557c478bd9Sstevel@tonic-gate     {
8567c478bd9Sstevel@tonic-gate       errnum = ERR_FILE_NOT_FOUND;
8577c478bd9Sstevel@tonic-gate       return 1;
8587c478bd9Sstevel@tonic-gate     }
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate   assign_device_name (current_drive, device);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate   return 0;
8637c478bd9Sstevel@tonic-gate }
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate static struct builtin builtin_device =
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate   "device",
8687c478bd9Sstevel@tonic-gate   device_func,
8697c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
8707c478bd9Sstevel@tonic-gate   "device DRIVE DEVICE",
8717c478bd9Sstevel@tonic-gate   "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command"
8727c478bd9Sstevel@tonic-gate   " can be used only in the grub shell."
8737c478bd9Sstevel@tonic-gate };
8747c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
8777c478bd9Sstevel@tonic-gate /* Debug Function for RPC */
8787c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
8797c478bd9Sstevel@tonic-gate /* portmap */
8807c478bd9Sstevel@tonic-gate static int
8817c478bd9Sstevel@tonic-gate portmap_func (char *arg, int flags)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate 	int port, prog, ver;
8847c478bd9Sstevel@tonic-gate 	if (! grub_eth_probe ()){
8857c478bd9Sstevel@tonic-gate 		grub_printf ("No ethernet card found.\n");
8867c478bd9Sstevel@tonic-gate 		errnum = ERR_DEV_VALUES;
8877c478bd9Sstevel@tonic-gate 		return 1;
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 	if ((prog = getdec(&arg)) == -1){
8907c478bd9Sstevel@tonic-gate 		grub_printf("Error prog number\n");
8917c478bd9Sstevel@tonic-gate 		return 1;
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 	arg = skip_to (0, arg);
8947c478bd9Sstevel@tonic-gate 	if ((ver = getdec(&arg)) == -1){
8957c478bd9Sstevel@tonic-gate 		grub_printf("Error ver number\n");
8967c478bd9Sstevel@tonic-gate 		return 1;
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate 	port = __pmapudp_getport(ARP_SERVER, prog, ver);
8997c478bd9Sstevel@tonic-gate 	printf("portmap getport %d", port);
9007c478bd9Sstevel@tonic-gate 	return 0;
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate static struct builtin builtin_portmap =
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate 	"portmap",
9067c478bd9Sstevel@tonic-gate 	portmap_func,
9077c478bd9Sstevel@tonic-gate 	BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
9087c478bd9Sstevel@tonic-gate 	"portmap prog_number vers_number",
9097c478bd9Sstevel@tonic-gate 	"Do portmap with the prog_number and vers_number"
9107c478bd9Sstevel@tonic-gate };
9117c478bd9Sstevel@tonic-gate #endif /* RPC_DEBUG */
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate /* dhcp */
9147c478bd9Sstevel@tonic-gate static int
9157c478bd9Sstevel@tonic-gate dhcp_func (char *arg, int flags)
9167c478bd9Sstevel@tonic-gate {
9177c478bd9Sstevel@tonic-gate   int with_configfile = 0;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
9207c478bd9Sstevel@tonic-gate       == 0)
9217c478bd9Sstevel@tonic-gate     {
9227c478bd9Sstevel@tonic-gate       with_configfile = 1;
9237c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
9247c478bd9Sstevel@tonic-gate     }
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate   if (! dhcp ())
9277c478bd9Sstevel@tonic-gate     {
9287c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
9297c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate       return 1;
9327c478bd9Sstevel@tonic-gate     }
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
9357c478bd9Sstevel@tonic-gate   print_network_configuration ();
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate   /* XXX: this can cause an endless loop, but there is no easy way to
9387c478bd9Sstevel@tonic-gate      detect such a loop unfortunately.  */
9397c478bd9Sstevel@tonic-gate   if (with_configfile)
9407c478bd9Sstevel@tonic-gate     configfile_func (config_file, flags);
9417c478bd9Sstevel@tonic-gate   else
9427c478bd9Sstevel@tonic-gate     solaris_config_file();
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate   return 0;
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate 
947*2506833eSJan Setje-Eilers static int
948*2506833eSJan Setje-Eilers test_config_file(char *menufile)
949*2506833eSJan Setje-Eilers {
950*2506833eSJan Setje-Eilers 	int err;
951*2506833eSJan Setje-Eilers 
952*2506833eSJan Setje-Eilers 	/*
953*2506833eSJan Setje-Eilers 	 * If the file exists, make it the default. Else, fallback
954*2506833eSJan Setje-Eilers 	 * to what it was.  Make sure we don't change errnum in the
955*2506833eSJan Setje-Eilers 	 * process.
956*2506833eSJan Setje-Eilers 	 */
957*2506833eSJan Setje-Eilers 	err = errnum;
958*2506833eSJan Setje-Eilers 	if (grub_open(menufile)) {
959*2506833eSJan Setje-Eilers 		grub_strcpy(config_file, menufile);
960*2506833eSJan Setje-Eilers 		grub_close();
961*2506833eSJan Setje-Eilers 		errnum = err;
962*2506833eSJan Setje-Eilers 		return (1);
963*2506833eSJan Setje-Eilers 	}
964*2506833eSJan Setje-Eilers 	errnum = err;
965*2506833eSJan Setje-Eilers 	return (0);
966*2506833eSJan Setje-Eilers }
967*2506833eSJan Setje-Eilers 
9687c478bd9Sstevel@tonic-gate static void solaris_config_file (void)
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate 	static char menufile[64];
9717c478bd9Sstevel@tonic-gate 	static char hexdigit[] = "0123456789ABCDEF";
9727c478bd9Sstevel@tonic-gate 	char *c = menufile;
9737c478bd9Sstevel@tonic-gate 	int i;
9747c478bd9Sstevel@tonic-gate 
975*2506833eSJan Setje-Eilers 	/*
976*2506833eSJan Setje-Eilers 	 * if DHCP option 150 has been provided, config_file will
977*2506833eSJan Setje-Eilers 	 * already contain the string, try it.
978*2506833eSJan Setje-Eilers 	 */
979*2506833eSJan Setje-Eilers 	if (configfile_origin == CFG_150) {
980*2506833eSJan Setje-Eilers 		if (test_config_file(config_file))
981*2506833eSJan Setje-Eilers 			return;
982*2506833eSJan Setje-Eilers 	}
9837c478bd9Sstevel@tonic-gate 
984*2506833eSJan Setje-Eilers 	/*
985*2506833eSJan Setje-Eilers 	 * try to find host (MAC address) specific configfile:
986*2506833eSJan Setje-Eilers 	 * menu.lst.01<ether_addr>
987*2506833eSJan Setje-Eilers 	 */
9882269adc8Sszhou 	grub_strcpy(c, "menu.lst.01");
9897c478bd9Sstevel@tonic-gate 	c += grub_strlen(c);
9907c478bd9Sstevel@tonic-gate 	for (i = 0; i < ETH_ALEN; i++) {
9917c478bd9Sstevel@tonic-gate 		unsigned char b = arptable[ARP_CLIENT].node[i];
9927c478bd9Sstevel@tonic-gate 		*c++ = hexdigit[b >> 4];
9937c478bd9Sstevel@tonic-gate 		*c++ = hexdigit[b & 0xf];
9947c478bd9Sstevel@tonic-gate 	}
9957c478bd9Sstevel@tonic-gate 	*c = 0;
996*2506833eSJan Setje-Eilers 	configfile_origin = CFG_MAC;
997*2506833eSJan Setje-Eilers 	if (test_config_file(menufile))
998*2506833eSJan Setje-Eilers 		return;
9997c478bd9Sstevel@tonic-gate 
10006759d08fScasper 	/*
1001*2506833eSJan Setje-Eilers 	 * try to find a configfile derived from the DHCP/bootp
1002*2506833eSJan Setje-Eilers 	 * BootFile string: menu.lst.<BootFile>
10037c478bd9Sstevel@tonic-gate 	 */
1004*2506833eSJan Setje-Eilers 	if (bootfile != NULL && bootfile[0] != 0) {
1005*2506833eSJan Setje-Eilers 		c = menufile;
1006*2506833eSJan Setje-Eilers 		grub_strcpy(c, "menu.lst.");
1007*2506833eSJan Setje-Eilers 		c += grub_strlen("menu.lst.");
1008*2506833eSJan Setje-Eilers 		i = grub_strlen("pxegrub.");
1009*2506833eSJan Setje-Eilers 		if (grub_memcmp(bootfile, "pxegrub.", i) == 0)
1010*2506833eSJan Setje-Eilers 			grub_strcpy(c, bootfile + i);
1011*2506833eSJan Setje-Eilers 		else
1012*2506833eSJan Setje-Eilers 			grub_strcpy(c, bootfile);
1013*2506833eSJan Setje-Eilers 		configfile_origin = CFG_BOOTFILE;
1014*2506833eSJan Setje-Eilers 		if (test_config_file(menufile))
1015*2506833eSJan Setje-Eilers 			return;
10167c478bd9Sstevel@tonic-gate 	}
1017*2506833eSJan Setje-Eilers 
1018*2506833eSJan Setje-Eilers 	/*
1019*2506833eSJan Setje-Eilers 	 * Default to hard coded "/boot/grub/menu.lst" config file.
1020*2506833eSJan Setje-Eilers 	 * This is the last resort, so there's no need to test it,
1021*2506833eSJan Setje-Eilers 	 * as there's nothing else to try.
1022*2506833eSJan Setje-Eilers 	 */
1023*2506833eSJan Setje-Eilers 	char *cp = config_file;
1024*2506833eSJan Setje-Eilers 	/* skip leading slashes for tftp */
1025*2506833eSJan Setje-Eilers 	while (*cp == '/')
1026*2506833eSJan Setje-Eilers 		++cp;
1027*2506833eSJan Setje-Eilers   	grub_memmove (config_file, cp, strlen(cp) + 1);
1028*2506833eSJan Setje-Eilers 	configfile_origin = CFG_HARDCODED;
10297c478bd9Sstevel@tonic-gate }
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate static struct builtin builtin_dhcp =
10327c478bd9Sstevel@tonic-gate {
10337c478bd9Sstevel@tonic-gate   "dhcp",
10347c478bd9Sstevel@tonic-gate   dhcp_func,
10357c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
10367c478bd9Sstevel@tonic-gate   "dhcp",
10377c478bd9Sstevel@tonic-gate   "Initialize a network device via DHCP."
10387c478bd9Sstevel@tonic-gate };
10397c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate static int terminal_func (char *arg, int flags);
10427c478bd9Sstevel@tonic-gate 
10431fac5a60Ssetje static int verbose_func(char *arg, int flags) {
10441fac5a60Ssetje 
10451fac5a60Ssetje     if (grub_strcmp(arg, "off") == 0) {
10461fac5a60Ssetje       silent.status = DEFER_SILENT;
10471fac5a60Ssetje       return;
10481fac5a60Ssetje     } else
10491fac5a60Ssetje         if (flags == BUILTIN_CMDLINE) {
10501fac5a60Ssetje           silent.status = DEFER_VERBOSE;
10511fac5a60Ssetje           return;
10521fac5a60Ssetje         }
10531fac5a60Ssetje 
10541fac5a60Ssetje   silent.status = VERBOSE;
10551fac5a60Ssetje 
1056ae115bc7Smrj   /* get back to text console */
10571fac5a60Ssetje   if (current_term->shutdown) {
10581fac5a60Ssetje     (*current_term->shutdown)();
10591fac5a60Ssetje     current_term = term_table; /* assumption: console is first */
10601fac5a60Ssetje   }
10611fac5a60Ssetje 
10621fac5a60Ssetje   /* dump the buffer */
10631fac5a60Ssetje   if (!silent.looped) {
10641fac5a60Ssetje     /* if the buffer hasn't looped, just print it */
10651fac5a60Ssetje     printf("%s", silent.buffer);
10661fac5a60Ssetje   } else {
10671fac5a60Ssetje     /*
10681fac5a60Ssetje      * If the buffer has looped, first print the oldest part of the buffer,
10691fac5a60Ssetje      * which is one past the current null. Then print the newer part which
10701fac5a60Ssetje      * starts at the beginning of the buffer.
10711fac5a60Ssetje      */
10721fac5a60Ssetje     printf("%s", silent.buffer_start + 1);
10731fac5a60Ssetje     printf("%s", silent.buffer);
10741fac5a60Ssetje   }
10751fac5a60Ssetje 
10761fac5a60Ssetje   return 0;
10771fac5a60Ssetje }
10781fac5a60Ssetje 
10791fac5a60Ssetje static struct builtin builtin_verbose =
10801fac5a60Ssetje {
10811fac5a60Ssetje   "verbose",
10821fac5a60Ssetje   verbose_func,
10831fac5a60Ssetje   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
10841fac5a60Ssetje   "verbose",
10851fac5a60Ssetje   "Verbose output during menu entry (script) execution."
10861fac5a60Ssetje };
10871fac5a60Ssetje 
10887c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate static int splashimage_func(char *arg, int flags) {
10917c478bd9Sstevel@tonic-gate     char splashimage[64];
10927c478bd9Sstevel@tonic-gate     int i;
10931fac5a60Ssetje 
10947c478bd9Sstevel@tonic-gate     /* filename can only be 64 characters due to our buffer size */
10957c478bd9Sstevel@tonic-gate     if (strlen(arg) > 63)
10967c478bd9Sstevel@tonic-gate 	return 1;
10977c478bd9Sstevel@tonic-gate 
10981fac5a60Ssetje     if (flags == BUILTIN_SCRIPT)
10991fac5a60Ssetje         flags = BUILTIN_CMDLINE;
11001fac5a60Ssetje 
1101a6e28364SSuhasini Peddada     if (flags == BUILTIN_CMDLINE) {
1102a6e28364SSuhasini Peddada 	if (!grub_open(arg))
1103a6e28364SSuhasini Peddada 	    return 1;
1104a6e28364SSuhasini Peddada 	grub_close();
1105a6e28364SSuhasini Peddada     }
11067c478bd9Sstevel@tonic-gate 
1107a6e28364SSuhasini Peddada     strcpy(splashimage, arg);
110841c4174fSWilliam Kucharski 
11097c478bd9Sstevel@tonic-gate     /* get rid of TERM_NEED_INIT from the graphics terminal. */
11107c478bd9Sstevel@tonic-gate     for (i = 0; term_table[i].name; i++) {
11117c478bd9Sstevel@tonic-gate 	if (grub_strcmp (term_table[i].name, "graphics") == 0) {
11127c478bd9Sstevel@tonic-gate 	    term_table[i].flags &= ~TERM_NEED_INIT;
11137c478bd9Sstevel@tonic-gate 	    break;
11147c478bd9Sstevel@tonic-gate 	}
11157c478bd9Sstevel@tonic-gate     }
11169b4e3ac2SWilliam Kucharski 
1117a6e28364SSuhasini Peddada     graphics_set_splash(splashimage);
1118a6e28364SSuhasini Peddada 
11197c478bd9Sstevel@tonic-gate     if (flags == BUILTIN_CMDLINE && graphics_inited) {
11201fac5a60Ssetje 	/*
11211fac5a60Ssetje 	 * calling graphics_end() here flickers the screen black. OTOH not
11221fac5a60Ssetje 	 * calling it gets us odd plane interlacing / early palette switching ?
11231fac5a60Ssetje 	 * ideally one should figure out how to double buffer and switch...
11241fac5a60Ssetje 	 */
11257c478bd9Sstevel@tonic-gate 	graphics_end();
11267c478bd9Sstevel@tonic-gate 	graphics_init();
11277c478bd9Sstevel@tonic-gate 	graphics_cls();
11287c478bd9Sstevel@tonic-gate     }
11297c478bd9Sstevel@tonic-gate 
11309b4e3ac2SWilliam Kucharski     /*
11319b4e3ac2SWilliam Kucharski      * This call does not explicitly initialize graphics mode, but rather
11329b4e3ac2SWilliam Kucharski      * simply sets the terminal type unless we're in command line mode and
11339b4e3ac2SWilliam Kucharski      * call this function while in terminal mode.
11349b4e3ac2SWilliam Kucharski      */
11357c478bd9Sstevel@tonic-gate     terminal_func("graphics", flags);
11367c478bd9Sstevel@tonic-gate 
11371fac5a60Ssetje     reset_term = 0;
11381fac5a60Ssetje 
11397c478bd9Sstevel@tonic-gate     return 0;
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate static struct builtin builtin_splashimage =
11437c478bd9Sstevel@tonic-gate {
11447c478bd9Sstevel@tonic-gate   "splashimage",
11457c478bd9Sstevel@tonic-gate   splashimage_func,
11461fac5a60Ssetje   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
11477c478bd9Sstevel@tonic-gate   "splashimage FILE",
11487c478bd9Sstevel@tonic-gate   "Load FILE as the background image when in graphics mode."
11497c478bd9Sstevel@tonic-gate };
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate /* foreground */
11537c478bd9Sstevel@tonic-gate static int
11547c478bd9Sstevel@tonic-gate foreground_func(char *arg, int flags)
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate     if (grub_strlen(arg) == 6) {
11577c478bd9Sstevel@tonic-gate 	int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
11587c478bd9Sstevel@tonic-gate 	int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
11597c478bd9Sstevel@tonic-gate 	int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	foreground = (r << 16) | (g << 8) | b;
11627c478bd9Sstevel@tonic-gate 	if (graphics_inited)
11637c478bd9Sstevel@tonic-gate 	    graphics_set_palette(15, r, g, b);
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 	return (0);
11667c478bd9Sstevel@tonic-gate     }
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate     return (1);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate static struct builtin builtin_foreground =
11727c478bd9Sstevel@tonic-gate {
11737c478bd9Sstevel@tonic-gate   "foreground",
11747c478bd9Sstevel@tonic-gate   foreground_func,
117567ce1dadSJan Setje-Eilers   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
11767c478bd9Sstevel@tonic-gate   "foreground RRGGBB",
11777c478bd9Sstevel@tonic-gate   "Sets the foreground color when in graphics mode."
11787c478bd9Sstevel@tonic-gate   "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
11797c478bd9Sstevel@tonic-gate };
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate /* background */
11837c478bd9Sstevel@tonic-gate static int
11847c478bd9Sstevel@tonic-gate background_func(char *arg, int flags)
11857c478bd9Sstevel@tonic-gate {
11867c478bd9Sstevel@tonic-gate     if (grub_strlen(arg) == 6) {
11877c478bd9Sstevel@tonic-gate 	int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
11887c478bd9Sstevel@tonic-gate 	int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
11897c478bd9Sstevel@tonic-gate 	int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	background = (r << 16) | (g << 8) | b;
11927c478bd9Sstevel@tonic-gate 	if (graphics_inited)
11937c478bd9Sstevel@tonic-gate 	    graphics_set_palette(0, r, g, b);
11947c478bd9Sstevel@tonic-gate 	return (0);
11957c478bd9Sstevel@tonic-gate     }
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate     return (1);
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate static struct builtin builtin_background =
12017c478bd9Sstevel@tonic-gate {
12027c478bd9Sstevel@tonic-gate   "background",
12037c478bd9Sstevel@tonic-gate   background_func,
120467ce1dadSJan Setje-Eilers   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
12057c478bd9Sstevel@tonic-gate   "background RRGGBB",
12067c478bd9Sstevel@tonic-gate   "Sets the background color when in graphics mode."
12077c478bd9Sstevel@tonic-gate   "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
12087c478bd9Sstevel@tonic-gate };
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate #endif /* SUPPORT_GRAPHICS */
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate /* clear */
12147c478bd9Sstevel@tonic-gate static int
12157c478bd9Sstevel@tonic-gate clear_func()
12167c478bd9Sstevel@tonic-gate {
12177c478bd9Sstevel@tonic-gate   if (current_term->cls)
12187c478bd9Sstevel@tonic-gate     current_term->cls();
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate   return 0;
12217c478bd9Sstevel@tonic-gate }
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate static struct builtin builtin_clear =
12247c478bd9Sstevel@tonic-gate {
12257c478bd9Sstevel@tonic-gate   "clear",
12267c478bd9Sstevel@tonic-gate   clear_func,
12277c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
12287c478bd9Sstevel@tonic-gate   "clear",
12297c478bd9Sstevel@tonic-gate   "Clear the screen"
12307c478bd9Sstevel@tonic-gate };
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate /* displayapm */
12337c478bd9Sstevel@tonic-gate static int
12347c478bd9Sstevel@tonic-gate displayapm_func (char *arg, int flags)
12357c478bd9Sstevel@tonic-gate {
12367c478bd9Sstevel@tonic-gate   if (mbi.flags & MB_INFO_APM_TABLE)
12377c478bd9Sstevel@tonic-gate     {
12387c478bd9Sstevel@tonic-gate       grub_printf ("APM BIOS information:\n"
12397c478bd9Sstevel@tonic-gate 		   " Version:          0x%x\n"
12407c478bd9Sstevel@tonic-gate 		   " 32-bit CS:        0x%x\n"
12417c478bd9Sstevel@tonic-gate 		   " Offset:           0x%x\n"
12427c478bd9Sstevel@tonic-gate 		   " 16-bit CS:        0x%x\n"
12437c478bd9Sstevel@tonic-gate 		   " 16-bit DS:        0x%x\n"
12447c478bd9Sstevel@tonic-gate 		   " 32-bit CS length: 0x%x\n"
12457c478bd9Sstevel@tonic-gate 		   " 16-bit CS length: 0x%x\n"
12467c478bd9Sstevel@tonic-gate 		   " 16-bit DS length: 0x%x\n",
12477c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.version,
12487c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg,
12497c478bd9Sstevel@tonic-gate 		   apm_bios_info.offset,
12507c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_16,
12517c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.dseg_16,
12527c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_len,
12537c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_16_len,
12547c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.dseg_16_len);
12557c478bd9Sstevel@tonic-gate     }
12567c478bd9Sstevel@tonic-gate   else
12577c478bd9Sstevel@tonic-gate     {
12587c478bd9Sstevel@tonic-gate       grub_printf ("No APM BIOS found or probe failed\n");
12597c478bd9Sstevel@tonic-gate     }
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate   return 0;
12627c478bd9Sstevel@tonic-gate }
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate static struct builtin builtin_displayapm =
12657c478bd9Sstevel@tonic-gate {
12667c478bd9Sstevel@tonic-gate   "displayapm",
12677c478bd9Sstevel@tonic-gate   displayapm_func,
12687c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
12697c478bd9Sstevel@tonic-gate   "displayapm",
12707c478bd9Sstevel@tonic-gate   "Display APM BIOS information."
12717c478bd9Sstevel@tonic-gate };
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate /* displaymem */
12757c478bd9Sstevel@tonic-gate static int
12767c478bd9Sstevel@tonic-gate displaymem_func (char *arg, int flags)
12777c478bd9Sstevel@tonic-gate {
12787c478bd9Sstevel@tonic-gate   if (get_eisamemsize () != -1)
12797c478bd9Sstevel@tonic-gate     grub_printf (" EISA Memory BIOS Interface is present\n");
12807c478bd9Sstevel@tonic-gate   if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0
12817c478bd9Sstevel@tonic-gate       || *((int *) SCRATCHADDR) != 0)
12827c478bd9Sstevel@tonic-gate     grub_printf (" Address Map BIOS Interface is present\n");
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate   grub_printf (" Lower memory: %uK, "
12857c478bd9Sstevel@tonic-gate 	       "Upper memory (to first chipset hole): %uK\n",
12867c478bd9Sstevel@tonic-gate 	       mbi.mem_lower, mbi.mem_upper);
12877c478bd9Sstevel@tonic-gate 
1288342440ecSPrasad Singamsetty   if (min_mem64 != 0)
1289342440ecSPrasad Singamsetty   	grub_printf (" Memory limit for 64-bit ISADIR expansion: %uMB\n",
1290342440ecSPrasad Singamsetty 	    min_mem64);
1291342440ecSPrasad Singamsetty 
12927c478bd9Sstevel@tonic-gate   if (mbi.flags & MB_INFO_MEM_MAP)
12937c478bd9Sstevel@tonic-gate     {
12947c478bd9Sstevel@tonic-gate       struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
12957c478bd9Sstevel@tonic-gate       int end_addr = mbi.mmap_addr + mbi.mmap_length;
12967c478bd9Sstevel@tonic-gate 
12977c478bd9Sstevel@tonic-gate       grub_printf (" [Address Range Descriptor entries "
12987c478bd9Sstevel@tonic-gate 		   "immediately follow (values are 64-bit)]\n");
12997c478bd9Sstevel@tonic-gate       while (end_addr > (int) map)
13007c478bd9Sstevel@tonic-gate 	{
13017c478bd9Sstevel@tonic-gate 	  char *str;
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	  if (map->Type == MB_ARD_MEMORY)
13047c478bd9Sstevel@tonic-gate 	    str = "Usable RAM";
13057c478bd9Sstevel@tonic-gate 	  else
13067c478bd9Sstevel@tonic-gate 	    str = "Reserved";
13077c478bd9Sstevel@tonic-gate 	  grub_printf ("   %s:  Base Address:  0x%x X 4GB + 0x%x,\n"
1308342440ecSPrasad Singamsetty 		"      Length:   0x%x X 4GB + 0x%x bytes\n",
1309342440ecSPrasad Singamsetty 		str,
1310342440ecSPrasad Singamsetty 		(unsigned long) (map->BaseAddr >> 32),
1311342440ecSPrasad Singamsetty 		(unsigned long) (map->BaseAddr & 0xFFFFFFFF),
1312342440ecSPrasad Singamsetty 		(unsigned long) (map->Length >> 32),
1313342440ecSPrasad Singamsetty 		(unsigned long) (map->Length & 0xFFFFFFFF));
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 	  map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size));
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate     }
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate   return 0;
13207c478bd9Sstevel@tonic-gate }
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate static struct builtin builtin_displaymem =
13237c478bd9Sstevel@tonic-gate {
13247c478bd9Sstevel@tonic-gate   "displaymem",
13257c478bd9Sstevel@tonic-gate   displaymem_func,
13267c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
13277c478bd9Sstevel@tonic-gate   "displaymem",
13287c478bd9Sstevel@tonic-gate   "Display what GRUB thinks the system address space map of the"
13297c478bd9Sstevel@tonic-gate   " machine is, including all regions of physical RAM installed."
13307c478bd9Sstevel@tonic-gate };
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate /* dump FROM TO */
13347c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
13357c478bd9Sstevel@tonic-gate static int
13367c478bd9Sstevel@tonic-gate dump_func (char *arg, int flags)
13377c478bd9Sstevel@tonic-gate {
13387c478bd9Sstevel@tonic-gate   char *from, *to;
13397c478bd9Sstevel@tonic-gate   FILE *fp;
13407c478bd9Sstevel@tonic-gate   char c;
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate   from = arg;
13437c478bd9Sstevel@tonic-gate   to = skip_to (0, arg);
13447c478bd9Sstevel@tonic-gate   if (! *from || ! *to)
13457c478bd9Sstevel@tonic-gate     {
13467c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
13477c478bd9Sstevel@tonic-gate       return 1;
13487c478bd9Sstevel@tonic-gate     }
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate   nul_terminate (from);
13517c478bd9Sstevel@tonic-gate   nul_terminate (to);
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate   if (! grub_open (from))
13547c478bd9Sstevel@tonic-gate     return 1;
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate   fp = fopen (to, "w");
13577c478bd9Sstevel@tonic-gate   if (! fp)
13587c478bd9Sstevel@tonic-gate     {
13597c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
13607c478bd9Sstevel@tonic-gate       return 1;
13617c478bd9Sstevel@tonic-gate     }
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate   while (grub_read (&c, 1))
13647c478bd9Sstevel@tonic-gate     if (fputc (c, fp) == EOF)
13657c478bd9Sstevel@tonic-gate       {
13667c478bd9Sstevel@tonic-gate 	errnum = ERR_WRITE;
13677c478bd9Sstevel@tonic-gate 	fclose (fp);
13687c478bd9Sstevel@tonic-gate 	return 1;
13697c478bd9Sstevel@tonic-gate       }
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate   if (fclose (fp) == EOF)
13727c478bd9Sstevel@tonic-gate     {
13737c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
13747c478bd9Sstevel@tonic-gate       return 1;
13757c478bd9Sstevel@tonic-gate     }
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate   grub_close ();
13787c478bd9Sstevel@tonic-gate   return 0;
13797c478bd9Sstevel@tonic-gate }
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate static struct builtin builtin_dump =
13827c478bd9Sstevel@tonic-gate   {
13837c478bd9Sstevel@tonic-gate     "dump",
13847c478bd9Sstevel@tonic-gate     dump_func,
13857c478bd9Sstevel@tonic-gate     BUILTIN_CMDLINE,
13867c478bd9Sstevel@tonic-gate     "dump FROM TO",
13877c478bd9Sstevel@tonic-gate     "Dump the contents of the file FROM to the file TO. FROM must be"
13887c478bd9Sstevel@tonic-gate     " a GRUB file and TO must be an OS file."
13897c478bd9Sstevel@tonic-gate   };
13907c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate static char embed_info[32];
13947c478bd9Sstevel@tonic-gate /* embed */
13957c478bd9Sstevel@tonic-gate /* Embed a Stage 1.5 in the first cylinder after MBR or in the
13967c478bd9Sstevel@tonic-gate    bootloader block in a FFS.  */
13977c478bd9Sstevel@tonic-gate static int
13987c478bd9Sstevel@tonic-gate embed_func (char *arg, int flags)
13997c478bd9Sstevel@tonic-gate {
14007c478bd9Sstevel@tonic-gate   char *stage1_5;
14017c478bd9Sstevel@tonic-gate   char *device;
14027c478bd9Sstevel@tonic-gate   char *stage1_5_buffer = (char *) RAW_ADDR (0x100000);
14037c478bd9Sstevel@tonic-gate   int len, size;
14047c478bd9Sstevel@tonic-gate   int sector;
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate   stage1_5 = arg;
14077c478bd9Sstevel@tonic-gate   device = skip_to (0, stage1_5);
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate   /* Open a Stage 1.5.  */
14107c478bd9Sstevel@tonic-gate   if (! grub_open (stage1_5))
14117c478bd9Sstevel@tonic-gate     return 1;
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate   /* Read the whole of the Stage 1.5.  */
14147c478bd9Sstevel@tonic-gate   len = grub_read (stage1_5_buffer, -1);
14157c478bd9Sstevel@tonic-gate   grub_close ();
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate   if (errnum)
14187c478bd9Sstevel@tonic-gate     return 1;
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate   size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE;
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate   /* Get the device where the Stage 1.5 will be embedded.  */
14237c478bd9Sstevel@tonic-gate   set_device (device);
14247c478bd9Sstevel@tonic-gate   if (errnum)
14257c478bd9Sstevel@tonic-gate     return 1;
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate   if (current_partition == 0xFFFFFF)
14287c478bd9Sstevel@tonic-gate     {
14297c478bd9Sstevel@tonic-gate       /* Embed it after the MBR.  */
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate       char mbr[SECTOR_SIZE];
14327c478bd9Sstevel@tonic-gate       char ezbios_check[2*SECTOR_SIZE];
14337c478bd9Sstevel@tonic-gate       int i;
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate       /* Open the partition.  */
14367c478bd9Sstevel@tonic-gate       if (! open_partition ())
14377c478bd9Sstevel@tonic-gate 	return 1;
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate       /* No floppy has MBR.  */
14407c478bd9Sstevel@tonic-gate       if (! (current_drive & 0x80))
14417c478bd9Sstevel@tonic-gate 	{
14427c478bd9Sstevel@tonic-gate 	  errnum = ERR_DEV_VALUES;
14437c478bd9Sstevel@tonic-gate 	  return 1;
14447c478bd9Sstevel@tonic-gate 	}
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate       /* Read the MBR of CURRENT_DRIVE.  */
14477c478bd9Sstevel@tonic-gate       if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr))
14487c478bd9Sstevel@tonic-gate 	return 1;
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate       /* Sanity check.  */
14517c478bd9Sstevel@tonic-gate       if (! PC_MBR_CHECK_SIG (mbr))
14527c478bd9Sstevel@tonic-gate 	{
14537c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_PART_TABLE;
14547c478bd9Sstevel@tonic-gate 	  return 1;
14557c478bd9Sstevel@tonic-gate 	}
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate       /* Check if the disk can store the Stage 1.5.  */
14587c478bd9Sstevel@tonic-gate       for (i = 0; i < 4; i++)
14597c478bd9Sstevel@tonic-gate 	if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size)
14607c478bd9Sstevel@tonic-gate 	  {
14617c478bd9Sstevel@tonic-gate 	    errnum = ERR_NO_DISK_SPACE;
14627c478bd9Sstevel@tonic-gate 	    return 1;
14637c478bd9Sstevel@tonic-gate 	  }
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate       /* Check for EZ-BIOS signature. It should be in the third
14667c478bd9Sstevel@tonic-gate        * sector, but due to remapping it can appear in the second, so
14677c478bd9Sstevel@tonic-gate        * load and check both.
14687c478bd9Sstevel@tonic-gate        */
14697c478bd9Sstevel@tonic-gate       if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check))
14707c478bd9Sstevel@tonic-gate 	return 1;
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate       if (! memcmp (ezbios_check + 3, "AERMH", 5)
14737c478bd9Sstevel@tonic-gate 	  || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5))
14747c478bd9Sstevel@tonic-gate 	{
14757c478bd9Sstevel@tonic-gate 	  /* The space after the MBR is used by EZ-BIOS which we must
14767c478bd9Sstevel@tonic-gate 	   * not overwrite.
14777c478bd9Sstevel@tonic-gate 	   */
14787c478bd9Sstevel@tonic-gate 	  errnum = ERR_NO_DISK_SPACE;
14797c478bd9Sstevel@tonic-gate 	  return 1;
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate       sector = 1;
14837c478bd9Sstevel@tonic-gate     }
14847c478bd9Sstevel@tonic-gate   else
14857c478bd9Sstevel@tonic-gate     {
14867c478bd9Sstevel@tonic-gate       /* Embed it in the bootloader block in the filesystem.  */
14877c478bd9Sstevel@tonic-gate       int start_sector;
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate       /* Open the partition.  */
14907c478bd9Sstevel@tonic-gate       if (! open_device ())
14917c478bd9Sstevel@tonic-gate 	return 1;
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate       /* Check if the current slice supports embedding.  */
14947c478bd9Sstevel@tonic-gate       if (fsys_table[fsys_type].embed_func == 0
14957c478bd9Sstevel@tonic-gate 	  || ! fsys_table[fsys_type].embed_func (&start_sector, size))
14967c478bd9Sstevel@tonic-gate 	{
14977c478bd9Sstevel@tonic-gate 	  errnum = ERR_DEV_VALUES;
14987c478bd9Sstevel@tonic-gate 	  return 1;
14997c478bd9Sstevel@tonic-gate 	}
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate       sector = part_start + start_sector;
15027c478bd9Sstevel@tonic-gate     }
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate   /* Clear the cache.  */
1505342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate   /* Now perform the embedding.  */
15087c478bd9Sstevel@tonic-gate   if (! devwrite (sector - part_start, size, stage1_5_buffer))
15097c478bd9Sstevel@tonic-gate     return 1;
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate   grub_printf (" %d sectors are embedded.\n", size);
15127c478bd9Sstevel@tonic-gate   grub_sprintf (embed_info, "%d+%d", sector - part_start, size);
15137c478bd9Sstevel@tonic-gate   return 0;
15147c478bd9Sstevel@tonic-gate }
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate static struct builtin builtin_embed =
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate   "embed",
15197c478bd9Sstevel@tonic-gate   embed_func,
15207c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
15217c478bd9Sstevel@tonic-gate   "embed STAGE1_5 DEVICE",
15227c478bd9Sstevel@tonic-gate   "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE"
15237c478bd9Sstevel@tonic-gate   " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition."
15247c478bd9Sstevel@tonic-gate   " Print the number of sectors which STAGE1_5 occupies if successful."
15257c478bd9Sstevel@tonic-gate };
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate /* fallback */
15297c478bd9Sstevel@tonic-gate static int
15307c478bd9Sstevel@tonic-gate fallback_func (char *arg, int flags)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate   int i = 0;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate   while (*arg)
15357c478bd9Sstevel@tonic-gate     {
15367c478bd9Sstevel@tonic-gate       int entry;
15377c478bd9Sstevel@tonic-gate       int j;
15387c478bd9Sstevel@tonic-gate 
15397c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&arg, &entry))
15407c478bd9Sstevel@tonic-gate 	return 1;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate       /* Remove duplications to prevent infinite looping.  */
15437c478bd9Sstevel@tonic-gate       for (j = 0; j < i; j++)
15447c478bd9Sstevel@tonic-gate 	if (entry == fallback_entries[j])
15457c478bd9Sstevel@tonic-gate 	  break;
15467c478bd9Sstevel@tonic-gate       if (j != i)
15477c478bd9Sstevel@tonic-gate 	continue;
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate       fallback_entries[i++] = entry;
15507c478bd9Sstevel@tonic-gate       if (i == MAX_FALLBACK_ENTRIES)
15517c478bd9Sstevel@tonic-gate 	break;
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
15547c478bd9Sstevel@tonic-gate     }
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate   if (i < MAX_FALLBACK_ENTRIES)
15577c478bd9Sstevel@tonic-gate     fallback_entries[i] = -1;
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate   fallback_entryno = (i == 0) ? -1 : 0;
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate   return 0;
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate static struct builtin builtin_fallback =
15657c478bd9Sstevel@tonic-gate {
15667c478bd9Sstevel@tonic-gate   "fallback",
15677c478bd9Sstevel@tonic-gate   fallback_func,
15687c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
15697c478bd9Sstevel@tonic-gate #if 0
15707c478bd9Sstevel@tonic-gate   "fallback NUM...",
15717c478bd9Sstevel@tonic-gate   "Go into unattended boot mode: if the default boot entry has any"
15727c478bd9Sstevel@tonic-gate   " errors, instead of waiting for the user to do anything, it"
15737c478bd9Sstevel@tonic-gate   " immediately starts over using the NUM entry (same numbering as the"
15747c478bd9Sstevel@tonic-gate   " `default' command). This obviously won't help if the machine"
15757c478bd9Sstevel@tonic-gate   " was rebooted by a kernel that GRUB loaded."
15767c478bd9Sstevel@tonic-gate #endif
15777c478bd9Sstevel@tonic-gate };
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 
1580051aabe6Staylor 
1581051aabe6Staylor void
1582051aabe6Staylor set_root (char *root, unsigned long drive, unsigned long part)
1583051aabe6Staylor {
1584051aabe6Staylor   int bsd_part = (part >> 8) & 0xFF;
1585051aabe6Staylor   int pc_slice = part >> 16;
1586051aabe6Staylor 
1587051aabe6Staylor   if (bsd_part == 0xFF) {
1588051aabe6Staylor     grub_sprintf (root, "(hd%d,%d)\n", drive - 0x80, pc_slice);
1589051aabe6Staylor   } else {
1590051aabe6Staylor     grub_sprintf (root, "(hd%d,%d,%c)\n",
1591051aabe6Staylor 		 drive - 0x80, pc_slice, bsd_part + 'a');
1592051aabe6Staylor   }
1593051aabe6Staylor }
1594051aabe6Staylor 
15957c478bd9Sstevel@tonic-gate static int
1596eb2bd662Svikram find_common (char *arg, char *root, int for_root, int flags)
15977c478bd9Sstevel@tonic-gate {
1598eb2bd662Svikram   char *filename = NULL;
1599eb2bd662Svikram   static char argpart[32];
1600eb2bd662Svikram   static char device[32];
1601eb2bd662Svikram   char *tmp_argpart = NULL;
16027c478bd9Sstevel@tonic-gate   unsigned long drive;
16037c478bd9Sstevel@tonic-gate   unsigned long tmp_drive = saved_drive;
16047c478bd9Sstevel@tonic-gate   unsigned long tmp_partition = saved_partition;
16057c478bd9Sstevel@tonic-gate   int got_file = 0;
1606eb2bd662Svikram   static char bootsign[BOOTSIGN_LEN];
1607eb2bd662Svikram 
1608eb2bd662Svikram   /*
1609eb2bd662Svikram    * If argument has partition information (findroot command only), then
1610eb2bd662Svikram    * it can't be a floppy
1611eb2bd662Svikram    */
1612eb2bd662Svikram   if (for_root && arg[0] == '(') {
1613eb2bd662Svikram 	tmp_argpart = grub_strchr(arg + 1, ',');
1614eb2bd662Svikram         if (tmp_argpart == NULL)
1615eb2bd662Svikram 		goto out;
1616eb2bd662Svikram 	grub_strcpy(argpart, tmp_argpart);
1617eb2bd662Svikram 	*tmp_argpart = '\0';
1618eb2bd662Svikram 	arg++;
1619eb2bd662Svikram         grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
1620eb2bd662Svikram 	filename = bootsign;
1621eb2bd662Svikram 	goto harddisk;
1622eb2bd662Svikram   } else if (for_root) {
1623eb2bd662Svikram 	/* Boot signature without partition/slice information */
1624eb2bd662Svikram         grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
1625eb2bd662Svikram 	filename = bootsign;
1626eb2bd662Svikram   } else {
1627eb2bd662Svikram 	/* plain vanilla find cmd */
1628eb2bd662Svikram 	filename = arg;
1629eb2bd662Svikram   }
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate   /* Floppies.  */
16327c478bd9Sstevel@tonic-gate   for (drive = 0; drive < 8; drive++)
16337c478bd9Sstevel@tonic-gate     {
16347c478bd9Sstevel@tonic-gate       current_drive = drive;
16357c478bd9Sstevel@tonic-gate       current_partition = 0xFFFFFF;
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate       if (open_device ())
16387c478bd9Sstevel@tonic-gate 	{
16397c478bd9Sstevel@tonic-gate 	  saved_drive = current_drive;
16407c478bd9Sstevel@tonic-gate 	  saved_partition = current_partition;
16417c478bd9Sstevel@tonic-gate 	  if (grub_open (filename))
16427c478bd9Sstevel@tonic-gate 	    {
16437c478bd9Sstevel@tonic-gate 	      grub_close ();
16447c478bd9Sstevel@tonic-gate 	      got_file = 1;
1645eb2bd662Svikram 	      if (for_root) {
1646eb2bd662Svikram 		 grub_sprintf(root, "(fd%d)", drive);
1647eb2bd662Svikram 		 goto out;
1648eb2bd662Svikram 	      } else
1649eb2bd662Svikram 	         grub_printf (" (fd%d)\n", drive);
16507c478bd9Sstevel@tonic-gate 	    }
16517c478bd9Sstevel@tonic-gate 	}
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
16547c478bd9Sstevel@tonic-gate     }
16557c478bd9Sstevel@tonic-gate 
1656eb2bd662Svikram harddisk:
16577c478bd9Sstevel@tonic-gate   /* Hard disks.  */
16587c478bd9Sstevel@tonic-gate   for (drive = 0x80; drive < 0x88; drive++)
16597c478bd9Sstevel@tonic-gate     {
16607c478bd9Sstevel@tonic-gate       unsigned long part = 0xFFFFFF;
16617c478bd9Sstevel@tonic-gate       unsigned long start, len, offset, ext_offset;
16627c478bd9Sstevel@tonic-gate       int type, entry;
16637c478bd9Sstevel@tonic-gate       char buf[SECTOR_SIZE];
16647c478bd9Sstevel@tonic-gate 
1665eb2bd662Svikram       if (for_root && tmp_argpart) {
1666051aabe6Staylor 	grub_sprintf(device, "(hd%d%s", drive - 0x80, argpart);
1667eb2bd662Svikram 	set_device(device);
1668eb2bd662Svikram         errnum = ERR_NONE;
1669eb2bd662Svikram 	part = current_partition;
1670eb2bd662Svikram 	if (open_device ()) {
1671eb2bd662Svikram 	   saved_drive = current_drive;
1672eb2bd662Svikram 	   saved_partition = current_partition;
1673eb2bd662Svikram            errnum = ERR_NONE;
1674eb2bd662Svikram 	   if (grub_open (filename)) {
1675eb2bd662Svikram 	      grub_close ();
1676eb2bd662Svikram 	      got_file = 1;
1677051aabe6Staylor 	      if (is_zfs_mount == 0) {
1678051aabe6Staylor 	        set_root(root, current_drive, current_partition);
1679051aabe6Staylor 	        goto out;
1680051aabe6Staylor 	      } else {
1681051aabe6Staylor 		best_drive = current_drive;
1682051aabe6Staylor 		best_part = current_partition;
1683051aabe6Staylor 	      }
1684eb2bd662Svikram            }
1685eb2bd662Svikram 	}
1686eb2bd662Svikram         errnum = ERR_NONE;
1687eb2bd662Svikram 	continue;
1688eb2bd662Svikram       }
16897c478bd9Sstevel@tonic-gate       current_drive = drive;
16907c478bd9Sstevel@tonic-gate       while (next_partition (drive, 0xFFFFFF, &part, &type,
16917c478bd9Sstevel@tonic-gate 			     &start, &len, &offset, &entry,
16927c478bd9Sstevel@tonic-gate 			     &ext_offset, buf))
16937c478bd9Sstevel@tonic-gate 	{
16947c478bd9Sstevel@tonic-gate 	  if (type != PC_SLICE_TYPE_NONE
16957c478bd9Sstevel@tonic-gate 	      && ! IS_PC_SLICE_TYPE_BSD (type)
16967c478bd9Sstevel@tonic-gate 	      && ! IS_PC_SLICE_TYPE_EXTENDED (type))
16977c478bd9Sstevel@tonic-gate 	    {
16987c478bd9Sstevel@tonic-gate 	      current_partition = part;
16997c478bd9Sstevel@tonic-gate 	      if (open_device ())
17007c478bd9Sstevel@tonic-gate 		{
17017c478bd9Sstevel@tonic-gate 		  saved_drive = current_drive;
17027c478bd9Sstevel@tonic-gate 		  saved_partition = current_partition;
17037c478bd9Sstevel@tonic-gate 		  if (grub_open (filename))
17047c478bd9Sstevel@tonic-gate 		    {
1705051aabe6Staylor 		      char tmproot[32];
1706051aabe6Staylor 
17077c478bd9Sstevel@tonic-gate 		      grub_close ();
1708eb2bd662Svikram 		      got_file = 1;
1709051aabe6Staylor 		      set_root(tmproot, drive, part);
1710051aabe6Staylor 		      if (for_root) {
1711051aabe6Staylor 		 	grub_memcpy(root, tmproot, sizeof(tmproot));
1712051aabe6Staylor 			if (is_zfs_mount == 0) {
1713051aabe6Staylor 			      goto out;
1714051aabe6Staylor 			} else {
1715051aabe6Staylor 			      best_drive = current_drive;
1716051aabe6Staylor 			      best_part = current_partition;
1717051aabe6Staylor 			}
1718eb2bd662Svikram 		      } else {
1719051aabe6Staylor 			grub_printf("%s", tmproot);
1720eb2bd662Svikram 		      }
17217c478bd9Sstevel@tonic-gate 		    }
17227c478bd9Sstevel@tonic-gate 		}
17237c478bd9Sstevel@tonic-gate 	    }
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	  /* We want to ignore any error here.  */
17267c478bd9Sstevel@tonic-gate 	  errnum = ERR_NONE;
17277c478bd9Sstevel@tonic-gate 	}
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate       /* next_partition always sets ERRNUM in the last call, so clear
17307c478bd9Sstevel@tonic-gate 	 it.  */
17317c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
17327c478bd9Sstevel@tonic-gate     }
17337c478bd9Sstevel@tonic-gate 
1734eb2bd662Svikram out:
1735051aabe6Staylor   if (is_zfs_mount && for_root) {
1736051aabe6Staylor         set_root(root, best_drive, best_part);
1737051aabe6Staylor 	buf_drive = -1;
1738051aabe6Staylor   } else {
1739051aabe6Staylor 	saved_drive = tmp_drive;
1740051aabe6Staylor 	saved_partition = tmp_partition;
1741051aabe6Staylor   }
1742eb2bd662Svikram   if (tmp_argpart)
1743eb2bd662Svikram 	*tmp_argpart = ',';
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate   if (got_file)
17467c478bd9Sstevel@tonic-gate     {
17477c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
17487c478bd9Sstevel@tonic-gate       return 0;
17497c478bd9Sstevel@tonic-gate     }
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate   errnum = ERR_FILE_NOT_FOUND;
17527c478bd9Sstevel@tonic-gate   return 1;
17537c478bd9Sstevel@tonic-gate }
17547c478bd9Sstevel@tonic-gate 
1755eb2bd662Svikram /* find */
1756eb2bd662Svikram /* Search for the filename ARG in all of partitions.  */
1757eb2bd662Svikram static int
1758eb2bd662Svikram find_func (char *arg, int flags)
1759eb2bd662Svikram {
1760eb2bd662Svikram 	return (find_common(arg, NULL, 0, flags));
1761eb2bd662Svikram }
1762eb2bd662Svikram 
17637c478bd9Sstevel@tonic-gate static struct builtin builtin_find =
17647c478bd9Sstevel@tonic-gate {
17657c478bd9Sstevel@tonic-gate   "find",
17667c478bd9Sstevel@tonic-gate   find_func,
17677c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
17687c478bd9Sstevel@tonic-gate   "find FILENAME",
17697c478bd9Sstevel@tonic-gate   "Search for the filename FILENAME in all of partitions and print the list of"
17707c478bd9Sstevel@tonic-gate   " the devices which contain the file."
17717c478bd9Sstevel@tonic-gate };
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate /* fstest */
17757c478bd9Sstevel@tonic-gate static int
17767c478bd9Sstevel@tonic-gate fstest_func (char *arg, int flags)
17777c478bd9Sstevel@tonic-gate {
17787c478bd9Sstevel@tonic-gate   if (disk_read_hook)
17797c478bd9Sstevel@tonic-gate     {
17807c478bd9Sstevel@tonic-gate       disk_read_hook = NULL;
17817c478bd9Sstevel@tonic-gate       printf (" Filesystem tracing is now off\n");
17827c478bd9Sstevel@tonic-gate     }
17837c478bd9Sstevel@tonic-gate   else
17847c478bd9Sstevel@tonic-gate     {
17857c478bd9Sstevel@tonic-gate       disk_read_hook = disk_read_print_func;
17867c478bd9Sstevel@tonic-gate       printf (" Filesystem tracing is now on\n");
17877c478bd9Sstevel@tonic-gate     }
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate   return 0;
17907c478bd9Sstevel@tonic-gate }
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate static struct builtin builtin_fstest =
17937c478bd9Sstevel@tonic-gate {
17947c478bd9Sstevel@tonic-gate   "fstest",
17957c478bd9Sstevel@tonic-gate   fstest_func,
17967c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
17977c478bd9Sstevel@tonic-gate   "fstest",
17987c478bd9Sstevel@tonic-gate   "Toggle filesystem test mode."
17997c478bd9Sstevel@tonic-gate };
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate /* geometry */
18037c478bd9Sstevel@tonic-gate static int
18047c478bd9Sstevel@tonic-gate geometry_func (char *arg, int flags)
18057c478bd9Sstevel@tonic-gate {
18067c478bd9Sstevel@tonic-gate   struct geometry geom;
18077c478bd9Sstevel@tonic-gate   char *msg;
18087c478bd9Sstevel@tonic-gate   char *device = arg;
18097c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
18107c478bd9Sstevel@tonic-gate   char *ptr;
18117c478bd9Sstevel@tonic-gate #endif
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate   /* Get the device number.  */
18147c478bd9Sstevel@tonic-gate   set_device (device);
18157c478bd9Sstevel@tonic-gate   if (errnum)
18167c478bd9Sstevel@tonic-gate     return 1;
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate   /* Check for the geometry.  */
18197c478bd9Sstevel@tonic-gate   if (get_diskinfo (current_drive, &geom))
18207c478bd9Sstevel@tonic-gate     {
18217c478bd9Sstevel@tonic-gate       errnum = ERR_NO_DISK;
18227c478bd9Sstevel@tonic-gate       return 1;
18237c478bd9Sstevel@tonic-gate     }
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate   /* Attempt to read the first sector, because some BIOSes turns out not
18267c478bd9Sstevel@tonic-gate      to support LBA even though they set the bit 0 in the support
18277c478bd9Sstevel@tonic-gate      bitmap, only after reading something actually.  */
18287c478bd9Sstevel@tonic-gate   if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
18297c478bd9Sstevel@tonic-gate     {
18307c478bd9Sstevel@tonic-gate       errnum = ERR_READ;
18317c478bd9Sstevel@tonic-gate       return 1;
18327c478bd9Sstevel@tonic-gate     }
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
18357c478bd9Sstevel@tonic-gate   ptr = skip_to (0, device);
18367c478bd9Sstevel@tonic-gate   if (*ptr)
18377c478bd9Sstevel@tonic-gate     {
18387c478bd9Sstevel@tonic-gate       char *cylinder, *head, *sector, *total_sector;
18397c478bd9Sstevel@tonic-gate       int num_cylinder, num_head, num_sector, num_total_sector;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate       cylinder = ptr;
18427c478bd9Sstevel@tonic-gate       head = skip_to (0, cylinder);
18437c478bd9Sstevel@tonic-gate       sector = skip_to (0, head);
18447c478bd9Sstevel@tonic-gate       total_sector = skip_to (0, sector);
18457c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&cylinder, &num_cylinder)
18467c478bd9Sstevel@tonic-gate 	  || ! safe_parse_maxint (&head, &num_head)
18477c478bd9Sstevel@tonic-gate 	  || ! safe_parse_maxint (&sector, &num_sector))
18487c478bd9Sstevel@tonic-gate 	return 1;
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate       disks[current_drive].cylinders = num_cylinder;
18517c478bd9Sstevel@tonic-gate       disks[current_drive].heads = num_head;
18527c478bd9Sstevel@tonic-gate       disks[current_drive].sectors = num_sector;
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate       if (safe_parse_maxint (&total_sector, &num_total_sector))
18557c478bd9Sstevel@tonic-gate 	disks[current_drive].total_sectors = num_total_sector;
18567c478bd9Sstevel@tonic-gate       else
18577c478bd9Sstevel@tonic-gate 	disks[current_drive].total_sectors
18587c478bd9Sstevel@tonic-gate 	  = num_cylinder * num_head * num_sector;
18597c478bd9Sstevel@tonic-gate       errnum = 0;
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate       geom = disks[current_drive];
18627c478bd9Sstevel@tonic-gate       buf_drive = -1;
18637c478bd9Sstevel@tonic-gate     }
18647c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
18677c478bd9Sstevel@tonic-gate   msg = device_map[current_drive];
18687c478bd9Sstevel@tonic-gate #else
18697c478bd9Sstevel@tonic-gate   if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)
18707c478bd9Sstevel@tonic-gate     msg = "LBA";
18717c478bd9Sstevel@tonic-gate   else
18727c478bd9Sstevel@tonic-gate     msg = "CHS";
18737c478bd9Sstevel@tonic-gate #endif
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate   grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, "
1876342440ecSPrasad Singamsetty 	       "The number of sectors = %u, %s\n",
18777c478bd9Sstevel@tonic-gate 	       current_drive,
18787c478bd9Sstevel@tonic-gate 	       geom.cylinders, geom.heads, geom.sectors,
18797c478bd9Sstevel@tonic-gate 	       geom.total_sectors, msg);
18807c478bd9Sstevel@tonic-gate   real_open_partition (1);
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate   return 0;
18837c478bd9Sstevel@tonic-gate }
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate static struct builtin builtin_geometry =
18867c478bd9Sstevel@tonic-gate {
18877c478bd9Sstevel@tonic-gate   "geometry",
18887c478bd9Sstevel@tonic-gate   geometry_func,
18897c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
18907c478bd9Sstevel@tonic-gate   "geometry DRIVE [CYLINDER HEAD SECTOR [TOTAL_SECTOR]]",
18917c478bd9Sstevel@tonic-gate   "Print the information for a drive DRIVE. In the grub shell, you can"
18927c478bd9Sstevel@tonic-gate   " set the geometry of the drive arbitrarily. The number of the cylinders,"
18937c478bd9Sstevel@tonic-gate   " the one of the heads, the one of the sectors and the one of the total"
18947c478bd9Sstevel@tonic-gate   " sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR,"
18957c478bd9Sstevel@tonic-gate   " respectively. If you omit TOTAL_SECTOR, then it will be calculated based"
18967c478bd9Sstevel@tonic-gate   " on the C/H/S values automatically."
18977c478bd9Sstevel@tonic-gate };
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate /* halt */
19017c478bd9Sstevel@tonic-gate static int
19027c478bd9Sstevel@tonic-gate halt_func (char *arg, int flags)
19037c478bd9Sstevel@tonic-gate {
19047c478bd9Sstevel@tonic-gate   int no_apm;
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate   no_apm = (grub_memcmp (arg, "--no-apm", 8) == 0);
19077c478bd9Sstevel@tonic-gate   grub_halt (no_apm);
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate   /* Never reach here.  */
19107c478bd9Sstevel@tonic-gate   return 1;
19117c478bd9Sstevel@tonic-gate }
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate static struct builtin builtin_halt =
19147c478bd9Sstevel@tonic-gate {
19157c478bd9Sstevel@tonic-gate   "halt",
19167c478bd9Sstevel@tonic-gate   halt_func,
19177c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
19187c478bd9Sstevel@tonic-gate   "halt [--no-apm]",
19197c478bd9Sstevel@tonic-gate   "Halt your system. If APM is avaiable on it, turn off the power using"
19207c478bd9Sstevel@tonic-gate   " the APM BIOS, unless you specify the option `--no-apm'."
19217c478bd9Sstevel@tonic-gate };
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate /* help */
19257c478bd9Sstevel@tonic-gate #define MAX_SHORT_DOC_LEN	39
19267c478bd9Sstevel@tonic-gate #define MAX_LONG_DOC_LEN	66
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate static int
19297c478bd9Sstevel@tonic-gate help_func (char *arg, int flags)
19307c478bd9Sstevel@tonic-gate {
19317c478bd9Sstevel@tonic-gate   int all = 0;
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0)
19347c478bd9Sstevel@tonic-gate     {
19357c478bd9Sstevel@tonic-gate       all = 1;
19367c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
19377c478bd9Sstevel@tonic-gate     }
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate   if (! *arg)
19407c478bd9Sstevel@tonic-gate     {
19417c478bd9Sstevel@tonic-gate       /* Invoked with no argument. Print the list of the short docs.  */
19427c478bd9Sstevel@tonic-gate       struct builtin **builtin;
19437c478bd9Sstevel@tonic-gate       int left = 1;
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate       for (builtin = builtin_table; *builtin != 0; builtin++)
19467c478bd9Sstevel@tonic-gate 	{
19477c478bd9Sstevel@tonic-gate 	  int len;
19487c478bd9Sstevel@tonic-gate 	  int i;
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	  /* If this cannot be used in the command-line interface,
19517c478bd9Sstevel@tonic-gate 	     skip this.  */
19527c478bd9Sstevel@tonic-gate 	  if (! ((*builtin)->flags & BUILTIN_CMDLINE))
19537c478bd9Sstevel@tonic-gate 	    continue;
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	  /* If this doesn't need to be listed automatically and "--all"
19567c478bd9Sstevel@tonic-gate 	     is not specified, skip this.  */
19577c478bd9Sstevel@tonic-gate 	  if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST))
19587c478bd9Sstevel@tonic-gate 	    continue;
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate 	  len = grub_strlen ((*builtin)->short_doc);
19617c478bd9Sstevel@tonic-gate 	  /* If the length of SHORT_DOC is too long, truncate it.  */
19627c478bd9Sstevel@tonic-gate 	  if (len > MAX_SHORT_DOC_LEN - 1)
19637c478bd9Sstevel@tonic-gate 	    len = MAX_SHORT_DOC_LEN - 1;
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	  for (i = 0; i < len; i++)
19667c478bd9Sstevel@tonic-gate 	    grub_putchar ((*builtin)->short_doc[i]);
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 	  for (; i < MAX_SHORT_DOC_LEN; i++)
19697c478bd9Sstevel@tonic-gate 	    grub_putchar (' ');
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	  if (! left)
19727c478bd9Sstevel@tonic-gate 	    grub_putchar ('\n');
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	  left = ! left;
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 
19777c478bd9Sstevel@tonic-gate       /* If the last entry was at the left column, no newline was printed
19787c478bd9Sstevel@tonic-gate 	 at the end.  */
19797c478bd9Sstevel@tonic-gate       if (! left)
19807c478bd9Sstevel@tonic-gate 	grub_putchar ('\n');
19817c478bd9Sstevel@tonic-gate     }
19827c478bd9Sstevel@tonic-gate   else
19837c478bd9Sstevel@tonic-gate     {
19847c478bd9Sstevel@tonic-gate       /* Invoked with one or more patterns.  */
19857c478bd9Sstevel@tonic-gate       do
19867c478bd9Sstevel@tonic-gate 	{
19877c478bd9Sstevel@tonic-gate 	  struct builtin **builtin;
19887c478bd9Sstevel@tonic-gate 	  char *next_arg;
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 	  /* Get the next argument.  */
19917c478bd9Sstevel@tonic-gate 	  next_arg = skip_to (0, arg);
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	  /* Terminate ARG.  */
19947c478bd9Sstevel@tonic-gate 	  nul_terminate (arg);
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	  for (builtin = builtin_table; *builtin; builtin++)
19977c478bd9Sstevel@tonic-gate 	    {
19987c478bd9Sstevel@tonic-gate 	      /* Skip this if this is only for the configuration file.  */
19997c478bd9Sstevel@tonic-gate 	      if (! ((*builtin)->flags & BUILTIN_CMDLINE))
20007c478bd9Sstevel@tonic-gate 		continue;
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 	      if (substring (arg, (*builtin)->name) < 1)
20037c478bd9Sstevel@tonic-gate 		{
20047c478bd9Sstevel@tonic-gate 		  char *doc = (*builtin)->long_doc;
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 		  /* At first, print the name and the short doc.  */
20077c478bd9Sstevel@tonic-gate 		  grub_printf ("%s: %s\n",
20087c478bd9Sstevel@tonic-gate 			       (*builtin)->name, (*builtin)->short_doc);
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 		  /* Print the long doc.  */
20117c478bd9Sstevel@tonic-gate 		  while (*doc)
20127c478bd9Sstevel@tonic-gate 		    {
20137c478bd9Sstevel@tonic-gate 		      int len = grub_strlen (doc);
20147c478bd9Sstevel@tonic-gate 		      int i;
20157c478bd9Sstevel@tonic-gate 
20167c478bd9Sstevel@tonic-gate 		      /* If LEN is too long, fold DOC.  */
20177c478bd9Sstevel@tonic-gate 		      if (len > MAX_LONG_DOC_LEN)
20187c478bd9Sstevel@tonic-gate 			{
20197c478bd9Sstevel@tonic-gate 			  /* Fold this line at the position of a space.  */
20207c478bd9Sstevel@tonic-gate 			  for (len = MAX_LONG_DOC_LEN; len > 0; len--)
20217c478bd9Sstevel@tonic-gate 			    if (doc[len - 1] == ' ')
20227c478bd9Sstevel@tonic-gate 			      break;
20237c478bd9Sstevel@tonic-gate 			}
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 		      grub_printf ("    ");
20267c478bd9Sstevel@tonic-gate 		      for (i = 0; i < len; i++)
20277c478bd9Sstevel@tonic-gate 			grub_putchar (*doc++);
20287c478bd9Sstevel@tonic-gate 		      grub_putchar ('\n');
20297c478bd9Sstevel@tonic-gate 		    }
20307c478bd9Sstevel@tonic-gate 		}
20317c478bd9Sstevel@tonic-gate 	    }
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	  arg = next_arg;
20347c478bd9Sstevel@tonic-gate 	}
20357c478bd9Sstevel@tonic-gate       while (*arg);
20367c478bd9Sstevel@tonic-gate     }
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate   return 0;
20397c478bd9Sstevel@tonic-gate }
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate static struct builtin builtin_help =
20427c478bd9Sstevel@tonic-gate {
20437c478bd9Sstevel@tonic-gate   "help",
20447c478bd9Sstevel@tonic-gate   help_func,
20457c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
20467c478bd9Sstevel@tonic-gate   "help [--all] [PATTERN ...]",
20477c478bd9Sstevel@tonic-gate   "Display helpful information about builtin commands. Not all commands"
20487c478bd9Sstevel@tonic-gate   " aren't shown without the option `--all'."
20497c478bd9Sstevel@tonic-gate };
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate /* hiddenmenu */
20537c478bd9Sstevel@tonic-gate static int
20547c478bd9Sstevel@tonic-gate hiddenmenu_func (char *arg, int flags)
20557c478bd9Sstevel@tonic-gate {
20567c478bd9Sstevel@tonic-gate   show_menu = 0;
20577c478bd9Sstevel@tonic-gate   return 0;
20587c478bd9Sstevel@tonic-gate }
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate static struct builtin builtin_hiddenmenu =
20617c478bd9Sstevel@tonic-gate {
20627c478bd9Sstevel@tonic-gate   "hiddenmenu",
20637c478bd9Sstevel@tonic-gate   hiddenmenu_func,
20647c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
20657c478bd9Sstevel@tonic-gate #if 0
20667c478bd9Sstevel@tonic-gate   "hiddenmenu",
20677c478bd9Sstevel@tonic-gate   "Hide the menu."
20687c478bd9Sstevel@tonic-gate #endif
20697c478bd9Sstevel@tonic-gate };
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate /* hide */
20737c478bd9Sstevel@tonic-gate static int
20747c478bd9Sstevel@tonic-gate hide_func (char *arg, int flags)
20757c478bd9Sstevel@tonic-gate {
20767c478bd9Sstevel@tonic-gate   if (! set_device (arg))
20777c478bd9Sstevel@tonic-gate     return 1;
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate   if (! set_partition_hidden_flag (1))
20807c478bd9Sstevel@tonic-gate     return 1;
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate   return 0;
20837c478bd9Sstevel@tonic-gate }
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate static struct builtin builtin_hide =
20867c478bd9Sstevel@tonic-gate {
20877c478bd9Sstevel@tonic-gate   "hide",
20887c478bd9Sstevel@tonic-gate   hide_func,
20897c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
20907c478bd9Sstevel@tonic-gate   "hide PARTITION",
20917c478bd9Sstevel@tonic-gate   "Hide PARTITION by setting the \"hidden\" bit in"
20927c478bd9Sstevel@tonic-gate   " its partition type code."
20937c478bd9Sstevel@tonic-gate };
20947c478bd9Sstevel@tonic-gate 
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
20977c478bd9Sstevel@tonic-gate /* ifconfig */
20987c478bd9Sstevel@tonic-gate static int
20997c478bd9Sstevel@tonic-gate ifconfig_func (char *arg, int flags)
21007c478bd9Sstevel@tonic-gate {
21017c478bd9Sstevel@tonic-gate   char *svr = 0, *ip = 0, *gw = 0, *sm = 0;
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate   if (! grub_eth_probe ())
21047c478bd9Sstevel@tonic-gate     {
21057c478bd9Sstevel@tonic-gate       grub_printf ("No ethernet card found.\n");
21067c478bd9Sstevel@tonic-gate       errnum = ERR_DEV_VALUES;
21077c478bd9Sstevel@tonic-gate       return 1;
21087c478bd9Sstevel@tonic-gate     }
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate   while (*arg)
21117c478bd9Sstevel@tonic-gate     {
21127c478bd9Sstevel@tonic-gate       if (! grub_memcmp ("--server=", arg, sizeof ("--server=") - 1))
21137c478bd9Sstevel@tonic-gate 	svr = arg + sizeof("--server=") - 1;
21147c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--address=", arg, sizeof ("--address=") - 1))
21157c478bd9Sstevel@tonic-gate 	ip = arg + sizeof ("--address=") - 1;
21167c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--gateway=", arg, sizeof ("--gateway=") - 1))
21177c478bd9Sstevel@tonic-gate 	gw = arg + sizeof ("--gateway=") - 1;
21187c478bd9Sstevel@tonic-gate       else if (! grub_memcmp ("--mask=", arg, sizeof("--mask=") - 1))
21197c478bd9Sstevel@tonic-gate 	sm = arg + sizeof ("--mask=") - 1;
21207c478bd9Sstevel@tonic-gate       else
21217c478bd9Sstevel@tonic-gate 	{
21227c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
21237c478bd9Sstevel@tonic-gate 	  return 1;
21247c478bd9Sstevel@tonic-gate 	}
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
21277c478bd9Sstevel@tonic-gate     }
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate   if (! ifconfig (ip, sm, gw, svr))
21307c478bd9Sstevel@tonic-gate     {
21317c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
21327c478bd9Sstevel@tonic-gate       return 1;
21337c478bd9Sstevel@tonic-gate     }
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate   print_network_configuration ();
21367c478bd9Sstevel@tonic-gate   return 0;
21377c478bd9Sstevel@tonic-gate }
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate static struct builtin builtin_ifconfig =
21407c478bd9Sstevel@tonic-gate {
21417c478bd9Sstevel@tonic-gate   "ifconfig",
21427c478bd9Sstevel@tonic-gate   ifconfig_func,
21437c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
21447c478bd9Sstevel@tonic-gate   "ifconfig [--address=IP] [--gateway=IP] [--mask=MASK] [--server=IP]",
21457c478bd9Sstevel@tonic-gate   "Configure the IP address, the netmask, the gateway and the server"
21467c478bd9Sstevel@tonic-gate   " address or print current network configuration."
21477c478bd9Sstevel@tonic-gate };
21487c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate /* impsprobe */
21527c478bd9Sstevel@tonic-gate static int
21537c478bd9Sstevel@tonic-gate impsprobe_func (char *arg, int flags)
21547c478bd9Sstevel@tonic-gate {
21557c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
21567c478bd9Sstevel@tonic-gate   /* In the grub shell, we cannot probe IMPS.  */
21577c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
21587c478bd9Sstevel@tonic-gate   return 1;
21597c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
21607c478bd9Sstevel@tonic-gate   if (!imps_probe ())
21617c478bd9Sstevel@tonic-gate     printf (" No MPS information found or probe failed\n");
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate   return 0;
21647c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
21657c478bd9Sstevel@tonic-gate }
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate static struct builtin builtin_impsprobe =
21687c478bd9Sstevel@tonic-gate {
21697c478bd9Sstevel@tonic-gate   "impsprobe",
21707c478bd9Sstevel@tonic-gate   impsprobe_func,
21717c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
21727c478bd9Sstevel@tonic-gate   "impsprobe",
21737c478bd9Sstevel@tonic-gate   "Probe the Intel Multiprocessor Specification 1.1 or 1.4"
21747c478bd9Sstevel@tonic-gate   " configuration table and boot the various CPUs which are found into"
21757c478bd9Sstevel@tonic-gate   " a tight loop."
21767c478bd9Sstevel@tonic-gate };
21777c478bd9Sstevel@tonic-gate 
21787ce76caaSEnrico Perla - Sun Microsystems /* extended info */
21797ce76caaSEnrico Perla - Sun Microsystems static int
21807ce76caaSEnrico Perla - Sun Microsystems info_func (char *arg, int flags)
21817ce76caaSEnrico Perla - Sun Microsystems {
21827ce76caaSEnrico Perla - Sun Microsystems   int  i;
21837ce76caaSEnrico Perla - Sun Microsystems 
21847ce76caaSEnrico Perla - Sun Microsystems   grub_printf("Extended version information : %s\n", pkg_version);
21857ce76caaSEnrico Perla - Sun Microsystems   grub_printf("stage2 (MD5) signature : ");
21867ce76caaSEnrico Perla - Sun Microsystems 
21877ce76caaSEnrico Perla - Sun Microsystems   for (i = 0; i < 0x10; i++)
21887ce76caaSEnrico Perla - Sun Microsystems     grub_printf("%x", md5hash[i]);
21897ce76caaSEnrico Perla - Sun Microsystems 
21907ce76caaSEnrico Perla - Sun Microsystems   grub_printf("\n");
21917ce76caaSEnrico Perla - Sun Microsystems }
21927ce76caaSEnrico Perla - Sun Microsystems 
21937ce76caaSEnrico Perla - Sun Microsystems static struct builtin builtin_info =
21947ce76caaSEnrico Perla - Sun Microsystems {
21957ce76caaSEnrico Perla - Sun Microsystems   "info",
21967ce76caaSEnrico Perla - Sun Microsystems   info_func,
21977ce76caaSEnrico Perla - Sun Microsystems   BUILTIN_CMDLINE | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
21987ce76caaSEnrico Perla - Sun Microsystems   "info",
21997ce76caaSEnrico Perla - Sun Microsystems   "Read Grub extended version and stage2 MD5 hash"
22007ce76caaSEnrico Perla - Sun Microsystems };
22017ce76caaSEnrico Perla - Sun Microsystems 
22027ce76caaSEnrico Perla - Sun Microsystems 
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate /* initrd */
22057c478bd9Sstevel@tonic-gate static int
22067c478bd9Sstevel@tonic-gate initrd_func (char *arg, int flags)
22077c478bd9Sstevel@tonic-gate {
22087c478bd9Sstevel@tonic-gate   switch (kernel_type)
22097c478bd9Sstevel@tonic-gate     {
22107c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
22117c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
22127c478bd9Sstevel@tonic-gate       if (! load_initrd (arg))
22137c478bd9Sstevel@tonic-gate 	return 1;
22147c478bd9Sstevel@tonic-gate       break;
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate     default:
22177c478bd9Sstevel@tonic-gate       errnum = ERR_NEED_LX_KERNEL;
22187c478bd9Sstevel@tonic-gate       return 1;
22197c478bd9Sstevel@tonic-gate     }
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate   return 0;
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate static struct builtin builtin_initrd =
22257c478bd9Sstevel@tonic-gate {
22267c478bd9Sstevel@tonic-gate   "initrd",
22277c478bd9Sstevel@tonic-gate   initrd_func,
22287c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
22297c478bd9Sstevel@tonic-gate   "initrd FILE [ARG ...]",
22307c478bd9Sstevel@tonic-gate   "Load an initial ramdisk FILE for a Linux format boot image and set the"
22317c478bd9Sstevel@tonic-gate   " appropriate parameters in the Linux setup area in memory."
22327c478bd9Sstevel@tonic-gate };
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate /* install */
22367c478bd9Sstevel@tonic-gate static int
22377c478bd9Sstevel@tonic-gate install_func (char *arg, int flags)
22387c478bd9Sstevel@tonic-gate {
22397c478bd9Sstevel@tonic-gate   char *stage1_file, *dest_dev, *file, *addr;
22407c478bd9Sstevel@tonic-gate   char *stage1_buffer = (char *) RAW_ADDR (0x100000);
22417c478bd9Sstevel@tonic-gate   char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
22427c478bd9Sstevel@tonic-gate   char *old_sect = stage2_buffer + SECTOR_SIZE;
22437c478bd9Sstevel@tonic-gate   char *stage2_first_buffer = old_sect + SECTOR_SIZE;
22447c478bd9Sstevel@tonic-gate   char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
22457c478bd9Sstevel@tonic-gate   /* XXX: Probably SECTOR_SIZE is reasonable.  */
22467c478bd9Sstevel@tonic-gate   char *config_filename = stage2_second_buffer + SECTOR_SIZE;
22477c478bd9Sstevel@tonic-gate   char *dummy = config_filename + SECTOR_SIZE;
22487c478bd9Sstevel@tonic-gate   int new_drive = GRUB_INVALID_DRIVE;
2249342440ecSPrasad Singamsetty   int dest_drive, dest_partition;
2250342440ecSPrasad Singamsetty   unsigned int dest_sector;
22517c478bd9Sstevel@tonic-gate   int src_drive, src_partition, src_part_start;
22527c478bd9Sstevel@tonic-gate   int i;
22537c478bd9Sstevel@tonic-gate   struct geometry dest_geom, src_geom;
2254342440ecSPrasad Singamsetty   unsigned int saved_sector;
2255342440ecSPrasad Singamsetty   unsigned int stage2_first_sector, stage2_second_sector;
22567c478bd9Sstevel@tonic-gate   char *ptr;
22577c478bd9Sstevel@tonic-gate   int installaddr, installlist;
22587c478bd9Sstevel@tonic-gate   /* Point to the location of the name of a configuration file in Stage 2.  */
22597c478bd9Sstevel@tonic-gate   char *config_file_location;
22607c478bd9Sstevel@tonic-gate   /* If FILE is a Stage 1.5?  */
22617c478bd9Sstevel@tonic-gate   int is_stage1_5 = 0;
22627c478bd9Sstevel@tonic-gate   /* Must call grub_close?  */
22637c478bd9Sstevel@tonic-gate   int is_open = 0;
22647c478bd9Sstevel@tonic-gate   /* If LBA is forced?  */
22657c478bd9Sstevel@tonic-gate   int is_force_lba = 0;
22667c478bd9Sstevel@tonic-gate   /* Was the last sector full? */
22677c478bd9Sstevel@tonic-gate   int last_length = SECTOR_SIZE;
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
22707c478bd9Sstevel@tonic-gate   /* If the Stage 2 is in a partition mounted by an OS, this will store
22717c478bd9Sstevel@tonic-gate      the filename under the OS.  */
22727c478bd9Sstevel@tonic-gate   char *stage2_os_file = 0;
22737c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
22747c478bd9Sstevel@tonic-gate 
22751b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
22761b8adde7SWilliam Kucharski       int length);
22771b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
22781b8adde7SWilliam Kucharski       int length);
22791b8adde7SWilliam Kucharski 
22807c478bd9Sstevel@tonic-gate   /* Save the first sector of Stage2 in STAGE2_SECT.  */
22811b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
22821b8adde7SWilliam Kucharski       int length)
22837c478bd9Sstevel@tonic-gate     {
22847c478bd9Sstevel@tonic-gate       if (debug)
2285342440ecSPrasad Singamsetty 	printf ("[%u]", sector);
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate       /* ReiserFS has files which sometimes contain data not aligned
22887c478bd9Sstevel@tonic-gate          on sector boundaries.  Returning an error is better than
22897c478bd9Sstevel@tonic-gate          silently failing. */
22907c478bd9Sstevel@tonic-gate       if (offset != 0 || length != SECTOR_SIZE)
22917c478bd9Sstevel@tonic-gate 	errnum = ERR_UNALIGNED;
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate       saved_sector = sector;
22947c478bd9Sstevel@tonic-gate     }
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate   /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
22977c478bd9Sstevel@tonic-gate      INSTALLSECT.  */
22981b8adde7SWilliam Kucharski   auto void disk_read_blocklist_func (unsigned int sector, int offset,
22991b8adde7SWilliam Kucharski       int length)
23007c478bd9Sstevel@tonic-gate     {
23017c478bd9Sstevel@tonic-gate       if (debug)
2302342440ecSPrasad Singamsetty 	printf("[%u]", sector);
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate       if (offset != 0 || last_length != SECTOR_SIZE)
23057c478bd9Sstevel@tonic-gate 	{
23067c478bd9Sstevel@tonic-gate 	  /* We found a non-sector-aligned data block. */
23077c478bd9Sstevel@tonic-gate 	  errnum = ERR_UNALIGNED;
23087c478bd9Sstevel@tonic-gate 	  return;
23097c478bd9Sstevel@tonic-gate 	}
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate       last_length = length;
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate       if (*((unsigned long *) (installlist - 4))
23147c478bd9Sstevel@tonic-gate 	  + *((unsigned short *) installlist) != sector
23157c478bd9Sstevel@tonic-gate 	  || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
23167c478bd9Sstevel@tonic-gate 	{
23177c478bd9Sstevel@tonic-gate 	  installlist -= 8;
23187c478bd9Sstevel@tonic-gate 
23197c478bd9Sstevel@tonic-gate 	  if (*((unsigned long *) (installlist - 8)))
23207c478bd9Sstevel@tonic-gate 	    errnum = ERR_WONT_FIT;
23217c478bd9Sstevel@tonic-gate 	  else
23227c478bd9Sstevel@tonic-gate 	    {
23237c478bd9Sstevel@tonic-gate 	      *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
23247c478bd9Sstevel@tonic-gate 	      *((unsigned long *) (installlist - 4)) = sector;
23257c478bd9Sstevel@tonic-gate 	    }
23267c478bd9Sstevel@tonic-gate 	}
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate       *((unsigned short *) installlist) += 1;
23297c478bd9Sstevel@tonic-gate       installaddr += 512;
23307c478bd9Sstevel@tonic-gate     }
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate   /* First, check the GNU-style long option.  */
23337c478bd9Sstevel@tonic-gate   while (1)
23347c478bd9Sstevel@tonic-gate     {
23357c478bd9Sstevel@tonic-gate       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
23367c478bd9Sstevel@tonic-gate 	{
23377c478bd9Sstevel@tonic-gate 	  is_force_lba = 1;
23387c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
23397c478bd9Sstevel@tonic-gate 	}
23407c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
23417c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
23427c478bd9Sstevel@tonic-gate 	{
23437c478bd9Sstevel@tonic-gate 	  stage2_os_file = arg + sizeof ("--stage2=") - 1;
23447c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
23457c478bd9Sstevel@tonic-gate 	  nul_terminate (stage2_os_file);
23467c478bd9Sstevel@tonic-gate 	}
23477c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
23487c478bd9Sstevel@tonic-gate       else
23497c478bd9Sstevel@tonic-gate 	break;
23507c478bd9Sstevel@tonic-gate     }
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate   stage1_file = arg;
23537c478bd9Sstevel@tonic-gate   dest_dev = skip_to (0, stage1_file);
23547c478bd9Sstevel@tonic-gate   if (*dest_dev == 'd')
23557c478bd9Sstevel@tonic-gate     {
23567c478bd9Sstevel@tonic-gate       new_drive = 0;
23577c478bd9Sstevel@tonic-gate       dest_dev = skip_to (0, dest_dev);
23587c478bd9Sstevel@tonic-gate     }
23597c478bd9Sstevel@tonic-gate   file = skip_to (0, dest_dev);
23607c478bd9Sstevel@tonic-gate   addr = skip_to (0, file);
23617c478bd9Sstevel@tonic-gate 
23627c478bd9Sstevel@tonic-gate   /* Get the installation address.  */
23637c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&addr, &installaddr))
23647c478bd9Sstevel@tonic-gate     {
23657c478bd9Sstevel@tonic-gate       /* ADDR is not specified.  */
23667c478bd9Sstevel@tonic-gate       installaddr = 0;
23677c478bd9Sstevel@tonic-gate       ptr = addr;
23687c478bd9Sstevel@tonic-gate       errnum = 0;
23697c478bd9Sstevel@tonic-gate     }
23707c478bd9Sstevel@tonic-gate   else
23717c478bd9Sstevel@tonic-gate     ptr = skip_to (0, addr);
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
23747c478bd9Sstevel@tonic-gate   /* Do not decompress Stage 1 or Stage 2.  */
23757c478bd9Sstevel@tonic-gate   no_decompression = 1;
23767c478bd9Sstevel@tonic-gate #endif
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate   /* Read Stage 1.  */
23797c478bd9Sstevel@tonic-gate   is_open = grub_open (stage1_file);
23807c478bd9Sstevel@tonic-gate   if (! is_open
23817c478bd9Sstevel@tonic-gate       || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE)
23827c478bd9Sstevel@tonic-gate     goto fail;
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate   /* Read the old sector from DEST_DEV.  */
23857c478bd9Sstevel@tonic-gate   if (! set_device (dest_dev)
23867c478bd9Sstevel@tonic-gate       || ! open_partition ()
23877c478bd9Sstevel@tonic-gate       || ! devread (0, 0, SECTOR_SIZE, old_sect))
23887c478bd9Sstevel@tonic-gate     goto fail;
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate   /* Store the information for the destination device.  */
23917c478bd9Sstevel@tonic-gate   dest_drive = current_drive;
23927c478bd9Sstevel@tonic-gate   dest_partition = current_partition;
23937c478bd9Sstevel@tonic-gate   dest_geom = buf_geom;
23947c478bd9Sstevel@tonic-gate   dest_sector = part_start;
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate   /* Copy the possible DOS BPB, 59 bytes at byte offset 3.  */
23977c478bd9Sstevel@tonic-gate   grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET,
23987c478bd9Sstevel@tonic-gate 		old_sect + BOOTSEC_BPB_OFFSET,
23997c478bd9Sstevel@tonic-gate 		BOOTSEC_BPB_LENGTH);
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate   /* If for a hard disk, copy the possible MBR/extended part table.  */
24027c478bd9Sstevel@tonic-gate   if (dest_drive & 0x80)
24037c478bd9Sstevel@tonic-gate     grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC,
24047c478bd9Sstevel@tonic-gate 		  old_sect + STAGE1_WINDOWS_NT_MAGIC,
24057c478bd9Sstevel@tonic-gate 		  STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC);
24067c478bd9Sstevel@tonic-gate 
24077c478bd9Sstevel@tonic-gate   /* Check for the version and the signature of Stage 1.  */
24087c478bd9Sstevel@tonic-gate   if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
24097c478bd9Sstevel@tonic-gate       || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET))
24107c478bd9Sstevel@tonic-gate 	  != BOOTSEC_SIGNATURE))
24117c478bd9Sstevel@tonic-gate     {
24127c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
24137c478bd9Sstevel@tonic-gate       goto fail;
24147c478bd9Sstevel@tonic-gate     }
24157c478bd9Sstevel@tonic-gate 
24167c478bd9Sstevel@tonic-gate   /* This below is not true any longer. But should we leave this alone?  */
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate   /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe
24197c478bd9Sstevel@tonic-gate      routine.  */
24207c478bd9Sstevel@tonic-gate   if (! (dest_drive & 0x80)
24217c478bd9Sstevel@tonic-gate       && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80
24227c478bd9Sstevel@tonic-gate 	  || stage1_buffer[BOOTSEC_PART_OFFSET] == 0))
24237c478bd9Sstevel@tonic-gate     {
24247c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
24257c478bd9Sstevel@tonic-gate       goto fail;
24267c478bd9Sstevel@tonic-gate     }
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate   grub_close ();
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate   /* Open Stage 2.  */
24317c478bd9Sstevel@tonic-gate   is_open = grub_open (file);
24327c478bd9Sstevel@tonic-gate   if (! is_open)
24337c478bd9Sstevel@tonic-gate     goto fail;
24347c478bd9Sstevel@tonic-gate 
24357c478bd9Sstevel@tonic-gate   src_drive = current_drive;
24367c478bd9Sstevel@tonic-gate   src_partition = current_partition;
24377c478bd9Sstevel@tonic-gate   src_part_start = part_start;
24387c478bd9Sstevel@tonic-gate   src_geom = buf_geom;
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate   if (! new_drive)
24417c478bd9Sstevel@tonic-gate     new_drive = src_drive;
24427c478bd9Sstevel@tonic-gate   else if (src_drive != dest_drive)
24437c478bd9Sstevel@tonic-gate     grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
24447c478bd9Sstevel@tonic-gate 		 " be installed on a\ndifferent drive than the drive where"
24457c478bd9Sstevel@tonic-gate 		 " the Stage 2 resides.\n");
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate   /* Set the boot drive.  */
24487c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate   /* Set the "force LBA" flag.  */
24517c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba;
24527c478bd9Sstevel@tonic-gate 
24531b8adde7SWilliam Kucharski   /* If DEST_DRIVE is a hard disk, enable the workaround, which is
24541b8adde7SWilliam Kucharski      for buggy BIOSes which don't pass boot drive correctly. Instead,
24551b8adde7SWilliam Kucharski      they pass 0x00 or 0x01 even when booted from 0x80.  */
24561b8adde7SWilliam Kucharski   if (dest_drive & BIOS_FLAG_FIXED_DISK)
24571b8adde7SWilliam Kucharski     /* Replace the jmp (2 bytes) with double nop's.  */
24581b8adde7SWilliam Kucharski     *((unsigned short *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK))
24591b8adde7SWilliam Kucharski       = 0x9090;
24601b8adde7SWilliam Kucharski 
24617c478bd9Sstevel@tonic-gate   /* Read the first sector of Stage 2.  */
24627c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_savesect_func;
24637c478bd9Sstevel@tonic-gate   if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
24647c478bd9Sstevel@tonic-gate     goto fail;
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate   stage2_first_sector = saved_sector;
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate   /* Read the second sector of Stage 2.  */
24697c478bd9Sstevel@tonic-gate   if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
24707c478bd9Sstevel@tonic-gate     goto fail;
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate   stage2_second_sector = saved_sector;
24737c478bd9Sstevel@tonic-gate 
24747c478bd9Sstevel@tonic-gate   /* Check for the version of Stage 2.  */
24757c478bd9Sstevel@tonic-gate   if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
24767c478bd9Sstevel@tonic-gate       != COMPAT_VERSION)
24777c478bd9Sstevel@tonic-gate     {
24787c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
24797c478bd9Sstevel@tonic-gate       goto fail;
24807c478bd9Sstevel@tonic-gate     }
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate   /* Check for the Stage 2 id.  */
24837c478bd9Sstevel@tonic-gate   if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2)
24847c478bd9Sstevel@tonic-gate     is_stage1_5 = 1;
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate   /* If INSTALLADDR is not specified explicitly in the command-line,
24877c478bd9Sstevel@tonic-gate      determine it by the Stage 2 id.  */
24887c478bd9Sstevel@tonic-gate   if (! installaddr)
24897c478bd9Sstevel@tonic-gate     {
24907c478bd9Sstevel@tonic-gate       if (! is_stage1_5)
24917c478bd9Sstevel@tonic-gate 	/* Stage 2.  */
24927c478bd9Sstevel@tonic-gate 	installaddr = 0x8000;
24937c478bd9Sstevel@tonic-gate       else
24947c478bd9Sstevel@tonic-gate 	/* Stage 1.5.  */
24957c478bd9Sstevel@tonic-gate 	installaddr = 0x2000;
24967c478bd9Sstevel@tonic-gate     }
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate   *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
24997c478bd9Sstevel@tonic-gate     = stage2_first_sector;
25007c478bd9Sstevel@tonic-gate   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
25017c478bd9Sstevel@tonic-gate     = installaddr;
25027c478bd9Sstevel@tonic-gate   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
25037c478bd9Sstevel@tonic-gate     = installaddr >> 4;
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate   i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
25067c478bd9Sstevel@tonic-gate   while (*((unsigned long *) i))
25077c478bd9Sstevel@tonic-gate     {
25087c478bd9Sstevel@tonic-gate       if (i < (int) stage2_first_buffer
25097c478bd9Sstevel@tonic-gate 	  || (*((int *) (i - 4)) & 0x80000000)
25107c478bd9Sstevel@tonic-gate 	  || *((unsigned short *) i) >= 0xA00
25117c478bd9Sstevel@tonic-gate 	  || *((short *) (i + 2)) == 0)
25127c478bd9Sstevel@tonic-gate 	{
25137c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_VERSION;
25147c478bd9Sstevel@tonic-gate 	  goto fail;
25157c478bd9Sstevel@tonic-gate 	}
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate       *((int *) i) = 0;
25187c478bd9Sstevel@tonic-gate       *((int *) (i - 4)) = 0;
25197c478bd9Sstevel@tonic-gate       i -= 8;
25207c478bd9Sstevel@tonic-gate     }
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate   installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
25237c478bd9Sstevel@tonic-gate   installaddr += SECTOR_SIZE;
25247c478bd9Sstevel@tonic-gate 
25257c478bd9Sstevel@tonic-gate   /* Read the whole of Stage2 except for the first sector.  */
25267c478bd9Sstevel@tonic-gate   grub_seek (SECTOR_SIZE);
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_blocklist_func;
25297c478bd9Sstevel@tonic-gate   if (! grub_read (dummy, -1))
25307c478bd9Sstevel@tonic-gate     goto fail;
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate   /* Find a string for the configuration filename.  */
25357c478bd9Sstevel@tonic-gate   config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS;
25367c478bd9Sstevel@tonic-gate   while (*(config_file_location++))
25377c478bd9Sstevel@tonic-gate     ;
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate   /* Set the "force LBA" flag for Stage2.  */
25407c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA))
25417c478bd9Sstevel@tonic-gate     = is_force_lba;
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate   if (*ptr == 'p')
25447c478bd9Sstevel@tonic-gate     {
25457c478bd9Sstevel@tonic-gate       *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
25467c478bd9Sstevel@tonic-gate 	= src_partition;
25477c478bd9Sstevel@tonic-gate       if (is_stage1_5)
25487c478bd9Sstevel@tonic-gate 	{
25497c478bd9Sstevel@tonic-gate 	  /* Reset the device information in FILE if it is a Stage 1.5.  */
25507c478bd9Sstevel@tonic-gate 	  unsigned long device = 0xFFFFFFFF;
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate 	  grub_memmove (config_file_location, (char *) &device,
25537c478bd9Sstevel@tonic-gate 			sizeof (device));
25547c478bd9Sstevel@tonic-gate 	}
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate       ptr = skip_to (0, ptr);
25577c478bd9Sstevel@tonic-gate     }
25587c478bd9Sstevel@tonic-gate 
25597c478bd9Sstevel@tonic-gate   if (*ptr)
25607c478bd9Sstevel@tonic-gate     {
25617c478bd9Sstevel@tonic-gate       grub_strcpy (config_filename, ptr);
25627c478bd9Sstevel@tonic-gate       nul_terminate (config_filename);
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate       if (! is_stage1_5)
25657c478bd9Sstevel@tonic-gate 	/* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION.  */
25667c478bd9Sstevel@tonic-gate 	grub_strcpy (config_file_location, ptr);
25677c478bd9Sstevel@tonic-gate       else
25687c478bd9Sstevel@tonic-gate 	{
25697c478bd9Sstevel@tonic-gate 	  char *real_config;
25707c478bd9Sstevel@tonic-gate 	  unsigned long device;
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	  /* Translate the external device syntax to the internal device
25737c478bd9Sstevel@tonic-gate 	     syntax.  */
25747c478bd9Sstevel@tonic-gate 	  if (! (real_config = set_device (ptr)))
25757c478bd9Sstevel@tonic-gate 	    {
25767c478bd9Sstevel@tonic-gate 	      /* The Stage 2 PTR does not contain the device name, so
25777c478bd9Sstevel@tonic-gate 		 use the root device instead.  */
25787c478bd9Sstevel@tonic-gate 	      errnum = ERR_NONE;
25797c478bd9Sstevel@tonic-gate 	      current_drive = saved_drive;
25807c478bd9Sstevel@tonic-gate 	      current_partition = saved_partition;
25817c478bd9Sstevel@tonic-gate 	      real_config = ptr;
25827c478bd9Sstevel@tonic-gate 	    }
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 	  if (current_drive == src_drive)
25857c478bd9Sstevel@tonic-gate 	    {
25867c478bd9Sstevel@tonic-gate 	      /* If the drive where the Stage 2 resides is the same as
25877c478bd9Sstevel@tonic-gate 		 the one where the Stage 1.5 resides, do not embed the
25887c478bd9Sstevel@tonic-gate 		 drive number.  */
25897c478bd9Sstevel@tonic-gate 	      current_drive = GRUB_INVALID_DRIVE;
25907c478bd9Sstevel@tonic-gate 	    }
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	  device = (current_drive << 24) | current_partition;
25937c478bd9Sstevel@tonic-gate 	  grub_memmove (config_file_location, (char *) &device,
25947c478bd9Sstevel@tonic-gate 			sizeof (device));
25957c478bd9Sstevel@tonic-gate 	  grub_strcpy (config_file_location + sizeof (device),
25967c478bd9Sstevel@tonic-gate 		       real_config);
25977c478bd9Sstevel@tonic-gate 	}
25987c478bd9Sstevel@tonic-gate 
25997c478bd9Sstevel@tonic-gate       /* If a Stage 1.5 is used, then we need to modify the Stage2.  */
26007c478bd9Sstevel@tonic-gate       if (is_stage1_5)
26017c478bd9Sstevel@tonic-gate 	{
26027c478bd9Sstevel@tonic-gate 	  char *real_config_filename = skip_to (0, ptr);
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 	  is_open = grub_open (config_filename);
26057c478bd9Sstevel@tonic-gate 	  if (! is_open)
26067c478bd9Sstevel@tonic-gate 	    goto fail;
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	  /* Skip the first sector.  */
26097c478bd9Sstevel@tonic-gate 	  grub_seek (SECTOR_SIZE);
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate 	  disk_read_hook = disk_read_savesect_func;
26127c478bd9Sstevel@tonic-gate 	  if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
26137c478bd9Sstevel@tonic-gate 	    goto fail;
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 	  disk_read_hook = 0;
26167c478bd9Sstevel@tonic-gate 	  grub_close ();
26177c478bd9Sstevel@tonic-gate 	  is_open = 0;
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 	  /* Sanity check.  */
26207c478bd9Sstevel@tonic-gate 	  if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2)
26217c478bd9Sstevel@tonic-gate 	    {
26227c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_VERSION;
26237c478bd9Sstevel@tonic-gate 	      goto fail;
26247c478bd9Sstevel@tonic-gate 	    }
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	  /* Set the "force LBA" flag for Stage2.  */
26277c478bd9Sstevel@tonic-gate 	  *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba;
26287c478bd9Sstevel@tonic-gate 
26297c478bd9Sstevel@tonic-gate 	  /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2.  */
26307c478bd9Sstevel@tonic-gate 	  if (*real_config_filename)
26317c478bd9Sstevel@tonic-gate 	    {
26327c478bd9Sstevel@tonic-gate 	      /* Specified */
26337c478bd9Sstevel@tonic-gate 	      char *location;
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	      /* Find a string for the configuration filename.  */
26367c478bd9Sstevel@tonic-gate 	      location = stage2_buffer + STAGE2_VER_STR_OFFS;
26377c478bd9Sstevel@tonic-gate 	      while (*(location++))
26387c478bd9Sstevel@tonic-gate 		;
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate 	      /* Copy the name.  */
26417c478bd9Sstevel@tonic-gate 	      grub_strcpy (location, real_config_filename);
26427c478bd9Sstevel@tonic-gate 	    }
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 	  /* Write it to the disk.  */
2645342440ecSPrasad Singamsetty 	  buf_track = BUF_CACHE_INVALID;
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
26487c478bd9Sstevel@tonic-gate 	  /* In the grub shell, access the Stage 2 via the OS filesystem
26497c478bd9Sstevel@tonic-gate 	     service, if possible.  */
26507c478bd9Sstevel@tonic-gate 	  if (stage2_os_file)
26517c478bd9Sstevel@tonic-gate 	    {
26527c478bd9Sstevel@tonic-gate 	      FILE *fp;
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 	      fp = fopen (stage2_os_file, "r+");
26557c478bd9Sstevel@tonic-gate 	      if (! fp)
26567c478bd9Sstevel@tonic-gate 		{
26577c478bd9Sstevel@tonic-gate 		  errnum = ERR_FILE_NOT_FOUND;
26587c478bd9Sstevel@tonic-gate 		  goto fail;
26597c478bd9Sstevel@tonic-gate 		}
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate 	      if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
26627c478bd9Sstevel@tonic-gate 		{
26637c478bd9Sstevel@tonic-gate 		  fclose (fp);
26647c478bd9Sstevel@tonic-gate 		  errnum = ERR_BAD_VERSION;
26657c478bd9Sstevel@tonic-gate 		  goto fail;
26667c478bd9Sstevel@tonic-gate 		}
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	      if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp)
26697c478bd9Sstevel@tonic-gate 		  != SECTOR_SIZE)
26707c478bd9Sstevel@tonic-gate 		{
26717c478bd9Sstevel@tonic-gate 		  fclose (fp);
26727c478bd9Sstevel@tonic-gate 		  errnum = ERR_WRITE;
26737c478bd9Sstevel@tonic-gate 		  goto fail;
26747c478bd9Sstevel@tonic-gate 		}
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 	      fclose (fp);
26777c478bd9Sstevel@tonic-gate 	    }
26787c478bd9Sstevel@tonic-gate 	  else
26797c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
26807c478bd9Sstevel@tonic-gate 	    {
26817c478bd9Sstevel@tonic-gate 	      if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
26827c478bd9Sstevel@tonic-gate 		goto fail;
26837c478bd9Sstevel@tonic-gate 	    }
26847c478bd9Sstevel@tonic-gate 	}
26857c478bd9Sstevel@tonic-gate     }
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate   /* Clear the cache.  */
2688342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate   /* Write the modified sectors of Stage2 to the disk.  */
26917c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
26927c478bd9Sstevel@tonic-gate   if (! is_stage1_5 && stage2_os_file)
26937c478bd9Sstevel@tonic-gate     {
26947c478bd9Sstevel@tonic-gate       FILE *fp;
26957c478bd9Sstevel@tonic-gate 
26967c478bd9Sstevel@tonic-gate       fp = fopen (stage2_os_file, "r+");
26977c478bd9Sstevel@tonic-gate       if (! fp)
26987c478bd9Sstevel@tonic-gate 	{
26997c478bd9Sstevel@tonic-gate 	  errnum = ERR_FILE_NOT_FOUND;
27007c478bd9Sstevel@tonic-gate 	  goto fail;
27017c478bd9Sstevel@tonic-gate 	}
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate       if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
27047c478bd9Sstevel@tonic-gate 	{
27057c478bd9Sstevel@tonic-gate 	  fclose (fp);
27067c478bd9Sstevel@tonic-gate 	  errnum = ERR_WRITE;
27077c478bd9Sstevel@tonic-gate 	  goto fail;
27087c478bd9Sstevel@tonic-gate 	}
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate       if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
27117c478bd9Sstevel@tonic-gate 	{
27127c478bd9Sstevel@tonic-gate 	  fclose (fp);
27137c478bd9Sstevel@tonic-gate 	  errnum = ERR_WRITE;
27147c478bd9Sstevel@tonic-gate 	  goto fail;
27157c478bd9Sstevel@tonic-gate 	}
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate       fclose (fp);
27187c478bd9Sstevel@tonic-gate     }
27197c478bd9Sstevel@tonic-gate   else
27207c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
27217c478bd9Sstevel@tonic-gate     {
27227c478bd9Sstevel@tonic-gate       /* The first.  */
27237c478bd9Sstevel@tonic-gate       current_drive = src_drive;
27247c478bd9Sstevel@tonic-gate       current_partition = src_partition;
27257c478bd9Sstevel@tonic-gate 
27267c478bd9Sstevel@tonic-gate       if (! open_partition ())
27277c478bd9Sstevel@tonic-gate 	goto fail;
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate       if (! devwrite (stage2_first_sector - src_part_start, 1,
27307c478bd9Sstevel@tonic-gate 		      stage2_first_buffer))
27317c478bd9Sstevel@tonic-gate 	goto fail;
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate       if (! devwrite (stage2_second_sector - src_part_start, 1,
27347c478bd9Sstevel@tonic-gate 		      stage2_second_buffer))
27357c478bd9Sstevel@tonic-gate 	goto fail;
27367c478bd9Sstevel@tonic-gate     }
27377c478bd9Sstevel@tonic-gate 
27387c478bd9Sstevel@tonic-gate   /* Write the modified sector of Stage 1 to the disk.  */
27397c478bd9Sstevel@tonic-gate   current_drive = dest_drive;
27407c478bd9Sstevel@tonic-gate   current_partition = dest_partition;
27417c478bd9Sstevel@tonic-gate   if (! open_partition ())
27427c478bd9Sstevel@tonic-gate     goto fail;
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate   devwrite (0, 1, stage1_buffer);
27457c478bd9Sstevel@tonic-gate 
27467c478bd9Sstevel@tonic-gate  fail:
27477c478bd9Sstevel@tonic-gate   if (is_open)
27487c478bd9Sstevel@tonic-gate     grub_close ();
27497c478bd9Sstevel@tonic-gate 
27507c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
27517c478bd9Sstevel@tonic-gate 
27527c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
27537c478bd9Sstevel@tonic-gate   no_decompression = 0;
27547c478bd9Sstevel@tonic-gate #endif
27557c478bd9Sstevel@tonic-gate 
27567c478bd9Sstevel@tonic-gate   return errnum;
27577c478bd9Sstevel@tonic-gate }
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate static struct builtin builtin_install =
27607c478bd9Sstevel@tonic-gate {
27617c478bd9Sstevel@tonic-gate   "install",
27627c478bd9Sstevel@tonic-gate   install_func,
27637c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
27647c478bd9Sstevel@tonic-gate   "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
27657c478bd9Sstevel@tonic-gate   "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2"
27667c478bd9Sstevel@tonic-gate   " as a Stage 2. If the option `d' is present, the Stage 1 will always"
27677c478bd9Sstevel@tonic-gate   " look for the disk where STAGE2 was installed, rather than using"
27687c478bd9Sstevel@tonic-gate   " the booting drive. The Stage 2 will be loaded at address ADDR, which"
27697c478bd9Sstevel@tonic-gate   " will be determined automatically if you don't specify it. If"
27707c478bd9Sstevel@tonic-gate   " the option `p' or CONFIG_FILE is present, then the first block"
27717c478bd9Sstevel@tonic-gate   " of Stage 2 is patched with new values of the partition and name"
27727c478bd9Sstevel@tonic-gate   " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
27737c478bd9Sstevel@tonic-gate   " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage"
27747c478bd9Sstevel@tonic-gate   " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
27757c478bd9Sstevel@tonic-gate   " patched with the configuration filename REAL_CONFIG_FILE."
27767c478bd9Sstevel@tonic-gate   " If the option `--force-lba' is specified, disable some sanity checks"
27777c478bd9Sstevel@tonic-gate   " for LBA mode. If the option `--stage2' is specified, rewrite the Stage"
27787c478bd9Sstevel@tonic-gate   " 2 via your OS's filesystem instead of the raw device."
27797c478bd9Sstevel@tonic-gate };
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 
27827c478bd9Sstevel@tonic-gate /* ioprobe */
27837c478bd9Sstevel@tonic-gate static int
27847c478bd9Sstevel@tonic-gate ioprobe_func (char *arg, int flags)
27857c478bd9Sstevel@tonic-gate {
27867c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
27897c478bd9Sstevel@tonic-gate   return 1;
27907c478bd9Sstevel@tonic-gate 
27917c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate   unsigned short *port;
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate   /* Get the drive number.  */
27967c478bd9Sstevel@tonic-gate   set_device (arg);
27977c478bd9Sstevel@tonic-gate   if (errnum)
27987c478bd9Sstevel@tonic-gate     return 1;
27997c478bd9Sstevel@tonic-gate 
28007c478bd9Sstevel@tonic-gate   /* Clean out IO_MAP.  */
28017c478bd9Sstevel@tonic-gate   grub_memset ((char *) io_map, 0, IO_MAP_SIZE * sizeof (unsigned short));
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate   /* Track the int13 handler.  */
28047c478bd9Sstevel@tonic-gate   track_int13 (current_drive);
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate   /* Print out the result.  */
28077c478bd9Sstevel@tonic-gate   for (port = io_map; *port != 0; port++)
28087c478bd9Sstevel@tonic-gate     grub_printf (" 0x%x", (unsigned int) *port);
28097c478bd9Sstevel@tonic-gate 
28107c478bd9Sstevel@tonic-gate   return 0;
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
28137c478bd9Sstevel@tonic-gate }
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate static struct builtin builtin_ioprobe =
28167c478bd9Sstevel@tonic-gate {
28177c478bd9Sstevel@tonic-gate   "ioprobe",
28187c478bd9Sstevel@tonic-gate   ioprobe_func,
28197c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
28207c478bd9Sstevel@tonic-gate   "ioprobe DRIVE",
28217c478bd9Sstevel@tonic-gate   "Probe I/O ports used for the drive DRIVE."
28227c478bd9Sstevel@tonic-gate };
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate 
2825b1b8ab34Slling /*
2826b1b8ab34Slling  * To boot from a ZFS root filesystem, the kernel$ or module$ commands
2827ffb5616eSLin Ling  * must include "-B $ZFS-BOOTFS" to expand to the zfs-bootfs, bootpath,
2828ffb5616eSLin Ling  * and diskdevid boot property values for passing to the kernel:
2829b1b8ab34Slling  *
2830b1b8ab34Slling  * e.g.
2831b1b8ab34Slling  * kernel$ /platform/i86pc/kernel/$ISADIR/unix -B $ZFS-BOOTFS,console=ttya
2832b1b8ab34Slling  *
2833ffb5616eSLin Ling  * $ZFS-BOOTFS is expanded to
2834ffb5616eSLin Ling  *
2835ffb5616eSLin Ling  *    zfs-bootfs=<rootpool-name/zfs-rootfilesystem-object-num>,
2836ffb5616eSLin Ling  *    bootpath=<device phys path>,
2837ffb5616eSLin Ling  *    diskdevid=<device id>
2838ffb5616eSLin Ling  *
2839ffb5616eSLin Ling  * if both bootpath and diskdevid can be found.
2840ffb5616eSLin Ling  * e.g
2841ffb5616eSLin Ling  *    zfs-bootfs=rpool/85,
2842ffb5616eSLin Ling  *    bootpath="/pci@0,0/pci1022,7450@a/pci17c2,10@4/sd@0,0:a",
2843ffb5616eSLin Ling  *    diskdevid="id1,sd@SSEAGATE_ST336607LC______3JA0LNHE0000741326W6/a"
2844b1b8ab34Slling  */
2845b1b8ab34Slling static int
2846b1b8ab34Slling expand_dollar_bootfs(char *in, char *out)
2847b1b8ab34Slling {
2848b1b8ab34Slling 	char *token, *tmpout = out;
2849b1b8ab34Slling 	int outlen, blen;
2850bf82a41bSeschrock 	int postcomma = 0;
2851b1b8ab34Slling 
285238614cc7SLin Ling 	/* no op if this is not zfs */
285338614cc7SLin Ling 	if (is_zfs_mount == 0)
285438614cc7SLin Ling 		return (0);
285538614cc7SLin Ling 
2856ffb5616eSLin Ling 	if (current_bootpath[0] == '\0' && current_devid[0] == '\0') {
2857ffb5616eSLin Ling 		errnum = ERR_NO_BOOTPATH;
2858ffb5616eSLin Ling 		return (1);
2859ffb5616eSLin Ling 	}
2860ffb5616eSLin Ling 
2861b1b8ab34Slling 	outlen = strlen(in);
2862b1b8ab34Slling 	blen = current_bootfs_obj == 0 ? strlen(current_rootpool) :
2863b1b8ab34Slling 	    strlen(current_rootpool) + 11;
2864b1b8ab34Slling 
2865b1b8ab34Slling 	out[0] = '\0';
2866b1b8ab34Slling 	while (token = strstr(in, "$ZFS-BOOTFS")) {
2867b1b8ab34Slling 
2868ffb5616eSLin Ling 		if ((outlen += blen) >= MAX_CMDLINE) {
2869b1b8ab34Slling 			errnum = ERR_WONT_FIT;
2870b1b8ab34Slling 			return (1);
2871b1b8ab34Slling 		}
2872b1b8ab34Slling 
2873b1b8ab34Slling 		token[0] = '\0';
2874b1b8ab34Slling 		grub_sprintf(tmpout, "%s", in);
2875b1b8ab34Slling 		token[0] = '$';
2876051aabe6Staylor 		in = token + 11; /* skip over $ZFS-BOOTFS */
2877b1b8ab34Slling 		tmpout = out + strlen(out);
2878b1b8ab34Slling 
2879b1b8ab34Slling 		/* Note: %u only fits 32 bit integer; */
2880b1b8ab34Slling 		if (current_bootfs_obj > 0)
2881b1b8ab34Slling 			grub_sprintf(tmpout, "zfs-bootfs=%s/%u",
2882b1b8ab34Slling 			    current_rootpool, current_bootfs_obj);
2883b1b8ab34Slling 		else
2884b1b8ab34Slling 			grub_sprintf(tmpout, "zfs-bootfs=%s",
2885b1b8ab34Slling 			    current_rootpool);
2886b1b8ab34Slling 		tmpout = out + strlen(out);
2887b1b8ab34Slling 	}
2888b1b8ab34Slling 
2889e7cbe64fSgw 	/*
2890bf82a41bSeschrock 	 * Check to see if 'zfs-bootfs' was explicitly specified on the command
2891bf82a41bSeschrock 	 * line so that we can insert the 'bootpath' property.
2892bf82a41bSeschrock 	 */
2893bf82a41bSeschrock 	if ((tmpout == out) && (token = strstr(in, "zfs-bootfs")) != NULL) {
2894bf82a41bSeschrock 		token[0] = '\0';
2895bf82a41bSeschrock 		grub_strcpy(tmpout, in);
2896bf82a41bSeschrock 		token[0] = 'z';
2897bf82a41bSeschrock 		in = token;
2898bf82a41bSeschrock 
2899bf82a41bSeschrock 		tmpout = out + strlen(out);
2900bf82a41bSeschrock 		postcomma = 1;
2901bf82a41bSeschrock 	}
2902bf82a41bSeschrock 
2903bf82a41bSeschrock 	/*
2904bf82a41bSeschrock 	 * Set the 'bootpath' property if a ZFS dataset was specified, either
2905bf82a41bSeschrock 	 * through '$ZFS-BOOTFS' or an explicit 'zfs-bootfs' setting.
2906e7cbe64fSgw 	 */
2907e7cbe64fSgw 	if (tmpout != out) {
2908ffb5616eSLin Ling 		if (current_bootpath[0] != '\0') {
2909ffb5616eSLin Ling 			if ((outlen += 12 + strlen(current_bootpath))
2910ffb5616eSLin Ling 			    >= MAX_CMDLINE) {
2911ffb5616eSLin Ling 				errnum = ERR_WONT_FIT;
2912ffb5616eSLin Ling 				return (1);
2913ffb5616eSLin Ling 			}
2914ffb5616eSLin Ling 			grub_sprintf(tmpout,
2915ffb5616eSLin Ling 			    postcomma ? "bootpath=\"%s\"," : ",bootpath=\"%s\"",
2916ffb5616eSLin Ling 			    current_bootpath);
2917ffb5616eSLin Ling 			tmpout = out + strlen(out);
2918e7cbe64fSgw 		}
2919ffb5616eSLin Ling 
2920ffb5616eSLin Ling 		if (current_devid[0] != '\0') {
2921ffb5616eSLin Ling 			if ((outlen += 13 + strlen(current_devid))
2922ffb5616eSLin Ling 			    >= MAX_CMDLINE) {
2923ffb5616eSLin Ling 				errnum = ERR_WONT_FIT;
2924ffb5616eSLin Ling 				return (1);
2925ffb5616eSLin Ling 			}
2926ffb5616eSLin Ling 			grub_sprintf(tmpout,
2927ffb5616eSLin Ling 			    postcomma ? "diskdevid=\"%s\"," : ",diskdevid=\"%s\"",
2928ffb5616eSLin Ling 			    current_devid);
2929051aabe6Staylor 		}
2930e7cbe64fSgw 	}
2931e7cbe64fSgw 
2932b1b8ab34Slling 	strncat(out, in, MAX_CMDLINE);
2933b1b8ab34Slling 	return (0);
2934b1b8ab34Slling }
2935b1b8ab34Slling 
29367c478bd9Sstevel@tonic-gate /* kernel */
29377c478bd9Sstevel@tonic-gate static int
29387c478bd9Sstevel@tonic-gate kernel_func (char *arg, int flags)
29397c478bd9Sstevel@tonic-gate {
29407c478bd9Sstevel@tonic-gate   int len;
29417c478bd9Sstevel@tonic-gate   kernel_t suggested_type = KERNEL_TYPE_NONE;
29427c478bd9Sstevel@tonic-gate   unsigned long load_flags = 0;
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate #ifndef AUTO_LINUX_MEM_OPT
29457c478bd9Sstevel@tonic-gate   load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
29467c478bd9Sstevel@tonic-gate #endif
29477c478bd9Sstevel@tonic-gate 
29487c478bd9Sstevel@tonic-gate   /* Deal with GNU-style long options.  */
29497c478bd9Sstevel@tonic-gate   while (1)
29507c478bd9Sstevel@tonic-gate     {
29517c478bd9Sstevel@tonic-gate       /* If the option `--type=TYPE' is specified, convert the string to
29527c478bd9Sstevel@tonic-gate 	 a kernel type.  */
29537c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--type=", 7) == 0)
29547c478bd9Sstevel@tonic-gate 	{
29557c478bd9Sstevel@tonic-gate 	  arg += 7;
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate 	  if (grub_memcmp (arg, "netbsd", 6) == 0)
29587c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_NETBSD;
29597c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "freebsd", 7) == 0)
29607c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_FREEBSD;
29617c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "openbsd", 7) == 0)
29627c478bd9Sstevel@tonic-gate 	    /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's
29637c478bd9Sstevel@tonic-gate 	       point of view.  */
29647c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_NETBSD;
29657c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "linux", 5) == 0)
29667c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_LINUX;
29677c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "biglinux", 8) == 0)
29687c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_BIG_LINUX;
29697c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "multiboot", 9) == 0)
29707c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_MULTIBOOT;
29717c478bd9Sstevel@tonic-gate 	  else
29727c478bd9Sstevel@tonic-gate 	    {
29737c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
29747c478bd9Sstevel@tonic-gate 	      return 1;
29757c478bd9Sstevel@tonic-gate 	    }
29767c478bd9Sstevel@tonic-gate 	}
29777c478bd9Sstevel@tonic-gate       /* If the `--no-mem-option' is specified, don't pass a Linux's mem
29787c478bd9Sstevel@tonic-gate 	 option automatically. If the kernel is another type, this flag
29797c478bd9Sstevel@tonic-gate 	 has no effect.  */
29807c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
29817c478bd9Sstevel@tonic-gate 	load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
29827c478bd9Sstevel@tonic-gate       else
29837c478bd9Sstevel@tonic-gate 	break;
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate       /* Try the next.  */
29867c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
29877c478bd9Sstevel@tonic-gate     }
29887c478bd9Sstevel@tonic-gate 
29897c478bd9Sstevel@tonic-gate   len = grub_strlen (arg);
29907c478bd9Sstevel@tonic-gate 
29917c478bd9Sstevel@tonic-gate   /* Reset MB_CMDLINE.  */
29927c478bd9Sstevel@tonic-gate   mb_cmdline = (char *) MB_CMDLINE_BUF;
29937c478bd9Sstevel@tonic-gate   if (len + 1 > MB_CMDLINE_BUFLEN)
29947c478bd9Sstevel@tonic-gate     {
29957c478bd9Sstevel@tonic-gate       errnum = ERR_WONT_FIT;
29967c478bd9Sstevel@tonic-gate       return 1;
29977c478bd9Sstevel@tonic-gate     }
29987c478bd9Sstevel@tonic-gate 
29997c478bd9Sstevel@tonic-gate   /* Copy the command-line to MB_CMDLINE.  */
30007c478bd9Sstevel@tonic-gate   grub_memmove (mb_cmdline, arg, len + 1);
30017c478bd9Sstevel@tonic-gate   kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags);
30027c478bd9Sstevel@tonic-gate   if (kernel_type == KERNEL_TYPE_NONE)
30037c478bd9Sstevel@tonic-gate     return 1;
30047c478bd9Sstevel@tonic-gate 
3005b1b8ab34Slling   mb_cmdline += grub_strlen(mb_cmdline) + 1;
30067c478bd9Sstevel@tonic-gate   return 0;
30077c478bd9Sstevel@tonic-gate }
30087c478bd9Sstevel@tonic-gate 
30097c478bd9Sstevel@tonic-gate static struct builtin builtin_kernel =
30107c478bd9Sstevel@tonic-gate {
30117c478bd9Sstevel@tonic-gate   "kernel",
30127c478bd9Sstevel@tonic-gate   kernel_func,
30137c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
30147c478bd9Sstevel@tonic-gate   "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
30157c478bd9Sstevel@tonic-gate   "Attempt to load the primary boot image from FILE. The rest of the"
30167c478bd9Sstevel@tonic-gate   " line is passed verbatim as the \"kernel command line\".  Any modules"
30177c478bd9Sstevel@tonic-gate   " must be reloaded after using this command. The option --type is used"
30187c478bd9Sstevel@tonic-gate   " to suggest what type of kernel to be loaded. TYPE must be either of"
30197c478bd9Sstevel@tonic-gate   " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
30207c478bd9Sstevel@tonic-gate   " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
30217c478bd9Sstevel@tonic-gate   " Linux's mem option automatically."
30227c478bd9Sstevel@tonic-gate };
30237c478bd9Sstevel@tonic-gate 
3024342440ecSPrasad Singamsetty int
3025342440ecSPrasad Singamsetty min_mem64_func(char *arg, int flags)
3026342440ecSPrasad Singamsetty {
3027342440ecSPrasad Singamsetty 	if (!safe_parse_maxint(&arg, &min_mem64))
3028342440ecSPrasad Singamsetty 		return (1);
3029342440ecSPrasad Singamsetty }
3030342440ecSPrasad Singamsetty 
3031342440ecSPrasad Singamsetty static struct builtin builtin_min_mem64 =
3032342440ecSPrasad Singamsetty {
3033342440ecSPrasad Singamsetty 	"min_mem64",
3034342440ecSPrasad Singamsetty 	min_mem64_func,
3035342440ecSPrasad Singamsetty 	BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
3036342440ecSPrasad Singamsetty 	"min_mem64 <memory in MB>",
3037342440ecSPrasad Singamsetty 	"Sets minimum memory (in MB) required for $ISADIR to expand to amd64, "
3038342440ecSPrasad Singamsetty 	"even on 64-bit capable hardware."
3039342440ecSPrasad Singamsetty };
3040342440ecSPrasad Singamsetty 
3041342440ecSPrasad Singamsetty int
3042342440ecSPrasad Singamsetty check_min_mem64()
3043342440ecSPrasad Singamsetty {
3044342440ecSPrasad Singamsetty 	if (min_mem64 == 0)
3045342440ecSPrasad Singamsetty 		return (1);
3046342440ecSPrasad Singamsetty 
3047342440ecSPrasad Singamsetty 	if ((mbi.mem_upper / 10240) * 11 >= min_mem64)
3048342440ecSPrasad Singamsetty 		return (1);
3049342440ecSPrasad Singamsetty 
3050342440ecSPrasad Singamsetty 	return (0);
3051342440ecSPrasad Singamsetty }
3052ae115bc7Smrj 
3053ae115bc7Smrj static int detect_target_operating_mode();
3054ae115bc7Smrj 
3055ae115bc7Smrj int
3056ae115bc7Smrj amd64_config_cpu(void)
3057ae115bc7Smrj {
3058ae115bc7Smrj         struct amd64_cpuid_regs __vcr, *vcr = &__vcr;
3059ae115bc7Smrj         uint32_t maxeax;
3060ae115bc7Smrj         uint32_t max_maxeax = 0x100;
3061ae115bc7Smrj         char vendor[13];
3062ae115bc7Smrj         int isamd64 = 0;
3063ae115bc7Smrj         uint32_t stdfeatures = 0, xtdfeatures = 0;
3064ae115bc7Smrj         uint64_t efer;
3065ae115bc7Smrj 
3066ae115bc7Smrj         /*
3067ae115bc7Smrj          * This check may seem silly, but if the C preprocesor symbol __amd64
3068ae115bc7Smrj          * is #defined during compilation, something that may outwardly seem
3069ae115bc7Smrj          * like a good idea, uts/common/sys/isa_defs.h will #define _LP64,
3070ae115bc7Smrj          * which will cause uts/common/sys/int_types.h to typedef uint64_t as
3071ae115bc7Smrj          * an unsigned long - which is only 4 bytes in size when using a 32-bit
3072ae115bc7Smrj          * compiler.
3073ae115bc7Smrj          *
3074ae115bc7Smrj          * If that happens, all the page table translation routines will fail
3075ae115bc7Smrj          * horribly, so check the size of uint64_t just to insure some degree
3076ae115bc7Smrj          * of sanity in future operations.
3077ae115bc7Smrj          */
3078ae115bc7Smrj         /*LINTED [sizeof result is invarient]*/
3079ae115bc7Smrj         if (sizeof (uint64_t) != 8)
3080ae115bc7Smrj                 prom_panic("grub compiled improperly, unable to boot "
3081ae115bc7Smrj                     "64-bit AMD64 executables");
3082ae115bc7Smrj 
3083ae115bc7Smrj         /*
3084ae115bc7Smrj          * If the CPU doesn't support the CPUID instruction, it's definitely
3085ae115bc7Smrj          * not an AMD64.
3086ae115bc7Smrj          */
3087ae115bc7Smrj         if (amd64_cpuid_supported() == 0)
3088ae115bc7Smrj                 return (0);
3089ae115bc7Smrj 
3090ae115bc7Smrj         amd64_cpuid_insn(0, vcr);
3091ae115bc7Smrj 
3092ae115bc7Smrj         maxeax = vcr->r_eax;
3093ae115bc7Smrj         {
3094ae115bc7Smrj                 /*LINTED [vendor string from cpuid data]*/
3095ae115bc7Smrj                 uint32_t *iptr = (uint32_t *)vendor;
3096ae115bc7Smrj 
3097ae115bc7Smrj                 *iptr++ = vcr->r_ebx;
3098ae115bc7Smrj                 *iptr++ = vcr->r_edx;
3099ae115bc7Smrj                 *iptr++ = vcr->r_ecx;
3100ae115bc7Smrj 
3101ae115bc7Smrj                 vendor[12] = '\0';
3102ae115bc7Smrj         }
3103ae115bc7Smrj 
3104ae115bc7Smrj         if (maxeax > max_maxeax) {
3105ae115bc7Smrj                 grub_printf("cpu: warning, maxeax was 0x%x -> 0x%x\n",
3106ae115bc7Smrj                     maxeax, max_maxeax);
3107ae115bc7Smrj                 maxeax = max_maxeax;
3108ae115bc7Smrj         }
3109ae115bc7Smrj 
3110ae115bc7Smrj         if (maxeax < 1)
3111ae115bc7Smrj                 return (0);     /* no additional functions, not an AMD64 */
3112ae115bc7Smrj         else {
3113ae115bc7Smrj                 uint_t family, model, step;
3114ae115bc7Smrj 
3115ae115bc7Smrj                 amd64_cpuid_insn(1, vcr);
3116ae115bc7Smrj 
3117ae115bc7Smrj                 /*
3118ae115bc7Smrj                  * All AMD64/IA32e processors technically SHOULD report
3119ae115bc7Smrj                  * themselves as being in family 0xf, but for some reason
3120ae115bc7Smrj                  * Simics doesn't, and this may change in the future, so
3121ae115bc7Smrj                  * don't error out if it's not true.
3122ae115bc7Smrj                  */
3123ae115bc7Smrj                 if ((family = BITX(vcr->r_eax, 11, 8)) == 0xf)
3124ae115bc7Smrj                         family += BITX(vcr->r_eax, 27, 20);
3125ae115bc7Smrj 
3126ae115bc7Smrj                 if ((model = BITX(vcr->r_eax, 7, 4)) == 0xf)
3127ae115bc7Smrj                         model += BITX(vcr->r_eax, 19, 16) << 4;
3128ae115bc7Smrj                 step = BITX(vcr->r_eax, 3, 0);
3129ae115bc7Smrj 
3130ae115bc7Smrj                 grub_printf("cpu: '%s' family %d model %d step %d\n",
3131ae115bc7Smrj                     vendor, family, model, step);
3132ae115bc7Smrj                 stdfeatures = vcr->r_edx;
3133ae115bc7Smrj         }
3134ae115bc7Smrj 
3135ae115bc7Smrj         amd64_cpuid_insn(0x80000000, vcr);
3136ae115bc7Smrj 
3137ae115bc7Smrj         if (vcr->r_eax & 0x80000000) {
3138ae115bc7Smrj                 uint32_t xmaxeax = vcr->r_eax;
3139ae115bc7Smrj                 const uint32_t max_xmaxeax = 0x80000100;
3140ae115bc7Smrj 
3141ae115bc7Smrj                 if (xmaxeax > max_xmaxeax) {
3142ae115bc7Smrj                         grub_printf("amd64: warning, xmaxeax was "
3143ae115bc7Smrj 			    "0x%x -> 0x%x\n", xmaxeax, max_xmaxeax);
3144ae115bc7Smrj                         xmaxeax = max_xmaxeax;
3145ae115bc7Smrj                 }
3146ae115bc7Smrj 
3147ae115bc7Smrj                 if (xmaxeax >= 0x80000001) {
3148ae115bc7Smrj                         amd64_cpuid_insn(0x80000001, vcr);
3149ae115bc7Smrj                         xtdfeatures = vcr->r_edx;
3150ae115bc7Smrj                 }
3151ae115bc7Smrj         }
3152ae115bc7Smrj 
3153ae115bc7Smrj         if (BITX(xtdfeatures, 29, 29))          /* long mode */
3154ae115bc7Smrj                 isamd64++;
3155ae115bc7Smrj         else
3156ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support long mode\n");
3157ae115bc7Smrj 
3158ae115bc7Smrj         if (!BITX(stdfeatures, 0, 0)) {
3159ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support FPU\n");
3160ae115bc7Smrj                 isamd64--;
3161ae115bc7Smrj         }
3162ae115bc7Smrj 
3163ae115bc7Smrj         if (!BITX(stdfeatures, 4, 4)) {
3164ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support TSC\n");
3165ae115bc7Smrj                 isamd64--;
3166ae115bc7Smrj         }
3167ae115bc7Smrj 
3168ae115bc7Smrj         if (!BITX(stdfeatures, 5, 5)) {
3169ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support MSRs\n");
3170ae115bc7Smrj                 isamd64--;
3171ae115bc7Smrj         }
3172ae115bc7Smrj 
3173ae115bc7Smrj         if (!BITX(stdfeatures, 6, 6)) {
3174ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support PAE\n");
3175ae115bc7Smrj                 isamd64--;
3176ae115bc7Smrj         }
3177ae115bc7Smrj 
3178ae115bc7Smrj         if (!BITX(stdfeatures, 8, 8)) {
3179ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support CX8\n");
3180ae115bc7Smrj                 isamd64--;
3181ae115bc7Smrj         }
3182ae115bc7Smrj 
3183ae115bc7Smrj         if (!BITX(stdfeatures, 13, 13)) {
3184ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support PGE\n");
3185ae115bc7Smrj                 isamd64--;
3186ae115bc7Smrj         }
3187ae115bc7Smrj 
3188ae115bc7Smrj         if (!BITX(stdfeatures, 19, 19)) {
3189ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support CLFSH\n");
3190ae115bc7Smrj                 isamd64--;
3191ae115bc7Smrj         }
3192ae115bc7Smrj 
3193ae115bc7Smrj         if (!BITX(stdfeatures, 23, 23)) {
3194ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support MMX\n");
3195ae115bc7Smrj                 isamd64--;
3196ae115bc7Smrj         }
3197ae115bc7Smrj 
3198ae115bc7Smrj         if (!BITX(stdfeatures, 24, 24)) {
3199ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support FXSR\n");
3200ae115bc7Smrj                 isamd64--;
3201ae115bc7Smrj         }
3202ae115bc7Smrj 
3203ae115bc7Smrj         if (!BITX(stdfeatures, 25, 25)) {
3204ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support SSE\n");
3205ae115bc7Smrj                 isamd64--;
3206ae115bc7Smrj         }
3207ae115bc7Smrj 
3208ae115bc7Smrj         if (!BITX(stdfeatures, 26, 26)) {
3209ae115bc7Smrj                 grub_printf("amd64: CPU does NOT support SSE2\n");
3210ae115bc7Smrj                 isamd64--;
3211ae115bc7Smrj         }
3212ae115bc7Smrj 
3213ae115bc7Smrj         if (isamd64 < 1) {
3214ae115bc7Smrj                 grub_printf("amd64: CPU does not support amd64 executables.\n");
3215ae115bc7Smrj                 return (0);
3216ae115bc7Smrj         }
3217ae115bc7Smrj 
3218ae115bc7Smrj         amd64_rdmsr(MSR_AMD_EFER, &efer);
3219ae115bc7Smrj         if (efer & AMD_EFER_SCE)
3220ae115bc7Smrj                 grub_printf("amd64: EFER_SCE (syscall/sysret) already "
3221ae115bc7Smrj 		    "enabled\n");
3222ae115bc7Smrj         if (efer & AMD_EFER_NXE)
3223ae115bc7Smrj                 grub_printf("amd64: EFER_NXE (no-exec prot) already enabled\n");
3224ae115bc7Smrj         if (efer & AMD_EFER_LME)
3225ae115bc7Smrj                 grub_printf("amd64: EFER_LME (long mode) already enabled\n");
3226ae115bc7Smrj 
3227ae115bc7Smrj         return (detect_target_operating_mode());
3228ae115bc7Smrj }
3229ae115bc7Smrj 
3230ae115bc7Smrj static int
3231ae115bc7Smrj detect_target_operating_mode()
3232ae115bc7Smrj {
3233ae115bc7Smrj         int ret, ah;
3234ae115bc7Smrj 
3235ae115bc7Smrj 	ah = get_target_operating_mode();
3236ae115bc7Smrj 
3237ae115bc7Smrj         ah = ah >> 8;
3238ae115bc7Smrj 
3239ae115bc7Smrj 	/* XXX still need to pass back the return from the call  */
3240ae115bc7Smrj 	ret = 0;
3241ae115bc7Smrj 
3242ae115bc7Smrj         if (ah == 0x86 && (ret & CB) != 0) {
3243ae115bc7Smrj                 grub_printf("[BIOS 'Detect Target Operating Mode' "
3244ae115bc7Smrj                     "callback unsupported on this platform]\n");
3245ae115bc7Smrj                 return (1);     /* unsupported, ignore */
3246ae115bc7Smrj         }
3247ae115bc7Smrj 
3248ae115bc7Smrj         if (ah == 0x0 && (ret & CB) == 0) {
3249ae115bc7Smrj                 grub_printf("[BIOS accepted mixed-mode target setting!]\n");
3250ae115bc7Smrj                 return (1);     /* told the bios what we're up to */
3251ae115bc7Smrj         }
3252ae115bc7Smrj 
3253ae115bc7Smrj         if (ah == 0 && ret & CB) {
3254ae115bc7Smrj                 grub_printf("fatal: BIOS reports this machine CANNOT run in "
3255ae115bc7Smrj 		    "mixed 32/64-bit mode!\n");
3256ae115bc7Smrj                 return (0);
3257ae115bc7Smrj         }
3258ae115bc7Smrj 
3259ae115bc7Smrj         grub_printf("warning: BIOS Detect Target Operating Mode callback "
3260ae115bc7Smrj             "confused.\n         %%ax >> 8 = 0x%x, carry = %d\n", ah,
3261ae115bc7Smrj             ret & CB ? 1 : 0);
3262ae115bc7Smrj 
3263ae115bc7Smrj         return (1);
3264ae115bc7Smrj }
3265ae115bc7Smrj 
3266ae115bc7Smrj 
3267ae115bc7Smrj int
3268ae115bc7Smrj isamd64()
3269ae115bc7Smrj {
3270ae115bc7Smrj 	static int ret = -1;
3271ae115bc7Smrj 
3272ae115bc7Smrj 	if (ret == -1)
3273ae115bc7Smrj 		ret = amd64_config_cpu();
3274ae115bc7Smrj 
3275ae115bc7Smrj 	return (ret);
3276ae115bc7Smrj }
3277ae115bc7Smrj 
3278b1b8ab34Slling static void
3279b1b8ab34Slling expand_arch (char *arg, char *newarg)
3280ae115bc7Smrj {
3281ae115bc7Smrj   char *index;
3282ae115bc7Smrj 
3283ae115bc7Smrj   newarg[0] = '\0';
3284ae115bc7Smrj 
3285ae115bc7Smrj   while ((index = strstr(arg, "$ISADIR")) != NULL) {
3286ae115bc7Smrj 
3287ae115bc7Smrj     index[0] = '\0';
3288ae115bc7Smrj     strncat(newarg, arg, MAX_CMDLINE);
3289ae115bc7Smrj     index[0] = '$';
3290ae115bc7Smrj 
3291342440ecSPrasad Singamsetty     if (isamd64() && check_min_mem64())
3292ae115bc7Smrj       strncat(newarg, "amd64", MAX_CMDLINE);
3293ae115bc7Smrj 
3294ae115bc7Smrj     arg = index + 7;
3295ae115bc7Smrj   }
3296ae115bc7Smrj 
3297ae115bc7Smrj   strncat(newarg, arg, MAX_CMDLINE);
3298b1b8ab34Slling   return;
3299ae115bc7Smrj }
3300ae115bc7Smrj 
3301ae115bc7Smrj /* kernel$ */
3302ae115bc7Smrj static int
3303ae115bc7Smrj kernel_dollar_func (char *arg, int flags)
3304ae115bc7Smrj {
3305b1b8ab34Slling   char newarg[MAX_CMDLINE];	/* everything boils down to MAX_CMDLINE */
3306b1b8ab34Slling 
3307b1b8ab34Slling   grub_printf("loading '%s' ...\n", arg);
3308b1b8ab34Slling   expand_arch(arg, newarg);
3309b1b8ab34Slling 
3310b1b8ab34Slling   if (kernel_func(newarg, flags))
3311b1b8ab34Slling 	return (1);
3312b1b8ab34Slling 
3313b1b8ab34Slling   mb_cmdline = (char *)MB_CMDLINE_BUF;
3314ffb5616eSLin Ling   if (expand_dollar_bootfs(newarg, mb_cmdline)) {
3315ffb5616eSLin Ling 	grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
3316ffb5616eSLin Ling 	    current_bootfs);
3317b1b8ab34Slling 	return (1);
3318ffb5616eSLin Ling   }
3319b1b8ab34Slling 
3320b1b8ab34Slling   grub_printf("'%s' is loaded\n", mb_cmdline);
3321b1b8ab34Slling   mb_cmdline += grub_strlen(mb_cmdline) + 1;
3322b1b8ab34Slling 
3323b1b8ab34Slling   return (0);
3324ae115bc7Smrj }
3325ae115bc7Smrj 
3326ae115bc7Smrj static struct builtin builtin_kernel_dollar =
3327ae115bc7Smrj {
3328ae115bc7Smrj   "kernel$",
3329ae115bc7Smrj   kernel_dollar_func,
3330ae115bc7Smrj   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3331ae115bc7Smrj   "kernel$ [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
3332ae115bc7Smrj   " Just like kernel, but with $ISADIR expansion."
3333ae115bc7Smrj };
3334ae115bc7Smrj 
33357c478bd9Sstevel@tonic-gate 
33367c478bd9Sstevel@tonic-gate /* lock */
33377c478bd9Sstevel@tonic-gate static int
33387c478bd9Sstevel@tonic-gate lock_func (char *arg, int flags)
33397c478bd9Sstevel@tonic-gate {
33407c478bd9Sstevel@tonic-gate   if (! auth && password)
33417c478bd9Sstevel@tonic-gate     {
33427c478bd9Sstevel@tonic-gate       errnum = ERR_PRIVILEGED;
33437c478bd9Sstevel@tonic-gate       return 1;
33447c478bd9Sstevel@tonic-gate     }
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate   return 0;
33477c478bd9Sstevel@tonic-gate }
33487c478bd9Sstevel@tonic-gate 
33497c478bd9Sstevel@tonic-gate static struct builtin builtin_lock =
33507c478bd9Sstevel@tonic-gate {
33517c478bd9Sstevel@tonic-gate   "lock",
33527c478bd9Sstevel@tonic-gate   lock_func,
33537c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
33547c478bd9Sstevel@tonic-gate   "lock",
33557c478bd9Sstevel@tonic-gate   "Break a command execution unless the user is authenticated."
33567c478bd9Sstevel@tonic-gate };
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 
33597c478bd9Sstevel@tonic-gate /* makeactive */
33607c478bd9Sstevel@tonic-gate static int
33617c478bd9Sstevel@tonic-gate makeactive_func (char *arg, int flags)
33627c478bd9Sstevel@tonic-gate {
33637c478bd9Sstevel@tonic-gate   if (! make_saved_active ())
33647c478bd9Sstevel@tonic-gate     return 1;
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate   return 0;
33677c478bd9Sstevel@tonic-gate }
33687c478bd9Sstevel@tonic-gate 
33697c478bd9Sstevel@tonic-gate static struct builtin builtin_makeactive =
33707c478bd9Sstevel@tonic-gate {
33717c478bd9Sstevel@tonic-gate   "makeactive",
33727c478bd9Sstevel@tonic-gate   makeactive_func,
33737c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
33747c478bd9Sstevel@tonic-gate   "makeactive",
33757c478bd9Sstevel@tonic-gate   "Set the active partition on the root disk to GRUB's root device."
33767c478bd9Sstevel@tonic-gate   " This command is limited to _primary_ PC partitions on a hard disk."
33777c478bd9Sstevel@tonic-gate };
33787c478bd9Sstevel@tonic-gate 
33797c478bd9Sstevel@tonic-gate 
33807c478bd9Sstevel@tonic-gate /* map */
33817c478bd9Sstevel@tonic-gate /* Map FROM_DRIVE to TO_DRIVE.  */
33827c478bd9Sstevel@tonic-gate static int
33837c478bd9Sstevel@tonic-gate map_func (char *arg, int flags)
33847c478bd9Sstevel@tonic-gate {
33857c478bd9Sstevel@tonic-gate   char *to_drive;
33867c478bd9Sstevel@tonic-gate   char *from_drive;
33877c478bd9Sstevel@tonic-gate   unsigned long to, from;
33887c478bd9Sstevel@tonic-gate   int i;
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate   to_drive = arg;
33917c478bd9Sstevel@tonic-gate   from_drive = skip_to (0, arg);
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate   /* Get the drive number for TO_DRIVE.  */
33947c478bd9Sstevel@tonic-gate   set_device (to_drive);
33957c478bd9Sstevel@tonic-gate   if (errnum)
33967c478bd9Sstevel@tonic-gate     return 1;
33977c478bd9Sstevel@tonic-gate   to = current_drive;
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate   /* Get the drive number for FROM_DRIVE.  */
34007c478bd9Sstevel@tonic-gate   set_device (from_drive);
34017c478bd9Sstevel@tonic-gate   if (errnum)
34027c478bd9Sstevel@tonic-gate     return 1;
34037c478bd9Sstevel@tonic-gate   from = current_drive;
34047c478bd9Sstevel@tonic-gate 
34057c478bd9Sstevel@tonic-gate   /* Search for an empty slot in BIOS_DRIVE_MAP.  */
34067c478bd9Sstevel@tonic-gate   for (i = 0; i < DRIVE_MAP_SIZE; i++)
34077c478bd9Sstevel@tonic-gate     {
34087c478bd9Sstevel@tonic-gate       /* Perhaps the user wants to override the map.  */
34097c478bd9Sstevel@tonic-gate       if ((bios_drive_map[i] & 0xff) == from)
34107c478bd9Sstevel@tonic-gate 	break;
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate       if (! bios_drive_map[i])
34137c478bd9Sstevel@tonic-gate 	break;
34147c478bd9Sstevel@tonic-gate     }
34157c478bd9Sstevel@tonic-gate 
34167c478bd9Sstevel@tonic-gate   if (i == DRIVE_MAP_SIZE)
34177c478bd9Sstevel@tonic-gate     {
34187c478bd9Sstevel@tonic-gate       errnum = ERR_WONT_FIT;
34197c478bd9Sstevel@tonic-gate       return 1;
34207c478bd9Sstevel@tonic-gate     }
34217c478bd9Sstevel@tonic-gate 
34227c478bd9Sstevel@tonic-gate   if (to == from)
34237c478bd9Sstevel@tonic-gate     /* If TO is equal to FROM, delete the entry.  */
34247c478bd9Sstevel@tonic-gate     grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i + 1],
34257c478bd9Sstevel@tonic-gate 		  sizeof (unsigned short) * (DRIVE_MAP_SIZE - i));
34267c478bd9Sstevel@tonic-gate   else
34277c478bd9Sstevel@tonic-gate     bios_drive_map[i] = from | (to << 8);
34287c478bd9Sstevel@tonic-gate 
34297c478bd9Sstevel@tonic-gate   return 0;
34307c478bd9Sstevel@tonic-gate }
34317c478bd9Sstevel@tonic-gate 
34327c478bd9Sstevel@tonic-gate static struct builtin builtin_map =
34337c478bd9Sstevel@tonic-gate {
34347c478bd9Sstevel@tonic-gate   "map",
34357c478bd9Sstevel@tonic-gate   map_func,
34367c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
34377c478bd9Sstevel@tonic-gate   "map TO_DRIVE FROM_DRIVE",
34387c478bd9Sstevel@tonic-gate   "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
34397c478bd9Sstevel@tonic-gate   " when you chain-load some operating systems, such as DOS, if such an"
34407c478bd9Sstevel@tonic-gate   " OS resides at a non-first drive."
34417c478bd9Sstevel@tonic-gate };
34427c478bd9Sstevel@tonic-gate 
34437c478bd9Sstevel@tonic-gate 
34447c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
34457c478bd9Sstevel@tonic-gate /* md5crypt */
34467c478bd9Sstevel@tonic-gate static int
34477c478bd9Sstevel@tonic-gate md5crypt_func (char *arg, int flags)
34487c478bd9Sstevel@tonic-gate {
34497c478bd9Sstevel@tonic-gate   char crypted[36];
34507c478bd9Sstevel@tonic-gate   char key[32];
34517c478bd9Sstevel@tonic-gate   unsigned int seed;
34527c478bd9Sstevel@tonic-gate   int i;
34537c478bd9Sstevel@tonic-gate   const char *const seedchars =
34547c478bd9Sstevel@tonic-gate     "./0123456789ABCDEFGHIJKLMNOPQRST"
34557c478bd9Sstevel@tonic-gate     "UVWXYZabcdefghijklmnopqrstuvwxyz";
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate   /* First create a salt.  */
34587c478bd9Sstevel@tonic-gate 
34597c478bd9Sstevel@tonic-gate   /* The magical prefix.  */
34607c478bd9Sstevel@tonic-gate   grub_memset (crypted, 0, sizeof (crypted));
34617c478bd9Sstevel@tonic-gate   grub_memmove (crypted, "$1$", 3);
34627c478bd9Sstevel@tonic-gate 
34637c478bd9Sstevel@tonic-gate   /* Create the length of a salt.  */
34647c478bd9Sstevel@tonic-gate   seed = currticks ();
34657c478bd9Sstevel@tonic-gate 
34667c478bd9Sstevel@tonic-gate   /* Generate a salt.  */
34677c478bd9Sstevel@tonic-gate   for (i = 0; i < 8 && seed; i++)
34687c478bd9Sstevel@tonic-gate     {
34697c478bd9Sstevel@tonic-gate       /* FIXME: This should be more random.  */
34707c478bd9Sstevel@tonic-gate       crypted[3 + i] = seedchars[seed & 0x3f];
34717c478bd9Sstevel@tonic-gate       seed >>= 6;
34727c478bd9Sstevel@tonic-gate     }
34737c478bd9Sstevel@tonic-gate 
34747c478bd9Sstevel@tonic-gate   /* A salt must be terminated with `$', if it is less than 8 chars.  */
34757c478bd9Sstevel@tonic-gate   crypted[3 + i] = '$';
34767c478bd9Sstevel@tonic-gate 
34777c478bd9Sstevel@tonic-gate #ifdef DEBUG_MD5CRYPT
34787c478bd9Sstevel@tonic-gate   grub_printf ("salt = %s\n", crypted);
34797c478bd9Sstevel@tonic-gate #endif
34807c478bd9Sstevel@tonic-gate 
34817c478bd9Sstevel@tonic-gate   /* Get a password.  */
34827c478bd9Sstevel@tonic-gate   grub_memset (key, 0, sizeof (key));
34837c478bd9Sstevel@tonic-gate   get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
34847c478bd9Sstevel@tonic-gate 
34857c478bd9Sstevel@tonic-gate   /* Crypt the key.  */
34867c478bd9Sstevel@tonic-gate   make_md5_password (key, crypted);
34877c478bd9Sstevel@tonic-gate 
34887c478bd9Sstevel@tonic-gate   grub_printf ("Encrypted: %s\n", crypted);
34897c478bd9Sstevel@tonic-gate   return 0;
34907c478bd9Sstevel@tonic-gate }
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate static struct builtin builtin_md5crypt =
34937c478bd9Sstevel@tonic-gate {
34947c478bd9Sstevel@tonic-gate   "md5crypt",
34957c478bd9Sstevel@tonic-gate   md5crypt_func,
34967c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
34977c478bd9Sstevel@tonic-gate   "md5crypt",
34987c478bd9Sstevel@tonic-gate   "Generate a password in MD5 format."
34997c478bd9Sstevel@tonic-gate };
35007c478bd9Sstevel@tonic-gate #endif /* USE_MD5_PASSWORDS */
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 
35037c478bd9Sstevel@tonic-gate /* module */
35047c478bd9Sstevel@tonic-gate static int
35057c478bd9Sstevel@tonic-gate module_func (char *arg, int flags)
35067c478bd9Sstevel@tonic-gate {
35077c478bd9Sstevel@tonic-gate   int len = grub_strlen (arg);
35087c478bd9Sstevel@tonic-gate 
35097c478bd9Sstevel@tonic-gate   switch (kernel_type)
35107c478bd9Sstevel@tonic-gate     {
35117c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_MULTIBOOT:
35127c478bd9Sstevel@tonic-gate       if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN)
35137c478bd9Sstevel@tonic-gate 	{
35147c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
35157c478bd9Sstevel@tonic-gate 	  return 1;
35167c478bd9Sstevel@tonic-gate 	}
35177c478bd9Sstevel@tonic-gate       grub_memmove (mb_cmdline, arg, len + 1);
35187c478bd9Sstevel@tonic-gate       if (! load_module (arg, mb_cmdline))
35197c478bd9Sstevel@tonic-gate 	return 1;
3520b1b8ab34Slling 
3521b1b8ab34Slling       mb_cmdline += grub_strlen(mb_cmdline) + 1;
35227c478bd9Sstevel@tonic-gate       break;
35237c478bd9Sstevel@tonic-gate 
35247c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
35257c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
35267c478bd9Sstevel@tonic-gate       if (! load_initrd (arg))
35277c478bd9Sstevel@tonic-gate 	return 1;
35287c478bd9Sstevel@tonic-gate       break;
35297c478bd9Sstevel@tonic-gate 
35307c478bd9Sstevel@tonic-gate     default:
35317c478bd9Sstevel@tonic-gate       errnum = ERR_NEED_MB_KERNEL;
35327c478bd9Sstevel@tonic-gate       return 1;
35337c478bd9Sstevel@tonic-gate     }
35347c478bd9Sstevel@tonic-gate 
35357c478bd9Sstevel@tonic-gate   return 0;
35367c478bd9Sstevel@tonic-gate }
35377c478bd9Sstevel@tonic-gate 
35387c478bd9Sstevel@tonic-gate static struct builtin builtin_module =
35397c478bd9Sstevel@tonic-gate {
35407c478bd9Sstevel@tonic-gate   "module",
35417c478bd9Sstevel@tonic-gate   module_func,
35427c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
35437c478bd9Sstevel@tonic-gate   "module FILE [ARG ...]",
35447c478bd9Sstevel@tonic-gate   "Load a boot module FILE for a Multiboot format boot image (no"
35457c478bd9Sstevel@tonic-gate   " interpretation of the file contents is made, so users of this"
35467c478bd9Sstevel@tonic-gate   " command must know what the kernel in question expects). The"
35477c478bd9Sstevel@tonic-gate   " rest of the line is passed as the \"module command line\", like"
35487c478bd9Sstevel@tonic-gate   " the `kernel' command."
35497c478bd9Sstevel@tonic-gate };
35507c478bd9Sstevel@tonic-gate 
3551ae115bc7Smrj /* module$ */
3552ae115bc7Smrj static int
3553ae115bc7Smrj module_dollar_func (char *arg, int flags)
3554ae115bc7Smrj {
3555b1b8ab34Slling   char newarg[MAX_CMDLINE];	/* everything boils down to MAX_CMDLINE */
3556b1b8ab34Slling   char *cmdline_sav;
3557b1b8ab34Slling 
3558b1b8ab34Slling   grub_printf("loading '%s' ...\n", arg);
3559b1b8ab34Slling   expand_arch(arg, newarg);
3560b1b8ab34Slling 
3561b1b8ab34Slling   cmdline_sav = (char *)mb_cmdline;
3562b1b8ab34Slling   if (module_func(newarg, flags))
3563b1b8ab34Slling 	return (1);
3564b1b8ab34Slling 
3565ffb5616eSLin Ling   if (expand_dollar_bootfs(newarg, cmdline_sav)) {
3566ffb5616eSLin Ling 	grub_printf("cannot expand $ZFS-BOOTFS for dataset %s\n",
3567ffb5616eSLin Ling 	    current_bootfs);
3568b1b8ab34Slling 	return (1);
3569ffb5616eSLin Ling   }
3570b1b8ab34Slling 
3571b1b8ab34Slling   grub_printf("'%s' is loaded\n", (char *)cmdline_sav);
3572b1b8ab34Slling   mb_cmdline += grub_strlen(cmdline_sav) + 1;
3573b1b8ab34Slling 
3574b1b8ab34Slling   return (0);
3575ae115bc7Smrj }
3576ae115bc7Smrj 
3577ae115bc7Smrj static struct builtin builtin_module_dollar =
3578ae115bc7Smrj {
3579ae115bc7Smrj   "module$",
3580ae115bc7Smrj   module_dollar_func,
3581ae115bc7Smrj   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3582ae115bc7Smrj   "module FILE [ARG ...]",
3583ae115bc7Smrj   " Just like module, but with $ISADIR expansion."
3584ae115bc7Smrj };
3585ae115bc7Smrj 
35867c478bd9Sstevel@tonic-gate 
35877c478bd9Sstevel@tonic-gate /* modulenounzip */
35887c478bd9Sstevel@tonic-gate static int
35897c478bd9Sstevel@tonic-gate modulenounzip_func (char *arg, int flags)
35907c478bd9Sstevel@tonic-gate {
35917c478bd9Sstevel@tonic-gate   int ret;
35927c478bd9Sstevel@tonic-gate 
35937c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
35947c478bd9Sstevel@tonic-gate   no_decompression = 1;
35957c478bd9Sstevel@tonic-gate #endif
35967c478bd9Sstevel@tonic-gate 
35977c478bd9Sstevel@tonic-gate   ret = module_func (arg, flags);
35987c478bd9Sstevel@tonic-gate 
35997c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
36007c478bd9Sstevel@tonic-gate   no_decompression = 0;
36017c478bd9Sstevel@tonic-gate #endif
36027c478bd9Sstevel@tonic-gate 
36037c478bd9Sstevel@tonic-gate   return ret;
36047c478bd9Sstevel@tonic-gate }
36057c478bd9Sstevel@tonic-gate 
36067c478bd9Sstevel@tonic-gate static struct builtin builtin_modulenounzip =
36077c478bd9Sstevel@tonic-gate {
36087c478bd9Sstevel@tonic-gate   "modulenounzip",
36097c478bd9Sstevel@tonic-gate   modulenounzip_func,
36107c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
36117c478bd9Sstevel@tonic-gate   "modulenounzip FILE [ARG ...]",
36127c478bd9Sstevel@tonic-gate   "The same as `module', except that automatic decompression is"
36137c478bd9Sstevel@tonic-gate   " disabled."
36147c478bd9Sstevel@tonic-gate };
36157c478bd9Sstevel@tonic-gate 
36167c478bd9Sstevel@tonic-gate 
36177c478bd9Sstevel@tonic-gate /* pager [on|off] */
36187c478bd9Sstevel@tonic-gate static int
36197c478bd9Sstevel@tonic-gate pager_func (char *arg, int flags)
36207c478bd9Sstevel@tonic-gate {
36217c478bd9Sstevel@tonic-gate   /* If ARG is empty, toggle the flag.  */
36227c478bd9Sstevel@tonic-gate   if (! *arg)
36237c478bd9Sstevel@tonic-gate     use_pager = ! use_pager;
36247c478bd9Sstevel@tonic-gate   else if (grub_memcmp (arg, "on", 2) == 0)
36257c478bd9Sstevel@tonic-gate     use_pager = 1;
36267c478bd9Sstevel@tonic-gate   else if (grub_memcmp (arg, "off", 3) == 0)
36277c478bd9Sstevel@tonic-gate     use_pager = 0;
36287c478bd9Sstevel@tonic-gate   else
36297c478bd9Sstevel@tonic-gate     {
36307c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36317c478bd9Sstevel@tonic-gate       return 1;
36327c478bd9Sstevel@tonic-gate     }
36337c478bd9Sstevel@tonic-gate 
36347c478bd9Sstevel@tonic-gate   grub_printf (" Internal pager is now %s\n", use_pager ? "on" : "off");
36357c478bd9Sstevel@tonic-gate   return 0;
36367c478bd9Sstevel@tonic-gate }
36377c478bd9Sstevel@tonic-gate 
36387c478bd9Sstevel@tonic-gate static struct builtin builtin_pager =
36397c478bd9Sstevel@tonic-gate {
36407c478bd9Sstevel@tonic-gate   "pager",
36417c478bd9Sstevel@tonic-gate   pager_func,
36427c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
36437c478bd9Sstevel@tonic-gate   "pager [FLAG]",
36447c478bd9Sstevel@tonic-gate   "Toggle pager mode with no argument. If FLAG is given and its value"
36457c478bd9Sstevel@tonic-gate   " is `on', turn on the mode. If FLAG is `off', turn off the mode."
36467c478bd9Sstevel@tonic-gate };
36477c478bd9Sstevel@tonic-gate 
36487c478bd9Sstevel@tonic-gate 
36497c478bd9Sstevel@tonic-gate /* partnew PART TYPE START LEN */
36507c478bd9Sstevel@tonic-gate static int
36517c478bd9Sstevel@tonic-gate partnew_func (char *arg, int flags)
36527c478bd9Sstevel@tonic-gate {
36537c478bd9Sstevel@tonic-gate   int new_type, new_start, new_len;
36547c478bd9Sstevel@tonic-gate   int start_cl, start_ch, start_dh;
36557c478bd9Sstevel@tonic-gate   int end_cl, end_ch, end_dh;
36567c478bd9Sstevel@tonic-gate   int entry;
36577c478bd9Sstevel@tonic-gate   char mbr[512];
36587c478bd9Sstevel@tonic-gate 
36597c478bd9Sstevel@tonic-gate   /* Convert a LBA address to a CHS address in the INT 13 format.  */
36607c478bd9Sstevel@tonic-gate   auto void lba_to_chs (int lba, int *cl, int *ch, int *dh);
36617c478bd9Sstevel@tonic-gate   void lba_to_chs (int lba, int *cl, int *ch, int *dh)
36627c478bd9Sstevel@tonic-gate     {
36637c478bd9Sstevel@tonic-gate       int cylinder, head, sector;
36647c478bd9Sstevel@tonic-gate 
36657c478bd9Sstevel@tonic-gate       sector = lba % buf_geom.sectors + 1;
36667c478bd9Sstevel@tonic-gate       head = (lba / buf_geom.sectors) % buf_geom.heads;
36677c478bd9Sstevel@tonic-gate       cylinder = lba / (buf_geom.sectors * buf_geom.heads);
36687c478bd9Sstevel@tonic-gate 
36697c478bd9Sstevel@tonic-gate       if (cylinder >= buf_geom.cylinders)
36707c478bd9Sstevel@tonic-gate 	cylinder = buf_geom.cylinders - 1;
36717c478bd9Sstevel@tonic-gate 
36727c478bd9Sstevel@tonic-gate       *cl = sector | ((cylinder & 0x300) >> 2);
36737c478bd9Sstevel@tonic-gate       *ch = cylinder & 0xFF;
36747c478bd9Sstevel@tonic-gate       *dh = head;
36757c478bd9Sstevel@tonic-gate     }
36767c478bd9Sstevel@tonic-gate 
36777c478bd9Sstevel@tonic-gate   /* Get the drive and the partition.  */
36787c478bd9Sstevel@tonic-gate   if (! set_device (arg))
36797c478bd9Sstevel@tonic-gate     return 1;
36807c478bd9Sstevel@tonic-gate 
36817c478bd9Sstevel@tonic-gate   /* The drive must be a hard disk.  */
36827c478bd9Sstevel@tonic-gate   if (! (current_drive & 0x80))
36837c478bd9Sstevel@tonic-gate     {
36847c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36857c478bd9Sstevel@tonic-gate       return 1;
36867c478bd9Sstevel@tonic-gate     }
36877c478bd9Sstevel@tonic-gate 
36887c478bd9Sstevel@tonic-gate   /* The partition must a primary partition.  */
36897c478bd9Sstevel@tonic-gate   if ((current_partition >> 16) > 3
36907c478bd9Sstevel@tonic-gate       || (current_partition & 0xFFFF) != 0xFFFF)
36917c478bd9Sstevel@tonic-gate     {
36927c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
36937c478bd9Sstevel@tonic-gate       return 1;
36947c478bd9Sstevel@tonic-gate     }
36957c478bd9Sstevel@tonic-gate 
36967c478bd9Sstevel@tonic-gate   entry = current_partition >> 16;
36977c478bd9Sstevel@tonic-gate 
36987c478bd9Sstevel@tonic-gate   /* Get the new partition type.  */
36997c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
37007c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_type))
37017c478bd9Sstevel@tonic-gate     return 1;
37027c478bd9Sstevel@tonic-gate 
37037c478bd9Sstevel@tonic-gate   /* The partition type is unsigned char.  */
37047c478bd9Sstevel@tonic-gate   if (new_type > 0xFF)
37057c478bd9Sstevel@tonic-gate     {
37067c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37077c478bd9Sstevel@tonic-gate       return 1;
37087c478bd9Sstevel@tonic-gate     }
37097c478bd9Sstevel@tonic-gate 
37107c478bd9Sstevel@tonic-gate   /* Get the new partition start.  */
37117c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
37127c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_start))
37137c478bd9Sstevel@tonic-gate     return 1;
37147c478bd9Sstevel@tonic-gate 
37157c478bd9Sstevel@tonic-gate   /* Get the new partition length.  */
37167c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
37177c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_len))
37187c478bd9Sstevel@tonic-gate     return 1;
37197c478bd9Sstevel@tonic-gate 
37207c478bd9Sstevel@tonic-gate   /* Read the MBR.  */
37217c478bd9Sstevel@tonic-gate   if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr))
37227c478bd9Sstevel@tonic-gate     return 1;
37237c478bd9Sstevel@tonic-gate 
37247c478bd9Sstevel@tonic-gate   /* Check if the new partition will fit in the disk.  */
37257c478bd9Sstevel@tonic-gate   if (new_start + new_len > buf_geom.total_sectors)
37267c478bd9Sstevel@tonic-gate     {
37277c478bd9Sstevel@tonic-gate       errnum = ERR_GEOM;
37287c478bd9Sstevel@tonic-gate       return 1;
37297c478bd9Sstevel@tonic-gate     }
37307c478bd9Sstevel@tonic-gate 
37317c478bd9Sstevel@tonic-gate   /* Store the partition information in the MBR.  */
37327c478bd9Sstevel@tonic-gate   lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
37337c478bd9Sstevel@tonic-gate   lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
37347c478bd9Sstevel@tonic-gate 
37357c478bd9Sstevel@tonic-gate   PC_SLICE_FLAG (mbr, entry) = 0;
37367c478bd9Sstevel@tonic-gate   PC_SLICE_HEAD (mbr, entry) = start_dh;
37377c478bd9Sstevel@tonic-gate   PC_SLICE_SEC (mbr, entry) = start_cl;
37387c478bd9Sstevel@tonic-gate   PC_SLICE_CYL (mbr, entry) = start_ch;
37397c478bd9Sstevel@tonic-gate   PC_SLICE_TYPE (mbr, entry) = new_type;
37407c478bd9Sstevel@tonic-gate   PC_SLICE_EHEAD (mbr, entry) = end_dh;
37417c478bd9Sstevel@tonic-gate   PC_SLICE_ESEC (mbr, entry) = end_cl;
37427c478bd9Sstevel@tonic-gate   PC_SLICE_ECYL (mbr, entry) = end_ch;
37437c478bd9Sstevel@tonic-gate   PC_SLICE_START (mbr, entry) = new_start;
37447c478bd9Sstevel@tonic-gate   PC_SLICE_LENGTH (mbr, entry) = new_len;
37457c478bd9Sstevel@tonic-gate 
37467c478bd9Sstevel@tonic-gate   /* Make sure that the MBR has a valid signature.  */
37477c478bd9Sstevel@tonic-gate   PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
37487c478bd9Sstevel@tonic-gate 
37497c478bd9Sstevel@tonic-gate   /* Write back the MBR to the disk.  */
3750342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
37517c478bd9Sstevel@tonic-gate   if (! rawwrite (current_drive, 0, mbr))
37527c478bd9Sstevel@tonic-gate     return 1;
37537c478bd9Sstevel@tonic-gate 
37547c478bd9Sstevel@tonic-gate   return 0;
37557c478bd9Sstevel@tonic-gate }
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate static struct builtin builtin_partnew =
37587c478bd9Sstevel@tonic-gate {
37597c478bd9Sstevel@tonic-gate   "partnew",
37607c478bd9Sstevel@tonic-gate   partnew_func,
37617c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
37627c478bd9Sstevel@tonic-gate   "partnew PART TYPE START LEN",
37637c478bd9Sstevel@tonic-gate   "Create a primary partition at the starting address START with the"
37647c478bd9Sstevel@tonic-gate   " length LEN, with the type TYPE. START and LEN are in sector units."
37657c478bd9Sstevel@tonic-gate };
37667c478bd9Sstevel@tonic-gate 
37677c478bd9Sstevel@tonic-gate 
37687c478bd9Sstevel@tonic-gate /* parttype PART TYPE */
37697c478bd9Sstevel@tonic-gate static int
37707c478bd9Sstevel@tonic-gate parttype_func (char *arg, int flags)
37717c478bd9Sstevel@tonic-gate {
37727c478bd9Sstevel@tonic-gate   int new_type;
37737c478bd9Sstevel@tonic-gate   unsigned long part = 0xFFFFFF;
37747c478bd9Sstevel@tonic-gate   unsigned long start, len, offset, ext_offset;
37757c478bd9Sstevel@tonic-gate   int entry, type;
37767c478bd9Sstevel@tonic-gate   char mbr[512];
37777c478bd9Sstevel@tonic-gate 
37787c478bd9Sstevel@tonic-gate   /* Get the drive and the partition.  */
37797c478bd9Sstevel@tonic-gate   if (! set_device (arg))
37807c478bd9Sstevel@tonic-gate     return 1;
37817c478bd9Sstevel@tonic-gate 
37827c478bd9Sstevel@tonic-gate   /* The drive must be a hard disk.  */
37837c478bd9Sstevel@tonic-gate   if (! (current_drive & 0x80))
37847c478bd9Sstevel@tonic-gate     {
37857c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37867c478bd9Sstevel@tonic-gate       return 1;
37877c478bd9Sstevel@tonic-gate     }
37887c478bd9Sstevel@tonic-gate 
37897c478bd9Sstevel@tonic-gate   /* The partition must be a PC slice.  */
37907c478bd9Sstevel@tonic-gate   if ((current_partition >> 16) == 0xFF
37917c478bd9Sstevel@tonic-gate       || (current_partition & 0xFFFF) != 0xFFFF)
37927c478bd9Sstevel@tonic-gate     {
37937c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
37947c478bd9Sstevel@tonic-gate       return 1;
37957c478bd9Sstevel@tonic-gate     }
37967c478bd9Sstevel@tonic-gate 
37977c478bd9Sstevel@tonic-gate   /* Get the new partition type.  */
37987c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
37997c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_type))
38007c478bd9Sstevel@tonic-gate     return 1;
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate   /* The partition type is unsigned char.  */
38037c478bd9Sstevel@tonic-gate   if (new_type > 0xFF)
38047c478bd9Sstevel@tonic-gate     {
38057c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
38067c478bd9Sstevel@tonic-gate       return 1;
38077c478bd9Sstevel@tonic-gate     }
38087c478bd9Sstevel@tonic-gate 
38097c478bd9Sstevel@tonic-gate   /* Look for the partition.  */
38107c478bd9Sstevel@tonic-gate   while (next_partition (current_drive, 0xFFFFFF, &part, &type,
38117c478bd9Sstevel@tonic-gate 			 &start, &len, &offset, &entry,
38127c478bd9Sstevel@tonic-gate 			 &ext_offset, mbr))
38137c478bd9Sstevel@tonic-gate     {
38147c478bd9Sstevel@tonic-gate       if (part == current_partition)
38157c478bd9Sstevel@tonic-gate 	{
38167c478bd9Sstevel@tonic-gate 	  /* Found.  */
38177c478bd9Sstevel@tonic-gate 
38187c478bd9Sstevel@tonic-gate 	  /* Set the type to NEW_TYPE.  */
38197c478bd9Sstevel@tonic-gate 	  PC_SLICE_TYPE (mbr, entry) = new_type;
38207c478bd9Sstevel@tonic-gate 
38217c478bd9Sstevel@tonic-gate 	  /* Write back the MBR to the disk.  */
3822342440ecSPrasad Singamsetty 	  buf_track = BUF_CACHE_INVALID;
38237c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, offset, mbr))
38247c478bd9Sstevel@tonic-gate 	    return 1;
38257c478bd9Sstevel@tonic-gate 
38267c478bd9Sstevel@tonic-gate 	  /* Succeed.  */
38277c478bd9Sstevel@tonic-gate 	  return 0;
38287c478bd9Sstevel@tonic-gate 	}
38297c478bd9Sstevel@tonic-gate     }
38307c478bd9Sstevel@tonic-gate 
38317c478bd9Sstevel@tonic-gate   /* The partition was not found.  ERRNUM was set by next_partition.  */
38327c478bd9Sstevel@tonic-gate   return 1;
38337c478bd9Sstevel@tonic-gate }
38347c478bd9Sstevel@tonic-gate 
38357c478bd9Sstevel@tonic-gate static struct builtin builtin_parttype =
38367c478bd9Sstevel@tonic-gate {
38377c478bd9Sstevel@tonic-gate   "parttype",
38387c478bd9Sstevel@tonic-gate   parttype_func,
38397c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
38407c478bd9Sstevel@tonic-gate   "parttype PART TYPE",
38417c478bd9Sstevel@tonic-gate   "Change the type of the partition PART to TYPE."
38427c478bd9Sstevel@tonic-gate };
38437c478bd9Sstevel@tonic-gate 
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate /* password */
38467c478bd9Sstevel@tonic-gate static int
38477c478bd9Sstevel@tonic-gate password_func (char *arg, int flags)
38487c478bd9Sstevel@tonic-gate {
38497c478bd9Sstevel@tonic-gate   int len;
38507c478bd9Sstevel@tonic-gate   password_t type = PASSWORD_PLAIN;
38517c478bd9Sstevel@tonic-gate 
38527c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
38537c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--md5", 5) == 0)
38547c478bd9Sstevel@tonic-gate     {
38557c478bd9Sstevel@tonic-gate       type = PASSWORD_MD5;
38567c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
38577c478bd9Sstevel@tonic-gate     }
38587c478bd9Sstevel@tonic-gate #endif
38597c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--", 2) == 0)
38607c478bd9Sstevel@tonic-gate     {
38617c478bd9Sstevel@tonic-gate       type = PASSWORD_UNSUPPORTED;
38627c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
38637c478bd9Sstevel@tonic-gate     }
38647c478bd9Sstevel@tonic-gate 
38657c478bd9Sstevel@tonic-gate   if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
38667c478bd9Sstevel@tonic-gate     {
38677c478bd9Sstevel@tonic-gate       /* Do password check! */
38687c478bd9Sstevel@tonic-gate       char entered[32];
38697c478bd9Sstevel@tonic-gate 
38707c478bd9Sstevel@tonic-gate       /* Wipe out any previously entered password */
38717c478bd9Sstevel@tonic-gate       entered[0] = 0;
38727c478bd9Sstevel@tonic-gate       get_cmdline ("Password: ", entered, 31, '*', 0);
38737c478bd9Sstevel@tonic-gate 
38747c478bd9Sstevel@tonic-gate       nul_terminate (arg);
38757c478bd9Sstevel@tonic-gate       if (check_password (entered, arg, type) != 0)
38767c478bd9Sstevel@tonic-gate 	{
38777c478bd9Sstevel@tonic-gate 	  errnum = ERR_PRIVILEGED;
38787c478bd9Sstevel@tonic-gate 	  return 1;
38797c478bd9Sstevel@tonic-gate 	}
38807c478bd9Sstevel@tonic-gate     }
38817c478bd9Sstevel@tonic-gate   else
38827c478bd9Sstevel@tonic-gate     {
38837c478bd9Sstevel@tonic-gate       len = grub_strlen (arg);
38847c478bd9Sstevel@tonic-gate 
38857c478bd9Sstevel@tonic-gate       /* PASSWORD NUL NUL ... */
38867c478bd9Sstevel@tonic-gate       if (len + 2 > PASSWORD_BUFLEN)
38877c478bd9Sstevel@tonic-gate 	{
38887c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
38897c478bd9Sstevel@tonic-gate 	  return 1;
38907c478bd9Sstevel@tonic-gate 	}
38917c478bd9Sstevel@tonic-gate 
38927c478bd9Sstevel@tonic-gate       /* Copy the password and clear the rest of the buffer.  */
38937c478bd9Sstevel@tonic-gate       password = (char *) PASSWORD_BUF;
38947c478bd9Sstevel@tonic-gate       grub_memmove (password, arg, len);
38957c478bd9Sstevel@tonic-gate       grub_memset (password + len, 0, PASSWORD_BUFLEN - len);
38967c478bd9Sstevel@tonic-gate       password_type = type;
38977c478bd9Sstevel@tonic-gate     }
38987c478bd9Sstevel@tonic-gate   return 0;
38997c478bd9Sstevel@tonic-gate }
39007c478bd9Sstevel@tonic-gate 
39017c478bd9Sstevel@tonic-gate static struct builtin builtin_password =
39027c478bd9Sstevel@tonic-gate {
39037c478bd9Sstevel@tonic-gate   "password",
39047c478bd9Sstevel@tonic-gate   password_func,
39057c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
39067c478bd9Sstevel@tonic-gate   "password [--md5] PASSWD [FILE]",
39077c478bd9Sstevel@tonic-gate   "If used in the first section of a menu file, disable all"
39087c478bd9Sstevel@tonic-gate   " interactive editing control (menu entry editor and"
39097c478bd9Sstevel@tonic-gate   " command line). If the password PASSWD is entered, it loads the"
39107c478bd9Sstevel@tonic-gate   " FILE as a new config file and restarts the GRUB Stage 2. If you"
39117c478bd9Sstevel@tonic-gate   " omit the argument FILE, then GRUB just unlocks privileged"
39127c478bd9Sstevel@tonic-gate   " instructions.  You can also use it in the script section, in"
39137c478bd9Sstevel@tonic-gate   " which case it will ask for the password, before continueing."
39147c478bd9Sstevel@tonic-gate   " The option --md5 tells GRUB that PASSWD is encrypted with"
39157c478bd9Sstevel@tonic-gate   " md5crypt."
39167c478bd9Sstevel@tonic-gate };
39177c478bd9Sstevel@tonic-gate 
39187c478bd9Sstevel@tonic-gate 
39197c478bd9Sstevel@tonic-gate /* pause */
39207c478bd9Sstevel@tonic-gate static int
39217c478bd9Sstevel@tonic-gate pause_func (char *arg, int flags)
39227c478bd9Sstevel@tonic-gate {
39237c478bd9Sstevel@tonic-gate   printf("%s\n", arg);
39247c478bd9Sstevel@tonic-gate 
39257c478bd9Sstevel@tonic-gate   /* If ESC is returned, then abort this entry.  */
39267c478bd9Sstevel@tonic-gate   if (ASCII_CHAR (getkey ()) == 27)
39277c478bd9Sstevel@tonic-gate     return 1;
39287c478bd9Sstevel@tonic-gate 
39297c478bd9Sstevel@tonic-gate   return 0;
39307c478bd9Sstevel@tonic-gate }
39317c478bd9Sstevel@tonic-gate 
39327c478bd9Sstevel@tonic-gate static struct builtin builtin_pause =
39337c478bd9Sstevel@tonic-gate {
39347c478bd9Sstevel@tonic-gate   "pause",
39357c478bd9Sstevel@tonic-gate   pause_func,
39367c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
39377c478bd9Sstevel@tonic-gate   "pause [MESSAGE ...]",
39387c478bd9Sstevel@tonic-gate   "Print MESSAGE, then wait until a key is pressed."
39397c478bd9Sstevel@tonic-gate };
39407c478bd9Sstevel@tonic-gate 
39417c478bd9Sstevel@tonic-gate 
39427c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
39437c478bd9Sstevel@tonic-gate /* quit */
39447c478bd9Sstevel@tonic-gate static int
39457c478bd9Sstevel@tonic-gate quit_func (char *arg, int flags)
39467c478bd9Sstevel@tonic-gate {
39477c478bd9Sstevel@tonic-gate   stop ();
39487c478bd9Sstevel@tonic-gate 
39497c478bd9Sstevel@tonic-gate   /* Never reach here.  */
39507c478bd9Sstevel@tonic-gate   return 0;
39517c478bd9Sstevel@tonic-gate }
39527c478bd9Sstevel@tonic-gate 
39537c478bd9Sstevel@tonic-gate static struct builtin builtin_quit =
39547c478bd9Sstevel@tonic-gate {
39557c478bd9Sstevel@tonic-gate   "quit",
39567c478bd9Sstevel@tonic-gate   quit_func,
39577c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
39587c478bd9Sstevel@tonic-gate   "quit",
39597c478bd9Sstevel@tonic-gate   "Exit from the GRUB shell."
39607c478bd9Sstevel@tonic-gate };
39617c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
39627c478bd9Sstevel@tonic-gate 
39637c478bd9Sstevel@tonic-gate 
39647c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
39657c478bd9Sstevel@tonic-gate /* rarp */
39667c478bd9Sstevel@tonic-gate static int
39677c478bd9Sstevel@tonic-gate rarp_func (char *arg, int flags)
39687c478bd9Sstevel@tonic-gate {
39697c478bd9Sstevel@tonic-gate   if (! rarp ())
39707c478bd9Sstevel@tonic-gate     {
39717c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
39727c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
39737c478bd9Sstevel@tonic-gate 
39747c478bd9Sstevel@tonic-gate       return 1;
39757c478bd9Sstevel@tonic-gate     }
39767c478bd9Sstevel@tonic-gate 
39777c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
39787c478bd9Sstevel@tonic-gate   print_network_configuration ();
39797c478bd9Sstevel@tonic-gate   return 0;
39807c478bd9Sstevel@tonic-gate }
39817c478bd9Sstevel@tonic-gate 
39827c478bd9Sstevel@tonic-gate static struct builtin builtin_rarp =
39837c478bd9Sstevel@tonic-gate {
39847c478bd9Sstevel@tonic-gate   "rarp",
39857c478bd9Sstevel@tonic-gate   rarp_func,
39867c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
39877c478bd9Sstevel@tonic-gate   "rarp",
39887c478bd9Sstevel@tonic-gate   "Initialize a network device via RARP."
39897c478bd9Sstevel@tonic-gate };
39907c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
39917c478bd9Sstevel@tonic-gate 
39927c478bd9Sstevel@tonic-gate 
39937c478bd9Sstevel@tonic-gate static int
39947c478bd9Sstevel@tonic-gate read_func (char *arg, int flags)
39957c478bd9Sstevel@tonic-gate {
39967c478bd9Sstevel@tonic-gate   int addr;
39977c478bd9Sstevel@tonic-gate 
39987c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &addr))
39997c478bd9Sstevel@tonic-gate     return 1;
40007c478bd9Sstevel@tonic-gate 
40017c478bd9Sstevel@tonic-gate   grub_printf ("Address 0x%x: Value 0x%x\n",
40027c478bd9Sstevel@tonic-gate 	       addr, *((unsigned *) RAW_ADDR (addr)));
40037c478bd9Sstevel@tonic-gate   return 0;
40047c478bd9Sstevel@tonic-gate }
40057c478bd9Sstevel@tonic-gate 
40067c478bd9Sstevel@tonic-gate static struct builtin builtin_read =
40077c478bd9Sstevel@tonic-gate {
40087c478bd9Sstevel@tonic-gate   "read",
40097c478bd9Sstevel@tonic-gate   read_func,
40107c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
40117c478bd9Sstevel@tonic-gate   "read ADDR",
40127c478bd9Sstevel@tonic-gate   "Read a 32-bit value from memory at address ADDR and"
40137c478bd9Sstevel@tonic-gate   " display it in hex format."
40147c478bd9Sstevel@tonic-gate };
40157c478bd9Sstevel@tonic-gate 
40167c478bd9Sstevel@tonic-gate 
40177c478bd9Sstevel@tonic-gate /* reboot */
40187c478bd9Sstevel@tonic-gate static int
40197c478bd9Sstevel@tonic-gate reboot_func (char *arg, int flags)
40207c478bd9Sstevel@tonic-gate {
40217c478bd9Sstevel@tonic-gate   grub_reboot ();
40227c478bd9Sstevel@tonic-gate 
40237c478bd9Sstevel@tonic-gate   /* Never reach here.  */
40247c478bd9Sstevel@tonic-gate   return 1;
40257c478bd9Sstevel@tonic-gate }
40267c478bd9Sstevel@tonic-gate 
40277c478bd9Sstevel@tonic-gate static struct builtin builtin_reboot =
40287c478bd9Sstevel@tonic-gate {
40297c478bd9Sstevel@tonic-gate   "reboot",
40307c478bd9Sstevel@tonic-gate   reboot_func,
40317c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
40327c478bd9Sstevel@tonic-gate   "reboot",
40337c478bd9Sstevel@tonic-gate   "Reboot your system."
40347c478bd9Sstevel@tonic-gate };
40357c478bd9Sstevel@tonic-gate 
40367c478bd9Sstevel@tonic-gate 
40377c478bd9Sstevel@tonic-gate /* Print the root device information.  */
40387c478bd9Sstevel@tonic-gate static void
40397c478bd9Sstevel@tonic-gate print_root_device (void)
40407c478bd9Sstevel@tonic-gate {
40417c478bd9Sstevel@tonic-gate   if (saved_drive == NETWORK_DRIVE)
40427c478bd9Sstevel@tonic-gate     {
40437c478bd9Sstevel@tonic-gate       /* Network drive.  */
40447c478bd9Sstevel@tonic-gate       grub_printf (" (nd):");
40457c478bd9Sstevel@tonic-gate     }
40467c478bd9Sstevel@tonic-gate   else if (saved_drive & 0x80)
40477c478bd9Sstevel@tonic-gate     {
40487c478bd9Sstevel@tonic-gate       /* Hard disk drive.  */
40497c478bd9Sstevel@tonic-gate       grub_printf (" (hd%d", saved_drive - 0x80);
40507c478bd9Sstevel@tonic-gate 
40517c478bd9Sstevel@tonic-gate       if ((saved_partition & 0xFF0000) != 0xFF0000)
40527c478bd9Sstevel@tonic-gate 	grub_printf (",%d", saved_partition >> 16);
40537c478bd9Sstevel@tonic-gate 
40547c478bd9Sstevel@tonic-gate       if ((saved_partition & 0x00FF00) != 0x00FF00)
40557c478bd9Sstevel@tonic-gate 	grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a');
40567c478bd9Sstevel@tonic-gate 
40577c478bd9Sstevel@tonic-gate       grub_printf ("):");
40587c478bd9Sstevel@tonic-gate     }
40597c478bd9Sstevel@tonic-gate   else
40607c478bd9Sstevel@tonic-gate     {
40617c478bd9Sstevel@tonic-gate       /* Floppy disk drive.  */
40627c478bd9Sstevel@tonic-gate       grub_printf (" (fd%d):", saved_drive);
40637c478bd9Sstevel@tonic-gate     }
40647c478bd9Sstevel@tonic-gate 
40657c478bd9Sstevel@tonic-gate   /* Print the filesystem information.  */
40667c478bd9Sstevel@tonic-gate   current_partition = saved_partition;
40677c478bd9Sstevel@tonic-gate   current_drive = saved_drive;
40687c478bd9Sstevel@tonic-gate   print_fsys_type ();
40697c478bd9Sstevel@tonic-gate }
40707c478bd9Sstevel@tonic-gate 
40717c478bd9Sstevel@tonic-gate static int
40727c478bd9Sstevel@tonic-gate real_root_func (char *arg, int attempt_mount)
40737c478bd9Sstevel@tonic-gate {
40747c478bd9Sstevel@tonic-gate   int hdbias = 0;
40757c478bd9Sstevel@tonic-gate   char *biasptr;
40767c478bd9Sstevel@tonic-gate   char *next;
40777c478bd9Sstevel@tonic-gate 
40787c478bd9Sstevel@tonic-gate   /* If ARG is empty, just print the current root device.  */
40797c478bd9Sstevel@tonic-gate   if (! *arg)
40807c478bd9Sstevel@tonic-gate     {
40817c478bd9Sstevel@tonic-gate       print_root_device ();
40827c478bd9Sstevel@tonic-gate       return 0;
40837c478bd9Sstevel@tonic-gate     }
40847c478bd9Sstevel@tonic-gate 
40857c478bd9Sstevel@tonic-gate   /* Call set_device to get the drive and the partition in ARG.  */
40867c478bd9Sstevel@tonic-gate   next = set_device (arg);
40877c478bd9Sstevel@tonic-gate   if (! next)
40887c478bd9Sstevel@tonic-gate     return 1;
40897c478bd9Sstevel@tonic-gate 
40907c478bd9Sstevel@tonic-gate   /* Ignore ERR_FSYS_MOUNT.  */
40917c478bd9Sstevel@tonic-gate   if (attempt_mount)
40927c478bd9Sstevel@tonic-gate     {
40937c478bd9Sstevel@tonic-gate       if (! open_device () && errnum != ERR_FSYS_MOUNT)
40947c478bd9Sstevel@tonic-gate 	return 1;
40957c478bd9Sstevel@tonic-gate     }
40967c478bd9Sstevel@tonic-gate   else
40977c478bd9Sstevel@tonic-gate     {
40987c478bd9Sstevel@tonic-gate       /* This is necessary, because the location of a partition table
40997c478bd9Sstevel@tonic-gate 	 must be set appropriately.  */
41007c478bd9Sstevel@tonic-gate       if (open_partition ())
41017c478bd9Sstevel@tonic-gate 	{
41027c478bd9Sstevel@tonic-gate 	  set_bootdev (0);
41037c478bd9Sstevel@tonic-gate 	  if (errnum)
41047c478bd9Sstevel@tonic-gate 	    return 1;
41057c478bd9Sstevel@tonic-gate 	}
41067c478bd9Sstevel@tonic-gate     }
41077c478bd9Sstevel@tonic-gate 
41087c478bd9Sstevel@tonic-gate   /* Clear ERRNUM.  */
41097c478bd9Sstevel@tonic-gate   errnum = 0;
41107c478bd9Sstevel@tonic-gate   saved_partition = current_partition;
41117c478bd9Sstevel@tonic-gate   saved_drive = current_drive;
41127c478bd9Sstevel@tonic-gate 
41137c478bd9Sstevel@tonic-gate   if (attempt_mount)
41147c478bd9Sstevel@tonic-gate     {
41157c478bd9Sstevel@tonic-gate       /* BSD and chainloading evil hacks !!  */
41167c478bd9Sstevel@tonic-gate       biasptr = skip_to (0, next);
41177c478bd9Sstevel@tonic-gate       safe_parse_maxint (&biasptr, &hdbias);
41187c478bd9Sstevel@tonic-gate       errnum = 0;
41197c478bd9Sstevel@tonic-gate       bootdev = set_bootdev (hdbias);
41207c478bd9Sstevel@tonic-gate       if (errnum)
41217c478bd9Sstevel@tonic-gate 	return 1;
41227c478bd9Sstevel@tonic-gate 
41237c478bd9Sstevel@tonic-gate       /* Print the type of the filesystem.  */
41247c478bd9Sstevel@tonic-gate       print_fsys_type ();
41257c478bd9Sstevel@tonic-gate     }
41267c478bd9Sstevel@tonic-gate 
41277c478bd9Sstevel@tonic-gate   return 0;
41287c478bd9Sstevel@tonic-gate }
41297c478bd9Sstevel@tonic-gate 
41307c478bd9Sstevel@tonic-gate static int
41317c478bd9Sstevel@tonic-gate root_func (char *arg, int flags)
41327c478bd9Sstevel@tonic-gate {
4133b1b8ab34Slling   is_zfs_mount = 0;
41347c478bd9Sstevel@tonic-gate   return real_root_func (arg, 1);
41357c478bd9Sstevel@tonic-gate }
41367c478bd9Sstevel@tonic-gate 
41377c478bd9Sstevel@tonic-gate static struct builtin builtin_root =
41387c478bd9Sstevel@tonic-gate {
41397c478bd9Sstevel@tonic-gate   "root",
41407c478bd9Sstevel@tonic-gate   root_func,
41417c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
41427c478bd9Sstevel@tonic-gate   "root [DEVICE [HDBIAS]]",
41437c478bd9Sstevel@tonic-gate   "Set the current \"root device\" to the device DEVICE, then"
41447c478bd9Sstevel@tonic-gate   " attempt to mount it to get the partition size (for passing the"
41457c478bd9Sstevel@tonic-gate   " partition descriptor in `ES:ESI', used by some chain-loaded"
41467c478bd9Sstevel@tonic-gate   " bootloaders), the BSD drive-type (for booting BSD kernels using"
41477c478bd9Sstevel@tonic-gate   " their native boot format), and correctly determine "
41487c478bd9Sstevel@tonic-gate   " the PC partition where a BSD sub-partition is located. The"
41497c478bd9Sstevel@tonic-gate   " optional HDBIAS parameter is a number to tell a BSD kernel"
41507c478bd9Sstevel@tonic-gate   " how many BIOS drive numbers are on controllers before the current"
41517c478bd9Sstevel@tonic-gate   " one. For example, if there is an IDE disk and a SCSI disk, and your"
41527c478bd9Sstevel@tonic-gate   " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."
41537c478bd9Sstevel@tonic-gate };
41547c478bd9Sstevel@tonic-gate 
4155eb2bd662Svikram 
4156eb2bd662Svikram /* findroot */
4157eb2bd662Svikram static int
4158eb2bd662Svikram findroot_func (char *arg, int flags)
4159eb2bd662Svikram {
4160eb2bd662Svikram   int ret;
4161eb2bd662Svikram   char root[32];
4162eb2bd662Svikram 
4163eb2bd662Svikram   if (grub_strlen(arg) >= BOOTSIGN_ARGLEN) {
4164eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4165eb2bd662Svikram 	return 1;
4166eb2bd662Svikram   }
4167eb2bd662Svikram 
4168eb2bd662Svikram   if (arg[0] == '\0') {
4169eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4170eb2bd662Svikram 	return 1;
4171eb2bd662Svikram   }
4172eb2bd662Svikram 
4173eb2bd662Svikram   if (grub_strchr(arg, '/')) {
4174eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
4175eb2bd662Svikram 	return 1;
4176eb2bd662Svikram   }
4177eb2bd662Svikram 
4178051aabe6Staylor   find_best_root = 1;
4179051aabe6Staylor   best_drive = 0;
4180051aabe6Staylor   best_part = 0;
4181eb2bd662Svikram   ret = find_common(arg, root, 1, flags);
4182eb2bd662Svikram   if (ret != 0)
4183eb2bd662Svikram 	return (ret);
4184051aabe6Staylor   find_best_root = 0;
4185eb2bd662Svikram 
4186eb2bd662Svikram   return real_root_func (root, 1);
4187eb2bd662Svikram }
4188eb2bd662Svikram 
4189eb2bd662Svikram static struct builtin builtin_findroot =
4190eb2bd662Svikram {
4191eb2bd662Svikram   "findroot",
4192eb2bd662Svikram   findroot_func,
4193eb2bd662Svikram   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4194963390b4Svikram   "findroot  <SIGNATURE | (SIGNATURE,partition[,slice])>",
4195963390b4Svikram   "Searches across all partitions for the file name SIGNATURE."
4196963390b4Svikram   " GRUB looks only in the directory /boot/grub/bootsign for the"
4197963390b4Svikram   " filename and it stops as soon as it finds the first instance of"
4198963390b4Svikram   " the file - so to be useful the name of the signature file must be"
4199963390b4Svikram   " unique across all partitions. Once the signature file is found,"
4200963390b4Svikram   " GRUB invokes the \"root\" command on that partition."
4201eb2bd662Svikram   " An optional partition and slice may be specified to optimize the search."
4202eb2bd662Svikram };
4203eb2bd662Svikram 
4204b1b8ab34Slling 
4205b1b8ab34Slling /*
4206b1b8ab34Slling  * COMMAND to override the default root filesystem for ZFS
4207b1b8ab34Slling  *	bootfs pool/fs
4208b1b8ab34Slling  */
4209b1b8ab34Slling static int
4210b1b8ab34Slling bootfs_func (char *arg, int flags)
4211b1b8ab34Slling {
4212b1b8ab34Slling 	int hdbias = 0;
4213b1b8ab34Slling 	char *biasptr;
4214b1b8ab34Slling 	char *next;
4215b1b8ab34Slling 
4216b1b8ab34Slling 	if (! *arg) {
4217b1b8ab34Slling 	    if (current_bootfs[0] != '\0')
4218b1b8ab34Slling 		grub_printf ("The zfs boot filesystem is set to '%s'.\n",
4219b1b8ab34Slling 				current_bootfs);
4220b1b8ab34Slling 	    else if (current_rootpool[0] != 0 && current_bootfs_obj != 0)
4221b1b8ab34Slling 		grub_printf("The zfs boot filesystem is <default: %s/%u>.",
4222b1b8ab34Slling 				current_rootpool, current_bootfs_obj);
4223b1b8ab34Slling 	    else
422411a41203Slling 		grub_printf ("The zfs boot filesystem will be derived from "
422511a41203Slling 			"the default bootfs pool property.\n");
4226b1b8ab34Slling 
4227b1b8ab34Slling 	    return (1);
4228b1b8ab34Slling 	}
4229b1b8ab34Slling 
4230b1b8ab34Slling 	/* Verify the zfs filesystem name */
4231b1b8ab34Slling 	if (arg[0] == '/' || arg[0] == '\0') {
4232b1b8ab34Slling 		errnum = ERR_BAD_ARGUMENT;
4233b1b8ab34Slling 		return 0;
4234b1b8ab34Slling 	}
4235b35c6776Staylor 	if (current_rootpool[0] != 0 && grub_strncmp(arg,
4236b35c6776Staylor 	    current_rootpool, strlen(current_rootpool))) {
4237b35c6776Staylor 		errnum = ERR_BAD_ARGUMENT;
4238b35c6776Staylor 		return 0;
4239b35c6776Staylor 	}
4240b1b8ab34Slling 
4241b1b8ab34Slling 	if (set_bootfs(arg) == 0) {
4242b1b8ab34Slling 		errnum = ERR_BAD_ARGUMENT;
4243b1b8ab34Slling 		return 0;
4244b1b8ab34Slling 	}
4245b1b8ab34Slling 
4246b1b8ab34Slling 	return (1);
4247b1b8ab34Slling }
4248b1b8ab34Slling 
4249b1b8ab34Slling static struct builtin builtin_bootfs =
4250b1b8ab34Slling {
4251b1b8ab34Slling   "bootfs",
4252b1b8ab34Slling   bootfs_func,
4253b1b8ab34Slling   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4254b1b8ab34Slling   "bootfs [ZFSBOOTFS]",
4255b1b8ab34Slling   "Set the current zfs boot filesystem to ZFSBOOTFS (rootpool/rootfs)."
4256b1b8ab34Slling };
4257b1b8ab34Slling 
42587c478bd9Sstevel@tonic-gate 
42597c478bd9Sstevel@tonic-gate /* rootnoverify */
42607c478bd9Sstevel@tonic-gate static int
42617c478bd9Sstevel@tonic-gate rootnoverify_func (char *arg, int flags)
42627c478bd9Sstevel@tonic-gate {
42637c478bd9Sstevel@tonic-gate   return real_root_func (arg, 0);
42647c478bd9Sstevel@tonic-gate }
42657c478bd9Sstevel@tonic-gate 
42667c478bd9Sstevel@tonic-gate static struct builtin builtin_rootnoverify =
42677c478bd9Sstevel@tonic-gate {
42687c478bd9Sstevel@tonic-gate   "rootnoverify",
42697c478bd9Sstevel@tonic-gate   rootnoverify_func,
42707c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
42717c478bd9Sstevel@tonic-gate   "rootnoverify [DEVICE [HDBIAS]]",
42727c478bd9Sstevel@tonic-gate   "Similar to `root', but don't attempt to mount the partition. This"
42737c478bd9Sstevel@tonic-gate   " is useful for when an OS is outside of the area of the disk that"
42747c478bd9Sstevel@tonic-gate   " GRUB can read, but setting the correct root device is still"
42757c478bd9Sstevel@tonic-gate   " desired. Note that the items mentioned in `root' which"
42767c478bd9Sstevel@tonic-gate   " derived from attempting the mount will NOT work correctly."
42777c478bd9Sstevel@tonic-gate };
42787c478bd9Sstevel@tonic-gate 
42797c478bd9Sstevel@tonic-gate 
42807c478bd9Sstevel@tonic-gate /* savedefault */
42817c478bd9Sstevel@tonic-gate static int
42827c478bd9Sstevel@tonic-gate savedefault_func (char *arg, int flags)
42837c478bd9Sstevel@tonic-gate {
42847c478bd9Sstevel@tonic-gate #if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
42857c478bd9Sstevel@tonic-gate   unsigned long tmp_drive = saved_drive;
42867c478bd9Sstevel@tonic-gate   unsigned long tmp_partition = saved_partition;
42877c478bd9Sstevel@tonic-gate   char *default_file = (char *) DEFAULT_FILE_BUF;
42887c478bd9Sstevel@tonic-gate   char buf[10];
42897c478bd9Sstevel@tonic-gate   char sect[SECTOR_SIZE];
42907c478bd9Sstevel@tonic-gate   int entryno;
42917c478bd9Sstevel@tonic-gate   int sector_count = 0;
4292342440ecSPrasad Singamsetty   unsigned int saved_sectors[2];
42937c478bd9Sstevel@tonic-gate   int saved_offsets[2];
42947c478bd9Sstevel@tonic-gate   int saved_lengths[2];
42957c478bd9Sstevel@tonic-gate 
4296b1b8ab34Slling   /* not supported for zfs root */
4297b1b8ab34Slling   if (is_zfs_mount == 1) {
4298b1b8ab34Slling 	return (0); /* no-op */
4299b1b8ab34Slling   }
4300b1b8ab34Slling 
43017c478bd9Sstevel@tonic-gate   /* Save sector information about at most two sectors.  */
43021b8adde7SWilliam Kucharski   auto void disk_read_savesect_func (unsigned int sector, int offset,
43031b8adde7SWilliam Kucharski       int length);
43041b8adde7SWilliam Kucharski   void disk_read_savesect_func (unsigned int sector, int offset, int length)
43057c478bd9Sstevel@tonic-gate     {
43067c478bd9Sstevel@tonic-gate       if (sector_count < 2)
43077c478bd9Sstevel@tonic-gate 	{
43087c478bd9Sstevel@tonic-gate 	  saved_sectors[sector_count] = sector;
43097c478bd9Sstevel@tonic-gate 	  saved_offsets[sector_count] = offset;
43107c478bd9Sstevel@tonic-gate 	  saved_lengths[sector_count] = length;
43117c478bd9Sstevel@tonic-gate 	}
43127c478bd9Sstevel@tonic-gate       sector_count++;
43137c478bd9Sstevel@tonic-gate     }
43147c478bd9Sstevel@tonic-gate 
43157c478bd9Sstevel@tonic-gate   /* This command is only useful when you boot an entry from the menu
43167c478bd9Sstevel@tonic-gate      interface.  */
43177c478bd9Sstevel@tonic-gate   if (! (flags & BUILTIN_SCRIPT))
43187c478bd9Sstevel@tonic-gate     {
43197c478bd9Sstevel@tonic-gate       errnum = ERR_UNRECOGNIZED;
43207c478bd9Sstevel@tonic-gate       return 1;
43217c478bd9Sstevel@tonic-gate     }
43227c478bd9Sstevel@tonic-gate 
43237c478bd9Sstevel@tonic-gate   /* Determine a saved entry number.  */
43247c478bd9Sstevel@tonic-gate   if (*arg)
43257c478bd9Sstevel@tonic-gate     {
43267c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0)
43277c478bd9Sstevel@tonic-gate 	{
43287c478bd9Sstevel@tonic-gate 	  int i;
43297c478bd9Sstevel@tonic-gate 	  int index = 0;
43307c478bd9Sstevel@tonic-gate 
43317c478bd9Sstevel@tonic-gate 	  for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
43327c478bd9Sstevel@tonic-gate 	    {
43337c478bd9Sstevel@tonic-gate 	      if (fallback_entries[i] < 0)
43347c478bd9Sstevel@tonic-gate 		break;
43357c478bd9Sstevel@tonic-gate 	      if (fallback_entries[i] == current_entryno)
43367c478bd9Sstevel@tonic-gate 		{
43377c478bd9Sstevel@tonic-gate 		  index = i + 1;
43387c478bd9Sstevel@tonic-gate 		  break;
43397c478bd9Sstevel@tonic-gate 		}
43407c478bd9Sstevel@tonic-gate 	    }
43417c478bd9Sstevel@tonic-gate 
43427c478bd9Sstevel@tonic-gate 	  if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0)
43437c478bd9Sstevel@tonic-gate 	    {
43447c478bd9Sstevel@tonic-gate 	      /* This is the last.  */
43457c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
43467c478bd9Sstevel@tonic-gate 	      return 1;
43477c478bd9Sstevel@tonic-gate 	    }
43487c478bd9Sstevel@tonic-gate 
43497c478bd9Sstevel@tonic-gate 	  entryno = fallback_entries[index];
43507c478bd9Sstevel@tonic-gate 	}
43517c478bd9Sstevel@tonic-gate       else if (! safe_parse_maxint (&arg, &entryno))
43527c478bd9Sstevel@tonic-gate 	return 1;
43537c478bd9Sstevel@tonic-gate     }
43547c478bd9Sstevel@tonic-gate   else
43557c478bd9Sstevel@tonic-gate     entryno = current_entryno;
43567c478bd9Sstevel@tonic-gate 
43577c478bd9Sstevel@tonic-gate   /* Open the default file.  */
43587c478bd9Sstevel@tonic-gate   saved_drive = boot_drive;
43597c478bd9Sstevel@tonic-gate   saved_partition = install_partition;
43607c478bd9Sstevel@tonic-gate   if (grub_open (default_file))
43617c478bd9Sstevel@tonic-gate     {
43627c478bd9Sstevel@tonic-gate       int len;
43637c478bd9Sstevel@tonic-gate 
43647c478bd9Sstevel@tonic-gate       disk_read_hook = disk_read_savesect_func;
43657c478bd9Sstevel@tonic-gate       len = grub_read (buf, sizeof (buf));
43667c478bd9Sstevel@tonic-gate       disk_read_hook = 0;
43677c478bd9Sstevel@tonic-gate       grub_close ();
43687c478bd9Sstevel@tonic-gate 
43697c478bd9Sstevel@tonic-gate       if (len != sizeof (buf))
43707c478bd9Sstevel@tonic-gate 	{
43717c478bd9Sstevel@tonic-gate 	  /* This is too small. Do not modify the file manually, please!  */
43727c478bd9Sstevel@tonic-gate 	  errnum = ERR_READ;
43737c478bd9Sstevel@tonic-gate 	  goto fail;
43747c478bd9Sstevel@tonic-gate 	}
43757c478bd9Sstevel@tonic-gate 
43767c478bd9Sstevel@tonic-gate       if (sector_count > 2)
43777c478bd9Sstevel@tonic-gate 	{
43787c478bd9Sstevel@tonic-gate 	  /* Is this possible?! Too fragmented!  */
43797c478bd9Sstevel@tonic-gate 	  errnum = ERR_FSYS_CORRUPT;
43807c478bd9Sstevel@tonic-gate 	  goto fail;
43817c478bd9Sstevel@tonic-gate 	}
43827c478bd9Sstevel@tonic-gate 
43837c478bd9Sstevel@tonic-gate       /* Set up a string to be written.  */
43847c478bd9Sstevel@tonic-gate       grub_memset (buf, '\n', sizeof (buf));
43857c478bd9Sstevel@tonic-gate       grub_sprintf (buf, "%d", entryno);
43867c478bd9Sstevel@tonic-gate 
43877c478bd9Sstevel@tonic-gate       if (saved_lengths[0] < sizeof (buf))
43887c478bd9Sstevel@tonic-gate 	{
43897c478bd9Sstevel@tonic-gate 	  /* The file is anchored to another file and the first few bytes
43907c478bd9Sstevel@tonic-gate 	     are spanned in two sectors. Uggh...  */
43917c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
43927c478bd9Sstevel@tonic-gate 			 sect))
43937c478bd9Sstevel@tonic-gate 	    goto fail;
43947c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]);
43957c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
43967c478bd9Sstevel@tonic-gate 	    goto fail;
43977c478bd9Sstevel@tonic-gate 
43987c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE,
43997c478bd9Sstevel@tonic-gate 			 sect))
44007c478bd9Sstevel@tonic-gate 	    goto fail;
44017c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[1],
44027c478bd9Sstevel@tonic-gate 			buf + saved_lengths[0],
44037c478bd9Sstevel@tonic-gate 			sizeof (buf) - saved_lengths[0]);
44047c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[1], sect))
44057c478bd9Sstevel@tonic-gate 	    goto fail;
44067c478bd9Sstevel@tonic-gate 	}
44077c478bd9Sstevel@tonic-gate       else
44087c478bd9Sstevel@tonic-gate 	{
44097c478bd9Sstevel@tonic-gate 	  /* This is a simple case. It fits into a single sector.  */
44107c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
44117c478bd9Sstevel@tonic-gate 			 sect))
44127c478bd9Sstevel@tonic-gate 	    goto fail;
44137c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[0], buf, sizeof (buf));
44147c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
44157c478bd9Sstevel@tonic-gate 	    goto fail;
44167c478bd9Sstevel@tonic-gate 	}
44177c478bd9Sstevel@tonic-gate 
44187c478bd9Sstevel@tonic-gate       /* Clear the cache.  */
4419342440ecSPrasad Singamsetty       buf_track = BUF_CACHE_INVALID;
44207c478bd9Sstevel@tonic-gate     }
44217c478bd9Sstevel@tonic-gate 
44227c478bd9Sstevel@tonic-gate  fail:
44237c478bd9Sstevel@tonic-gate   saved_drive = tmp_drive;
44247c478bd9Sstevel@tonic-gate   saved_partition = tmp_partition;
44257c478bd9Sstevel@tonic-gate   return errnum;
44267c478bd9Sstevel@tonic-gate #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
44277c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
44287c478bd9Sstevel@tonic-gate   return 1;
44297c478bd9Sstevel@tonic-gate #endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
44307c478bd9Sstevel@tonic-gate }
44317c478bd9Sstevel@tonic-gate 
44327c478bd9Sstevel@tonic-gate static struct builtin builtin_savedefault =
44337c478bd9Sstevel@tonic-gate {
44347c478bd9Sstevel@tonic-gate   "savedefault",
44357c478bd9Sstevel@tonic-gate   savedefault_func,
44367c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
44377c478bd9Sstevel@tonic-gate   "savedefault [NUM | `fallback']",
44387c478bd9Sstevel@tonic-gate   "Save the current entry as the default boot entry if no argument is"
44397c478bd9Sstevel@tonic-gate   " specified. If a number is specified, this number is saved. If"
44407c478bd9Sstevel@tonic-gate   " `fallback' is used, next fallback entry is saved."
44417c478bd9Sstevel@tonic-gate };
44427c478bd9Sstevel@tonic-gate 
44437c478bd9Sstevel@tonic-gate 
44447c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
44457c478bd9Sstevel@tonic-gate /* serial */
44467c478bd9Sstevel@tonic-gate static int
44477c478bd9Sstevel@tonic-gate serial_func (char *arg, int flags)
44487c478bd9Sstevel@tonic-gate {
44497c478bd9Sstevel@tonic-gate   unsigned short port = serial_hw_get_port (0);
44507c478bd9Sstevel@tonic-gate   unsigned int speed = 9600;
44517c478bd9Sstevel@tonic-gate   int word_len = UART_8BITS_WORD;
44527c478bd9Sstevel@tonic-gate   int parity = UART_NO_PARITY;
44537c478bd9Sstevel@tonic-gate   int stop_bit_len = UART_1_STOP_BIT;
44547c478bd9Sstevel@tonic-gate 
44557c478bd9Sstevel@tonic-gate   /* Process GNU-style long options.
44567c478bd9Sstevel@tonic-gate      FIXME: We should implement a getopt-like function, to avoid
44577c478bd9Sstevel@tonic-gate      duplications.  */
44587c478bd9Sstevel@tonic-gate   while (1)
44597c478bd9Sstevel@tonic-gate     {
44607c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
44617c478bd9Sstevel@tonic-gate 	{
44627c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--unit=") - 1;
44637c478bd9Sstevel@tonic-gate 	  int unit;
44647c478bd9Sstevel@tonic-gate 
44657c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &unit))
44667c478bd9Sstevel@tonic-gate 	    return 1;
44677c478bd9Sstevel@tonic-gate 
44687c478bd9Sstevel@tonic-gate 	  if (unit < 0 || unit > 3)
44697c478bd9Sstevel@tonic-gate 	    {
44707c478bd9Sstevel@tonic-gate 	      errnum = ERR_DEV_VALUES;
44717c478bd9Sstevel@tonic-gate 	      return 1;
44727c478bd9Sstevel@tonic-gate 	    }
44737c478bd9Sstevel@tonic-gate 
44747c478bd9Sstevel@tonic-gate 	  port = serial_hw_get_port (unit);
44757c478bd9Sstevel@tonic-gate 	}
44767c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0)
44777c478bd9Sstevel@tonic-gate 	{
44787c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--speed=") - 1;
44797c478bd9Sstevel@tonic-gate 	  int num;
44807c478bd9Sstevel@tonic-gate 
44817c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &num))
44827c478bd9Sstevel@tonic-gate 	    return 1;
44837c478bd9Sstevel@tonic-gate 
44847c478bd9Sstevel@tonic-gate 	  speed = (unsigned int) num;
44857c478bd9Sstevel@tonic-gate 	}
44867c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
44877c478bd9Sstevel@tonic-gate 	{
44887c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--port=") - 1;
44897c478bd9Sstevel@tonic-gate 	  int num;
44907c478bd9Sstevel@tonic-gate 
44917c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &num))
44927c478bd9Sstevel@tonic-gate 	    return 1;
44937c478bd9Sstevel@tonic-gate 
44947c478bd9Sstevel@tonic-gate 	  port = (unsigned short) num;
44957c478bd9Sstevel@tonic-gate 	}
44967c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
44977c478bd9Sstevel@tonic-gate 	{
44987c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--word=") - 1;
44997c478bd9Sstevel@tonic-gate 	  int len;
45007c478bd9Sstevel@tonic-gate 
45017c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &len))
45027c478bd9Sstevel@tonic-gate 	    return 1;
45037c478bd9Sstevel@tonic-gate 
45047c478bd9Sstevel@tonic-gate 	  switch (len)
45057c478bd9Sstevel@tonic-gate 	    {
45067c478bd9Sstevel@tonic-gate 	    case 5: word_len = UART_5BITS_WORD; break;
45077c478bd9Sstevel@tonic-gate 	    case 6: word_len = UART_6BITS_WORD; break;
45087c478bd9Sstevel@tonic-gate 	    case 7: word_len = UART_7BITS_WORD; break;
45097c478bd9Sstevel@tonic-gate 	    case 8: word_len = UART_8BITS_WORD; break;
45107c478bd9Sstevel@tonic-gate 	    default:
45117c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
45127c478bd9Sstevel@tonic-gate 	      return 1;
45137c478bd9Sstevel@tonic-gate 	    }
45147c478bd9Sstevel@tonic-gate 	}
45157c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
45167c478bd9Sstevel@tonic-gate 	{
45177c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--stop=") - 1;
45187c478bd9Sstevel@tonic-gate 	  int len;
45197c478bd9Sstevel@tonic-gate 
45207c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &len))
45217c478bd9Sstevel@tonic-gate 	    return 1;
45227c478bd9Sstevel@tonic-gate 
45237c478bd9Sstevel@tonic-gate 	  switch (len)
45247c478bd9Sstevel@tonic-gate 	    {
45257c478bd9Sstevel@tonic-gate 	    case 1: stop_bit_len = UART_1_STOP_BIT; break;
45267c478bd9Sstevel@tonic-gate 	    case 2: stop_bit_len = UART_2_STOP_BITS; break;
45277c478bd9Sstevel@tonic-gate 	    default:
45287c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
45297c478bd9Sstevel@tonic-gate 	      return 1;
45307c478bd9Sstevel@tonic-gate 	    }
45317c478bd9Sstevel@tonic-gate 	}
45327c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
45337c478bd9Sstevel@tonic-gate 	{
45347c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--parity=") - 1;
45357c478bd9Sstevel@tonic-gate 
45367c478bd9Sstevel@tonic-gate 	  if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
45377c478bd9Sstevel@tonic-gate 	    parity = UART_NO_PARITY;
45387c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
45397c478bd9Sstevel@tonic-gate 	    parity = UART_ODD_PARITY;
45407c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
45417c478bd9Sstevel@tonic-gate 	    parity = UART_EVEN_PARITY;
45427c478bd9Sstevel@tonic-gate 	  else
45437c478bd9Sstevel@tonic-gate 	    {
45447c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
45457c478bd9Sstevel@tonic-gate 	      return 1;
45467c478bd9Sstevel@tonic-gate 	    }
45477c478bd9Sstevel@tonic-gate 	}
45487c478bd9Sstevel@tonic-gate # ifdef GRUB_UTIL
45497c478bd9Sstevel@tonic-gate       /* In the grub shell, don't use any port number but open a tty
45507c478bd9Sstevel@tonic-gate 	 device instead.  */
45517c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
45527c478bd9Sstevel@tonic-gate 	{
45537c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--device=") - 1;
45547c478bd9Sstevel@tonic-gate 	  char dev[256];	/* XXX */
45557c478bd9Sstevel@tonic-gate 	  char *q = dev;
45567c478bd9Sstevel@tonic-gate 
45577c478bd9Sstevel@tonic-gate 	  while (*p && ! grub_isspace (*p))
45587c478bd9Sstevel@tonic-gate 	    *q++ = *p++;
45597c478bd9Sstevel@tonic-gate 
45607c478bd9Sstevel@tonic-gate 	  *q = 0;
45617c478bd9Sstevel@tonic-gate 	  serial_set_device (dev);
45627c478bd9Sstevel@tonic-gate 	}
45637c478bd9Sstevel@tonic-gate # endif /* GRUB_UTIL */
45647c478bd9Sstevel@tonic-gate       else
45657c478bd9Sstevel@tonic-gate 	break;
45667c478bd9Sstevel@tonic-gate 
45677c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
45687c478bd9Sstevel@tonic-gate     }
45697c478bd9Sstevel@tonic-gate 
45707c478bd9Sstevel@tonic-gate   /* Initialize the serial unit.  */
45717c478bd9Sstevel@tonic-gate   if (! serial_hw_init (port, speed, word_len, parity, stop_bit_len))
45727c478bd9Sstevel@tonic-gate     {
45737c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
45747c478bd9Sstevel@tonic-gate       return 1;
45757c478bd9Sstevel@tonic-gate     }
45767c478bd9Sstevel@tonic-gate 
45777c478bd9Sstevel@tonic-gate   return 0;
45787c478bd9Sstevel@tonic-gate }
45797c478bd9Sstevel@tonic-gate 
45807c478bd9Sstevel@tonic-gate static struct builtin builtin_serial =
45817c478bd9Sstevel@tonic-gate {
45827c478bd9Sstevel@tonic-gate   "serial",
45837c478bd9Sstevel@tonic-gate   serial_func,
45847c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
45857c478bd9Sstevel@tonic-gate   "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
45867c478bd9Sstevel@tonic-gate   "Initialize a serial device. UNIT is a digit that specifies which serial"
45877c478bd9Sstevel@tonic-gate   " device is used (e.g. 0 == COM1). If you need to specify the port number,"
45887c478bd9Sstevel@tonic-gate   " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
45897c478bd9Sstevel@tonic-gate   " PARITY is the type of parity, which is one of `no', `odd' and `even'."
45907c478bd9Sstevel@tonic-gate   " STOP is the length of stop bit(s). The option --device can be used only"
45917c478bd9Sstevel@tonic-gate   " in the grub shell, which specifies the file name of a tty device. The"
45927c478bd9Sstevel@tonic-gate   " default values are COM1, 9600, 8N1."
45937c478bd9Sstevel@tonic-gate };
45947c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
45957c478bd9Sstevel@tonic-gate 
45967c478bd9Sstevel@tonic-gate 
45977c478bd9Sstevel@tonic-gate /* setkey */
45987c478bd9Sstevel@tonic-gate struct keysym
45997c478bd9Sstevel@tonic-gate {
46007c478bd9Sstevel@tonic-gate   char *unshifted_name;			/* the name in unshifted state */
46017c478bd9Sstevel@tonic-gate   char *shifted_name;			/* the name in shifted state */
46027c478bd9Sstevel@tonic-gate   unsigned char unshifted_ascii;	/* the ascii code in unshifted state */
46037c478bd9Sstevel@tonic-gate   unsigned char shifted_ascii;		/* the ascii code in shifted state */
46047c478bd9Sstevel@tonic-gate   unsigned char keycode;		/* keyboard scancode */
46057c478bd9Sstevel@tonic-gate };
46067c478bd9Sstevel@tonic-gate 
46077c478bd9Sstevel@tonic-gate /* The table for key symbols. If the "shifted" member of an entry is
46087c478bd9Sstevel@tonic-gate    NULL, the entry does not have shifted state.  */
46097c478bd9Sstevel@tonic-gate static struct keysym keysym_table[] =
46107c478bd9Sstevel@tonic-gate {
46117c478bd9Sstevel@tonic-gate   {"escape",		0,		0x1b,	0,	0x01},
46127c478bd9Sstevel@tonic-gate   {"1",			"exclam",	'1',	'!',	0x02},
46137c478bd9Sstevel@tonic-gate   {"2",			"at",		'2',	'@',	0x03},
46147c478bd9Sstevel@tonic-gate   {"3",			"numbersign",	'3',	'#',	0x04},
46157c478bd9Sstevel@tonic-gate   {"4",			"dollar",	'4',	'$',	0x05},
46167c478bd9Sstevel@tonic-gate   {"5",			"percent",	'5',	'%',	0x06},
46177c478bd9Sstevel@tonic-gate   {"6",			"caret",	'6',	'^',	0x07},
46187c478bd9Sstevel@tonic-gate   {"7",			"ampersand",	'7',	'&',	0x08},
46197c478bd9Sstevel@tonic-gate   {"8",			"asterisk",	'8',	'*',	0x09},
46207c478bd9Sstevel@tonic-gate   {"9",			"parenleft",	'9',	'(',	0x0a},
46217c478bd9Sstevel@tonic-gate   {"0",			"parenright",	'0',	')',	0x0b},
46227c478bd9Sstevel@tonic-gate   {"minus",		"underscore",	'-',	'_',	0x0c},
46237c478bd9Sstevel@tonic-gate   {"equal",		"plus",		'=',	'+',	0x0d},
46247c478bd9Sstevel@tonic-gate   {"backspace",		0,		'\b',	0,	0x0e},
46257c478bd9Sstevel@tonic-gate   {"tab",		0,		'\t',	0,	0x0f},
46267c478bd9Sstevel@tonic-gate   {"q",			"Q",		'q',	'Q',	0x10},
46277c478bd9Sstevel@tonic-gate   {"w",			"W",		'w',	'W',	0x11},
46287c478bd9Sstevel@tonic-gate   {"e",			"E",		'e',	'E',	0x12},
46297c478bd9Sstevel@tonic-gate   {"r",			"R",		'r',	'R',	0x13},
46307c478bd9Sstevel@tonic-gate   {"t",			"T",		't',	'T',	0x14},
46317c478bd9Sstevel@tonic-gate   {"y",			"Y",		'y',	'Y',	0x15},
46327c478bd9Sstevel@tonic-gate   {"u",			"U",		'u',	'U',	0x16},
46337c478bd9Sstevel@tonic-gate   {"i",			"I",		'i',	'I',	0x17},
46347c478bd9Sstevel@tonic-gate   {"o",			"O",		'o',	'O',	0x18},
46357c478bd9Sstevel@tonic-gate   {"p",			"P",		'p',	'P',	0x19},
46367c478bd9Sstevel@tonic-gate   {"bracketleft",	"braceleft",	'[',	'{',	0x1a},
46377c478bd9Sstevel@tonic-gate   {"bracketright",	"braceright",	']',	'}',	0x1b},
46387c478bd9Sstevel@tonic-gate   {"enter",		0,		'\n',	0,	0x1c},
46397c478bd9Sstevel@tonic-gate   {"control",		0,		0,	0,	0x1d},
46407c478bd9Sstevel@tonic-gate   {"a",			"A",		'a',	'A',	0x1e},
46417c478bd9Sstevel@tonic-gate   {"s",			"S",		's',	'S',	0x1f},
46427c478bd9Sstevel@tonic-gate   {"d",			"D",		'd',	'D',	0x20},
46437c478bd9Sstevel@tonic-gate   {"f",			"F",		'f',	'F',	0x21},
46447c478bd9Sstevel@tonic-gate   {"g",			"G",		'g',	'G',	0x22},
46457c478bd9Sstevel@tonic-gate   {"h",			"H",		'h',	'H',	0x23},
46467c478bd9Sstevel@tonic-gate   {"j",			"J",		'j',	'J',	0x24},
46477c478bd9Sstevel@tonic-gate   {"k",			"K",		'k',	'K',	0x25},
46487c478bd9Sstevel@tonic-gate   {"l",			"L",		'l',	'L',	0x26},
46497c478bd9Sstevel@tonic-gate   {"semicolon",		"colon",	';',	':',	0x27},
46507c478bd9Sstevel@tonic-gate   {"quote",		"doublequote",	'\'',	'"',	0x28},
46517c478bd9Sstevel@tonic-gate   {"backquote",		"tilde",	'`',	'~',	0x29},
46527c478bd9Sstevel@tonic-gate   {"shift",		0,		0,	0,	0x2a},
46537c478bd9Sstevel@tonic-gate   {"backslash",		"bar",		'\\',	'|',	0x2b},
46547c478bd9Sstevel@tonic-gate   {"z",			"Z",		'z',	'Z',	0x2c},
46557c478bd9Sstevel@tonic-gate   {"x",			"X",		'x',	'X',	0x2d},
46567c478bd9Sstevel@tonic-gate   {"c",			"C",		'c',	'C',	0x2e},
46577c478bd9Sstevel@tonic-gate   {"v",			"V",		'v',	'V',	0x2f},
46587c478bd9Sstevel@tonic-gate   {"b",			"B",		'b',	'B',	0x30},
46597c478bd9Sstevel@tonic-gate   {"n",			"N",		'n',	'N',	0x31},
46607c478bd9Sstevel@tonic-gate   {"m",			"M",		'm',	'M',	0x32},
46617c478bd9Sstevel@tonic-gate   {"comma",		"less",		',',	'<',	0x33},
46627c478bd9Sstevel@tonic-gate   {"period",		"greater",	'.',	'>',	0x34},
46637c478bd9Sstevel@tonic-gate   {"slash",		"question",	'/',	'?',	0x35},
46647c478bd9Sstevel@tonic-gate   {"alt",		0,		0,	0,	0x38},
46657c478bd9Sstevel@tonic-gate   {"space",		0,		' ',	0,	0x39},
46667c478bd9Sstevel@tonic-gate   {"capslock",		0,		0,	0,	0x3a},
46677c478bd9Sstevel@tonic-gate   {"F1",		0,		0,	0,	0x3b},
46687c478bd9Sstevel@tonic-gate   {"F2",		0,		0,	0,	0x3c},
46697c478bd9Sstevel@tonic-gate   {"F3",		0,		0,	0,	0x3d},
46707c478bd9Sstevel@tonic-gate   {"F4",		0,		0,	0,	0x3e},
46717c478bd9Sstevel@tonic-gate   {"F5",		0,		0,	0,	0x3f},
46727c478bd9Sstevel@tonic-gate   {"F6",		0,		0,	0,	0x40},
46737c478bd9Sstevel@tonic-gate   {"F7",		0,		0,	0,	0x41},
46747c478bd9Sstevel@tonic-gate   {"F8",		0,		0,	0,	0x42},
46757c478bd9Sstevel@tonic-gate   {"F9",		0,		0,	0,	0x43},
46767c478bd9Sstevel@tonic-gate   {"F10",		0,		0,	0,	0x44},
46777c478bd9Sstevel@tonic-gate   /* Caution: do not add NumLock here! we cannot deal with it properly.  */
46787c478bd9Sstevel@tonic-gate   {"delete",		0,		0x7f,	0,	0x53}
46797c478bd9Sstevel@tonic-gate };
46807c478bd9Sstevel@tonic-gate 
46817c478bd9Sstevel@tonic-gate static int
46827c478bd9Sstevel@tonic-gate setkey_func (char *arg, int flags)
46837c478bd9Sstevel@tonic-gate {
46847c478bd9Sstevel@tonic-gate   char *to_key, *from_key;
46857c478bd9Sstevel@tonic-gate   int to_code, from_code;
46867c478bd9Sstevel@tonic-gate   int map_in_interrupt = 0;
46877c478bd9Sstevel@tonic-gate 
46881b8adde7SWilliam Kucharski   auto int find_key_code (char *key);
46891b8adde7SWilliam Kucharski   auto int find_ascii_code (char *key);
46901b8adde7SWilliam Kucharski 
46911b8adde7SWilliam Kucharski   auto int find_key_code (char *key)
46927c478bd9Sstevel@tonic-gate     {
46937c478bd9Sstevel@tonic-gate       int i;
46947c478bd9Sstevel@tonic-gate 
46957c478bd9Sstevel@tonic-gate       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
46967c478bd9Sstevel@tonic-gate 	{
46977c478bd9Sstevel@tonic-gate 	  if (keysym_table[i].unshifted_name &&
46987c478bd9Sstevel@tonic-gate 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
46997c478bd9Sstevel@tonic-gate 	    return keysym_table[i].keycode;
47007c478bd9Sstevel@tonic-gate 	  else if (keysym_table[i].shifted_name &&
47017c478bd9Sstevel@tonic-gate 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
47027c478bd9Sstevel@tonic-gate 	    return keysym_table[i].keycode;
47037c478bd9Sstevel@tonic-gate 	}
47047c478bd9Sstevel@tonic-gate 
47057c478bd9Sstevel@tonic-gate       return 0;
47067c478bd9Sstevel@tonic-gate     }
47077c478bd9Sstevel@tonic-gate 
47081b8adde7SWilliam Kucharski   auto int find_ascii_code (char *key)
47097c478bd9Sstevel@tonic-gate     {
47107c478bd9Sstevel@tonic-gate       int i;
47117c478bd9Sstevel@tonic-gate 
47127c478bd9Sstevel@tonic-gate       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
47137c478bd9Sstevel@tonic-gate 	{
47147c478bd9Sstevel@tonic-gate 	  if (keysym_table[i].unshifted_name &&
47157c478bd9Sstevel@tonic-gate 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
47167c478bd9Sstevel@tonic-gate 	    return keysym_table[i].unshifted_ascii;
47177c478bd9Sstevel@tonic-gate 	  else if (keysym_table[i].shifted_name &&
47187c478bd9Sstevel@tonic-gate 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
47197c478bd9Sstevel@tonic-gate 	    return keysym_table[i].shifted_ascii;
47207c478bd9Sstevel@tonic-gate 	}
47217c478bd9Sstevel@tonic-gate 
47227c478bd9Sstevel@tonic-gate       return 0;
47237c478bd9Sstevel@tonic-gate     }
47247c478bd9Sstevel@tonic-gate 
47257c478bd9Sstevel@tonic-gate   to_key = arg;
47267c478bd9Sstevel@tonic-gate   from_key = skip_to (0, to_key);
47277c478bd9Sstevel@tonic-gate 
47287c478bd9Sstevel@tonic-gate   if (! *to_key)
47297c478bd9Sstevel@tonic-gate     {
47307c478bd9Sstevel@tonic-gate       /* If the user specifies no argument, reset the key mappings.  */
47317c478bd9Sstevel@tonic-gate       grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
47327c478bd9Sstevel@tonic-gate       grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
47337c478bd9Sstevel@tonic-gate 
47347c478bd9Sstevel@tonic-gate       return 0;
47357c478bd9Sstevel@tonic-gate     }
47367c478bd9Sstevel@tonic-gate   else if (! *from_key)
47377c478bd9Sstevel@tonic-gate     {
47387c478bd9Sstevel@tonic-gate       /* The user must specify two arguments or zero argument.  */
47397c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
47407c478bd9Sstevel@tonic-gate       return 1;
47417c478bd9Sstevel@tonic-gate     }
47427c478bd9Sstevel@tonic-gate 
47437c478bd9Sstevel@tonic-gate   nul_terminate (to_key);
47447c478bd9Sstevel@tonic-gate   nul_terminate (from_key);
47457c478bd9Sstevel@tonic-gate 
47467c478bd9Sstevel@tonic-gate   to_code = find_ascii_code (to_key);
47477c478bd9Sstevel@tonic-gate   from_code = find_ascii_code (from_key);
47487c478bd9Sstevel@tonic-gate   if (! to_code || ! from_code)
47497c478bd9Sstevel@tonic-gate     {
47507c478bd9Sstevel@tonic-gate       map_in_interrupt = 1;
47517c478bd9Sstevel@tonic-gate       to_code = find_key_code (to_key);
47527c478bd9Sstevel@tonic-gate       from_code = find_key_code (from_key);
47537c478bd9Sstevel@tonic-gate       if (! to_code || ! from_code)
47547c478bd9Sstevel@tonic-gate 	{
47557c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
47567c478bd9Sstevel@tonic-gate 	  return 1;
47577c478bd9Sstevel@tonic-gate 	}
47587c478bd9Sstevel@tonic-gate     }
47597c478bd9Sstevel@tonic-gate 
47607c478bd9Sstevel@tonic-gate   if (map_in_interrupt)
47617c478bd9Sstevel@tonic-gate     {
47627c478bd9Sstevel@tonic-gate       int i;
47637c478bd9Sstevel@tonic-gate 
47647c478bd9Sstevel@tonic-gate       /* Find an empty slot.  */
47657c478bd9Sstevel@tonic-gate       for (i = 0; i < KEY_MAP_SIZE; i++)
47667c478bd9Sstevel@tonic-gate 	{
47677c478bd9Sstevel@tonic-gate 	  if ((bios_key_map[i] & 0xff) == from_code)
47687c478bd9Sstevel@tonic-gate 	    /* Perhaps the user wants to overwrite the map.  */
47697c478bd9Sstevel@tonic-gate 	    break;
47707c478bd9Sstevel@tonic-gate 
47717c478bd9Sstevel@tonic-gate 	  if (! bios_key_map[i])
47727c478bd9Sstevel@tonic-gate 	    break;
47737c478bd9Sstevel@tonic-gate 	}
47747c478bd9Sstevel@tonic-gate 
47757c478bd9Sstevel@tonic-gate       if (i == KEY_MAP_SIZE)
47767c478bd9Sstevel@tonic-gate 	{
47777c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
47787c478bd9Sstevel@tonic-gate 	  return 1;
47797c478bd9Sstevel@tonic-gate 	}
47807c478bd9Sstevel@tonic-gate 
47817c478bd9Sstevel@tonic-gate       if (to_code == from_code)
47827c478bd9Sstevel@tonic-gate 	/* If TO is equal to FROM, delete the entry.  */
47837c478bd9Sstevel@tonic-gate 	grub_memmove ((char *) &bios_key_map[i],
47847c478bd9Sstevel@tonic-gate 		      (char *) &bios_key_map[i + 1],
47857c478bd9Sstevel@tonic-gate 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
47867c478bd9Sstevel@tonic-gate       else
47877c478bd9Sstevel@tonic-gate 	bios_key_map[i] = (to_code << 8) | from_code;
47887c478bd9Sstevel@tonic-gate 
47897c478bd9Sstevel@tonic-gate       /* Ugly but should work.  */
47907c478bd9Sstevel@tonic-gate       unset_int15_handler ();
47917c478bd9Sstevel@tonic-gate       set_int15_handler ();
47927c478bd9Sstevel@tonic-gate     }
47937c478bd9Sstevel@tonic-gate   else
47947c478bd9Sstevel@tonic-gate     {
47957c478bd9Sstevel@tonic-gate       int i;
47967c478bd9Sstevel@tonic-gate 
47977c478bd9Sstevel@tonic-gate       /* Find an empty slot.  */
47987c478bd9Sstevel@tonic-gate       for (i = 0; i < KEY_MAP_SIZE; i++)
47997c478bd9Sstevel@tonic-gate 	{
48007c478bd9Sstevel@tonic-gate 	  if ((ascii_key_map[i] & 0xff) == from_code)
48017c478bd9Sstevel@tonic-gate 	    /* Perhaps the user wants to overwrite the map.  */
48027c478bd9Sstevel@tonic-gate 	    break;
48037c478bd9Sstevel@tonic-gate 
48047c478bd9Sstevel@tonic-gate 	  if (! ascii_key_map[i])
48057c478bd9Sstevel@tonic-gate 	    break;
48067c478bd9Sstevel@tonic-gate 	}
48077c478bd9Sstevel@tonic-gate 
48087c478bd9Sstevel@tonic-gate       if (i == KEY_MAP_SIZE)
48097c478bd9Sstevel@tonic-gate 	{
48107c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
48117c478bd9Sstevel@tonic-gate 	  return 1;
48127c478bd9Sstevel@tonic-gate 	}
48137c478bd9Sstevel@tonic-gate 
48147c478bd9Sstevel@tonic-gate       if (to_code == from_code)
48157c478bd9Sstevel@tonic-gate 	/* If TO is equal to FROM, delete the entry.  */
48167c478bd9Sstevel@tonic-gate 	grub_memmove ((char *) &ascii_key_map[i],
48177c478bd9Sstevel@tonic-gate 		      (char *) &ascii_key_map[i + 1],
48187c478bd9Sstevel@tonic-gate 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
48197c478bd9Sstevel@tonic-gate       else
48207c478bd9Sstevel@tonic-gate 	ascii_key_map[i] = (to_code << 8) | from_code;
48217c478bd9Sstevel@tonic-gate     }
48227c478bd9Sstevel@tonic-gate 
48237c478bd9Sstevel@tonic-gate   return 0;
48247c478bd9Sstevel@tonic-gate }
48257c478bd9Sstevel@tonic-gate 
48267c478bd9Sstevel@tonic-gate static struct builtin builtin_setkey =
48277c478bd9Sstevel@tonic-gate {
48287c478bd9Sstevel@tonic-gate   "setkey",
48297c478bd9Sstevel@tonic-gate   setkey_func,
48307c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
48317c478bd9Sstevel@tonic-gate   "setkey [TO_KEY FROM_KEY]",
48327c478bd9Sstevel@tonic-gate   "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
48337c478bd9Sstevel@tonic-gate   " A key must be an alphabet, a digit, or one of these: escape, exclam,"
48347c478bd9Sstevel@tonic-gate   " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft,"
48357c478bd9Sstevel@tonic-gate   " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft,"
48367c478bd9Sstevel@tonic-gate   " braceleft, bracketright, braceright, enter, control, semicolon, colon,"
48377c478bd9Sstevel@tonic-gate   " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
48387c478bd9Sstevel@tonic-gate   " less, period, greater, slash, question, alt, space, capslock, FX (X"
48397c478bd9Sstevel@tonic-gate   " is a digit), and delete. If no argument is specified, reset key"
48407c478bd9Sstevel@tonic-gate   " mappings."
48417c478bd9Sstevel@tonic-gate };
48427c478bd9Sstevel@tonic-gate 
48437c478bd9Sstevel@tonic-gate 
48447c478bd9Sstevel@tonic-gate /* setup */
48457c478bd9Sstevel@tonic-gate static int
48467c478bd9Sstevel@tonic-gate setup_func (char *arg, int flags)
48477c478bd9Sstevel@tonic-gate {
48487c478bd9Sstevel@tonic-gate   /* Point to the string of the installed drive/partition.  */
48497c478bd9Sstevel@tonic-gate   char *install_ptr;
48507c478bd9Sstevel@tonic-gate   /* Point to the string of the drive/parition where the GRUB images
48517c478bd9Sstevel@tonic-gate      reside.  */
48527c478bd9Sstevel@tonic-gate   char *image_ptr;
48537c478bd9Sstevel@tonic-gate   unsigned long installed_drive, installed_partition;
48547c478bd9Sstevel@tonic-gate   unsigned long image_drive, image_partition;
48557c478bd9Sstevel@tonic-gate   unsigned long tmp_drive, tmp_partition;
48567c478bd9Sstevel@tonic-gate   char stage1[64];
48577c478bd9Sstevel@tonic-gate   char stage2[64];
48587c478bd9Sstevel@tonic-gate   char config_filename[64];
48597c478bd9Sstevel@tonic-gate   char real_config_filename[64];
48607c478bd9Sstevel@tonic-gate   char cmd_arg[256];
48617c478bd9Sstevel@tonic-gate   char device[16];
48627c478bd9Sstevel@tonic-gate   char *buffer = (char *) RAW_ADDR (0x100000);
48637c478bd9Sstevel@tonic-gate   int is_force_lba = 0;
48647c478bd9Sstevel@tonic-gate   char *stage2_arg = 0;
48657c478bd9Sstevel@tonic-gate   char *prefix = 0;
48667c478bd9Sstevel@tonic-gate 
48677c478bd9Sstevel@tonic-gate   auto int check_file (char *file);
48687c478bd9Sstevel@tonic-gate   auto void sprint_device (int drive, int partition);
48697c478bd9Sstevel@tonic-gate   auto int embed_stage1_5 (char * stage1_5, int drive, int partition);
48707c478bd9Sstevel@tonic-gate 
48717c478bd9Sstevel@tonic-gate   /* Check if the file FILE exists like Autoconf.  */
48727c478bd9Sstevel@tonic-gate   int check_file (char *file)
48737c478bd9Sstevel@tonic-gate     {
48747c478bd9Sstevel@tonic-gate       int ret;
48757c478bd9Sstevel@tonic-gate 
48767c478bd9Sstevel@tonic-gate       grub_printf (" Checking if \"%s\" exists... ", file);
48777c478bd9Sstevel@tonic-gate       ret = grub_open (file);
48787c478bd9Sstevel@tonic-gate       if (ret)
48797c478bd9Sstevel@tonic-gate 	{
48807c478bd9Sstevel@tonic-gate 	  grub_close ();
48817c478bd9Sstevel@tonic-gate 	  grub_printf ("yes\n");
48827c478bd9Sstevel@tonic-gate 	}
48837c478bd9Sstevel@tonic-gate       else
48847c478bd9Sstevel@tonic-gate 	grub_printf ("no\n");
48857c478bd9Sstevel@tonic-gate 
48867c478bd9Sstevel@tonic-gate       return ret;
48877c478bd9Sstevel@tonic-gate     }
48887c478bd9Sstevel@tonic-gate 
48897c478bd9Sstevel@tonic-gate   /* Construct a device name in DEVICE.  */
48907c478bd9Sstevel@tonic-gate   void sprint_device (int drive, int partition)
48917c478bd9Sstevel@tonic-gate     {
48927c478bd9Sstevel@tonic-gate       grub_sprintf (device, "(%cd%d",
48937c478bd9Sstevel@tonic-gate 		    (drive & 0x80) ? 'h' : 'f',
48947c478bd9Sstevel@tonic-gate 		    drive & ~0x80);
48957c478bd9Sstevel@tonic-gate       if ((partition & 0xFF0000) != 0xFF0000)
48967c478bd9Sstevel@tonic-gate 	{
48977c478bd9Sstevel@tonic-gate 	  char tmp[16];
48987c478bd9Sstevel@tonic-gate 	  grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
48997c478bd9Sstevel@tonic-gate 	  grub_strncat (device, tmp, 256);
49007c478bd9Sstevel@tonic-gate 	}
49017c478bd9Sstevel@tonic-gate       if ((partition & 0x00FF00) != 0x00FF00)
49027c478bd9Sstevel@tonic-gate 	{
49037c478bd9Sstevel@tonic-gate 	  char tmp[16];
49047c478bd9Sstevel@tonic-gate 	  grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
49057c478bd9Sstevel@tonic-gate 	  grub_strncat (device, tmp, 256);
49067c478bd9Sstevel@tonic-gate 	}
49077c478bd9Sstevel@tonic-gate       grub_strncat (device, ")", 256);
49087c478bd9Sstevel@tonic-gate     }
49097c478bd9Sstevel@tonic-gate 
49107c478bd9Sstevel@tonic-gate   int embed_stage1_5 (char *stage1_5, int drive, int partition)
49117c478bd9Sstevel@tonic-gate     {
49127c478bd9Sstevel@tonic-gate       /* We install GRUB into the MBR, so try to embed the
49137c478bd9Sstevel@tonic-gate 	 Stage 1.5 in the sectors right after the MBR.  */
49147c478bd9Sstevel@tonic-gate       sprint_device (drive, partition);
49157c478bd9Sstevel@tonic-gate       grub_sprintf (cmd_arg, "%s %s", stage1_5, device);
49167c478bd9Sstevel@tonic-gate 
49177c478bd9Sstevel@tonic-gate       /* Notify what will be run.  */
49187c478bd9Sstevel@tonic-gate       grub_printf (" Running \"embed %s\"... ", cmd_arg);
49197c478bd9Sstevel@tonic-gate 
49207c478bd9Sstevel@tonic-gate       embed_func (cmd_arg, flags);
49217c478bd9Sstevel@tonic-gate       if (! errnum)
49227c478bd9Sstevel@tonic-gate 	{
49237c478bd9Sstevel@tonic-gate 	  /* Construct the blocklist representation.  */
49247c478bd9Sstevel@tonic-gate 	  grub_sprintf (buffer, "%s%s", device, embed_info);
49257c478bd9Sstevel@tonic-gate 	  grub_printf ("succeeded\n");
49267c478bd9Sstevel@tonic-gate 	  return 1;
49277c478bd9Sstevel@tonic-gate 	}
49287c478bd9Sstevel@tonic-gate       else
49297c478bd9Sstevel@tonic-gate 	{
49307c478bd9Sstevel@tonic-gate 	  grub_printf ("failed (this is not fatal)\n");
49317c478bd9Sstevel@tonic-gate 	  return 0;
49327c478bd9Sstevel@tonic-gate 	}
49337c478bd9Sstevel@tonic-gate     }
49347c478bd9Sstevel@tonic-gate 
49357c478bd9Sstevel@tonic-gate   struct stage1_5_map {
49367c478bd9Sstevel@tonic-gate     char *fsys;
49377c478bd9Sstevel@tonic-gate     char *name;
49387c478bd9Sstevel@tonic-gate   };
49397c478bd9Sstevel@tonic-gate   struct stage1_5_map stage1_5_map[] =
49407c478bd9Sstevel@tonic-gate   {
49417c478bd9Sstevel@tonic-gate     {"ext2fs",   "/e2fs_stage1_5"},
49427c478bd9Sstevel@tonic-gate     {"fat",      "/fat_stage1_5"},
49437c478bd9Sstevel@tonic-gate     {"ufs2",     "/ufs2_stage1_5"},
49447c478bd9Sstevel@tonic-gate     {"ffs",      "/ffs_stage1_5"},
49457c478bd9Sstevel@tonic-gate     {"iso9660",  "/iso9660_stage1_5"},
49467c478bd9Sstevel@tonic-gate     {"jfs",      "/jfs_stage1_5"},
49477c478bd9Sstevel@tonic-gate     {"minix",    "/minix_stage1_5"},
49487c478bd9Sstevel@tonic-gate     {"reiserfs", "/reiserfs_stage1_5"},
49497c478bd9Sstevel@tonic-gate     {"vstafs",   "/vstafs_stage1_5"},
49507c478bd9Sstevel@tonic-gate     {"xfs",      "/xfs_stage1_5"},
49517c478bd9Sstevel@tonic-gate     {"ufs",      "/ufs_stage1_5"}
49527c478bd9Sstevel@tonic-gate   };
49537c478bd9Sstevel@tonic-gate 
49547c478bd9Sstevel@tonic-gate   tmp_drive = saved_drive;
49557c478bd9Sstevel@tonic-gate   tmp_partition = saved_partition;
49567c478bd9Sstevel@tonic-gate 
49577c478bd9Sstevel@tonic-gate   /* Check if the user specifies --force-lba.  */
49587c478bd9Sstevel@tonic-gate   while (1)
49597c478bd9Sstevel@tonic-gate     {
49607c478bd9Sstevel@tonic-gate       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
49617c478bd9Sstevel@tonic-gate 	{
49627c478bd9Sstevel@tonic-gate 	  is_force_lba = 1;
49637c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
49647c478bd9Sstevel@tonic-gate 	}
49657c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) == 0)
49667c478bd9Sstevel@tonic-gate 	{
49677c478bd9Sstevel@tonic-gate 	  prefix = arg + sizeof ("--prefix=") - 1;
49687c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
49697c478bd9Sstevel@tonic-gate 	  nul_terminate (prefix);
49707c478bd9Sstevel@tonic-gate 	}
49717c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
49727c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
49737c478bd9Sstevel@tonic-gate 	{
49747c478bd9Sstevel@tonic-gate 	  stage2_arg = arg;
49757c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
49767c478bd9Sstevel@tonic-gate 	  nul_terminate (stage2_arg);
49777c478bd9Sstevel@tonic-gate 	}
49787c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
49797c478bd9Sstevel@tonic-gate       else
49807c478bd9Sstevel@tonic-gate 	break;
49817c478bd9Sstevel@tonic-gate     }
49827c478bd9Sstevel@tonic-gate 
49837c478bd9Sstevel@tonic-gate   install_ptr = arg;
49847c478bd9Sstevel@tonic-gate   image_ptr = skip_to (0, install_ptr);
49857c478bd9Sstevel@tonic-gate 
49867c478bd9Sstevel@tonic-gate   /* Make sure that INSTALL_PTR is valid.  */
49877c478bd9Sstevel@tonic-gate   set_device (install_ptr);
49887c478bd9Sstevel@tonic-gate   if (errnum)
49897c478bd9Sstevel@tonic-gate     return 1;
49907c478bd9Sstevel@tonic-gate 
49917c478bd9Sstevel@tonic-gate   installed_drive = current_drive;
49927c478bd9Sstevel@tonic-gate   installed_partition = current_partition;
49937c478bd9Sstevel@tonic-gate 
49947c478bd9Sstevel@tonic-gate   /* Mount the drive pointed by IMAGE_PTR.  */
49957c478bd9Sstevel@tonic-gate   if (*image_ptr)
49967c478bd9Sstevel@tonic-gate     {
49977c478bd9Sstevel@tonic-gate       /* If the drive/partition where the images reside is specified,
49987c478bd9Sstevel@tonic-gate 	 get the drive and the partition.  */
49997c478bd9Sstevel@tonic-gate       set_device (image_ptr);
50007c478bd9Sstevel@tonic-gate       if (errnum)
50017c478bd9Sstevel@tonic-gate 	return 1;
50027c478bd9Sstevel@tonic-gate     }
50037c478bd9Sstevel@tonic-gate   else
50047c478bd9Sstevel@tonic-gate     {
50057c478bd9Sstevel@tonic-gate       /* If omitted, use SAVED_PARTITION and SAVED_DRIVE.  */
50067c478bd9Sstevel@tonic-gate       current_drive = saved_drive;
50077c478bd9Sstevel@tonic-gate       current_partition = saved_partition;
50087c478bd9Sstevel@tonic-gate     }
50097c478bd9Sstevel@tonic-gate 
50107c478bd9Sstevel@tonic-gate   image_drive = saved_drive = current_drive;
50117c478bd9Sstevel@tonic-gate   image_partition = saved_partition = current_partition;
50127c478bd9Sstevel@tonic-gate 
50137c478bd9Sstevel@tonic-gate   /* Open it.  */
50147c478bd9Sstevel@tonic-gate   if (! open_device ())
50157c478bd9Sstevel@tonic-gate     goto fail;
50167c478bd9Sstevel@tonic-gate 
50177c478bd9Sstevel@tonic-gate   /* Check if stage1 exists. If the user doesn't specify the option
50187c478bd9Sstevel@tonic-gate      `--prefix', attempt /boot/grub and /grub.  */
50197c478bd9Sstevel@tonic-gate   /* NOTE: It is dangerous to run this command without `--prefix' in the
50207c478bd9Sstevel@tonic-gate      grub shell, since that affects `--stage2'.  */
50217c478bd9Sstevel@tonic-gate   if (! prefix)
50227c478bd9Sstevel@tonic-gate     {
50237c478bd9Sstevel@tonic-gate       prefix = "/boot/grub";
50247c478bd9Sstevel@tonic-gate       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
50257c478bd9Sstevel@tonic-gate       if (! check_file (stage1))
50267c478bd9Sstevel@tonic-gate 	{
50277c478bd9Sstevel@tonic-gate 	  errnum = ERR_NONE;
50287c478bd9Sstevel@tonic-gate 	  prefix = "/grub";
50297c478bd9Sstevel@tonic-gate 	  grub_sprintf (stage1, "%s%s", prefix, "/stage1");
50307c478bd9Sstevel@tonic-gate 	  if (! check_file (stage1))
50317c478bd9Sstevel@tonic-gate 	    goto fail;
50327c478bd9Sstevel@tonic-gate 	}
50337c478bd9Sstevel@tonic-gate     }
50347c478bd9Sstevel@tonic-gate   else
50357c478bd9Sstevel@tonic-gate     {
50367c478bd9Sstevel@tonic-gate       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
50377c478bd9Sstevel@tonic-gate       if (! check_file (stage1))
50387c478bd9Sstevel@tonic-gate 	goto fail;
50397c478bd9Sstevel@tonic-gate     }
50407c478bd9Sstevel@tonic-gate 
50417c478bd9Sstevel@tonic-gate   /* The prefix was determined.  */
50427c478bd9Sstevel@tonic-gate   grub_sprintf (stage2, "%s%s", prefix, "/stage2");
50437c478bd9Sstevel@tonic-gate   grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst");
50447c478bd9Sstevel@tonic-gate   *real_config_filename = 0;
50457c478bd9Sstevel@tonic-gate 
50467c478bd9Sstevel@tonic-gate   /* Check if stage2 exists.  */
50477c478bd9Sstevel@tonic-gate   if (! check_file (stage2))
50487c478bd9Sstevel@tonic-gate     goto fail;
50497c478bd9Sstevel@tonic-gate 
50507c478bd9Sstevel@tonic-gate   {
50517c478bd9Sstevel@tonic-gate     char *fsys = fsys_table[fsys_type].name;
50527c478bd9Sstevel@tonic-gate     int i;
50537c478bd9Sstevel@tonic-gate     int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]);
50547c478bd9Sstevel@tonic-gate 
50557c478bd9Sstevel@tonic-gate     /* Iterate finding the same filesystem name as FSYS.  */
50567c478bd9Sstevel@tonic-gate     for (i = 0; i < size; i++)
50577c478bd9Sstevel@tonic-gate       if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0)
50587c478bd9Sstevel@tonic-gate 	{
50597c478bd9Sstevel@tonic-gate 	  /* OK, check if the Stage 1.5 exists.  */
50607c478bd9Sstevel@tonic-gate 	  char stage1_5[64];
50617c478bd9Sstevel@tonic-gate 
50627c478bd9Sstevel@tonic-gate 	  grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name);
50637c478bd9Sstevel@tonic-gate 	  if (check_file (stage1_5))
50647c478bd9Sstevel@tonic-gate 	    {
50657c478bd9Sstevel@tonic-gate 	      if (embed_stage1_5 (stage1_5,
50667c478bd9Sstevel@tonic-gate 				    installed_drive, installed_partition)
50677c478bd9Sstevel@tonic-gate 		  || embed_stage1_5 (stage1_5,
50687c478bd9Sstevel@tonic-gate 				     image_drive, image_partition))
50697c478bd9Sstevel@tonic-gate 		{
50707c478bd9Sstevel@tonic-gate 		  grub_strcpy (real_config_filename, config_filename);
50717c478bd9Sstevel@tonic-gate 		  sprint_device (image_drive, image_partition);
50727c478bd9Sstevel@tonic-gate 		  grub_sprintf (config_filename, "%s%s", device, stage2);
50737c478bd9Sstevel@tonic-gate 		  grub_strcpy (stage2, buffer);
50747c478bd9Sstevel@tonic-gate 		}
50757c478bd9Sstevel@tonic-gate 	    }
50767c478bd9Sstevel@tonic-gate 	  errnum = 0;
50777c478bd9Sstevel@tonic-gate 	  break;
50787c478bd9Sstevel@tonic-gate 	}
50797c478bd9Sstevel@tonic-gate   }
50807c478bd9Sstevel@tonic-gate 
50817c478bd9Sstevel@tonic-gate   /* Construct a string that is used by the command "install" as its
50827c478bd9Sstevel@tonic-gate      arguments.  */
50837c478bd9Sstevel@tonic-gate   sprint_device (installed_drive, installed_partition);
50847c478bd9Sstevel@tonic-gate 
50857c478bd9Sstevel@tonic-gate #if 1
50867c478bd9Sstevel@tonic-gate   /* Don't embed a drive number unnecessarily.  */
50877c478bd9Sstevel@tonic-gate   grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s",
50887c478bd9Sstevel@tonic-gate 		is_force_lba? "--force-lba " : "",
50897c478bd9Sstevel@tonic-gate 		stage2_arg? stage2_arg : "",
50907c478bd9Sstevel@tonic-gate 		stage2_arg? " " : "",
50917c478bd9Sstevel@tonic-gate 		stage1,
50927c478bd9Sstevel@tonic-gate 		(installed_drive != image_drive) ? "d " : "",
50937c478bd9Sstevel@tonic-gate 		device,
50947c478bd9Sstevel@tonic-gate 		stage2,
50957c478bd9Sstevel@tonic-gate 		config_filename,
50967c478bd9Sstevel@tonic-gate 		real_config_filename);
50977c478bd9Sstevel@tonic-gate #else /* NOT USED */
50987c478bd9Sstevel@tonic-gate   /* This code was used, because we belived some BIOSes had a problem
50997c478bd9Sstevel@tonic-gate      that they didn't pass a booting drive correctly. It turned out,
51007c478bd9Sstevel@tonic-gate      however, stage1 could trash a booting drive when checking LBA support,
51017c478bd9Sstevel@tonic-gate      because some BIOSes modified the register %dx in INT 13H, AH=48H.
51027c478bd9Sstevel@tonic-gate      So it becamed unclear whether GRUB should use a pre-defined booting
51037c478bd9Sstevel@tonic-gate      drive or not. If the problem still exists, it would be necessary to
51047c478bd9Sstevel@tonic-gate      switch back to this code.  */
51057c478bd9Sstevel@tonic-gate   grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s",
51067c478bd9Sstevel@tonic-gate 		is_force_lba? "--force-lba " : "",
51077c478bd9Sstevel@tonic-gate 		stage2_arg? stage2_arg : "",
51087c478bd9Sstevel@tonic-gate 		stage2_arg? " " : "",
51097c478bd9Sstevel@tonic-gate 		stage1,
51107c478bd9Sstevel@tonic-gate 		device,
51117c478bd9Sstevel@tonic-gate 		stage2,
51127c478bd9Sstevel@tonic-gate 		config_filename,
51137c478bd9Sstevel@tonic-gate 		real_config_filename);
51147c478bd9Sstevel@tonic-gate #endif /* NOT USED */
51157c478bd9Sstevel@tonic-gate 
51167c478bd9Sstevel@tonic-gate   /* Notify what will be run.  */
51177c478bd9Sstevel@tonic-gate   grub_printf (" Running \"install %s\"... ", cmd_arg);
51187c478bd9Sstevel@tonic-gate 
51197c478bd9Sstevel@tonic-gate   /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical
51207c478bd9Sstevel@tonic-gate      with IMAGE_DRIVE and IMAGE_PARTITION, respectively.  */
51217c478bd9Sstevel@tonic-gate   saved_drive = image_drive;
51227c478bd9Sstevel@tonic-gate   saved_partition = image_partition;
51237c478bd9Sstevel@tonic-gate 
51247c478bd9Sstevel@tonic-gate   /* Run the command.  */
51257c478bd9Sstevel@tonic-gate   if (! install_func (cmd_arg, flags))
51267c478bd9Sstevel@tonic-gate     grub_printf ("succeeded\nDone.\n");
51277c478bd9Sstevel@tonic-gate   else
51287c478bd9Sstevel@tonic-gate     grub_printf ("failed\n");
51297c478bd9Sstevel@tonic-gate 
51307c478bd9Sstevel@tonic-gate  fail:
51317c478bd9Sstevel@tonic-gate   saved_drive = tmp_drive;
51327c478bd9Sstevel@tonic-gate   saved_partition = tmp_partition;
51337c478bd9Sstevel@tonic-gate   return errnum;
51347c478bd9Sstevel@tonic-gate }
51357c478bd9Sstevel@tonic-gate 
51367c478bd9Sstevel@tonic-gate static struct builtin builtin_setup =
51377c478bd9Sstevel@tonic-gate {
51387c478bd9Sstevel@tonic-gate   "setup",
51397c478bd9Sstevel@tonic-gate   setup_func,
51407c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
51417c478bd9Sstevel@tonic-gate   "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
51427c478bd9Sstevel@tonic-gate   "Set up the installation of GRUB automatically. This command uses"
51437c478bd9Sstevel@tonic-gate   " the more flexible command \"install\" in the backend and installs"
51447c478bd9Sstevel@tonic-gate   " GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified,"
51457c478bd9Sstevel@tonic-gate   " then find the GRUB images in the device IMAGE_DEVICE, otherwise"
51467c478bd9Sstevel@tonic-gate   " use the current \"root device\", which can be set by the command"
51477c478bd9Sstevel@tonic-gate   " \"root\". If you know that your BIOS should support LBA but GRUB"
51487c478bd9Sstevel@tonic-gate   " doesn't work in LBA mode, specify the option `--force-lba'."
51497c478bd9Sstevel@tonic-gate   " If you install GRUB under the grub shell and you cannot unmount the"
51507c478bd9Sstevel@tonic-gate   " partition where GRUB images reside, specify the option `--stage2'"
51517c478bd9Sstevel@tonic-gate   " to tell GRUB the file name under your OS."
51527c478bd9Sstevel@tonic-gate };
51537c478bd9Sstevel@tonic-gate 
51547c478bd9Sstevel@tonic-gate 
51557c478bd9Sstevel@tonic-gate #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
51567c478bd9Sstevel@tonic-gate /* terminal */
51577c478bd9Sstevel@tonic-gate static int
51587c478bd9Sstevel@tonic-gate terminal_func (char *arg, int flags)
51597c478bd9Sstevel@tonic-gate {
51607c478bd9Sstevel@tonic-gate   /* The index of the default terminal in TERM_TABLE.  */
51617c478bd9Sstevel@tonic-gate   int default_term = -1;
51627c478bd9Sstevel@tonic-gate   struct term_entry *prev_term = current_term;
51637c478bd9Sstevel@tonic-gate   int to = -1;
51647c478bd9Sstevel@tonic-gate   int lines = 0;
51657c478bd9Sstevel@tonic-gate   int no_message = 0;
51667c478bd9Sstevel@tonic-gate   unsigned long term_flags = 0;
51677c478bd9Sstevel@tonic-gate   /* XXX: Assume less than 32 terminals.  */
51687c478bd9Sstevel@tonic-gate   unsigned long term_bitmap = 0;
51697c478bd9Sstevel@tonic-gate 
51707c478bd9Sstevel@tonic-gate   /* Get GNU-style long options.  */
51717c478bd9Sstevel@tonic-gate   while (1)
51727c478bd9Sstevel@tonic-gate     {
51737c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0)
51747c478bd9Sstevel@tonic-gate 	term_flags |= TERM_DUMB;
51757c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0)
51767c478bd9Sstevel@tonic-gate 	/* ``--no-echo'' implies ``--no-edit''.  */
51777c478bd9Sstevel@tonic-gate 	term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT);
51787c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0)
51797c478bd9Sstevel@tonic-gate 	term_flags |= TERM_NO_EDIT;
51807c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0)
51817c478bd9Sstevel@tonic-gate 	{
51827c478bd9Sstevel@tonic-gate 	  char *val = arg + sizeof ("--timeout=") - 1;
51837c478bd9Sstevel@tonic-gate 
51847c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&val, &to))
51857c478bd9Sstevel@tonic-gate 	    return 1;
51867c478bd9Sstevel@tonic-gate 	}
51877c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0)
51887c478bd9Sstevel@tonic-gate 	{
51897c478bd9Sstevel@tonic-gate 	  char *val = arg + sizeof ("--lines=") - 1;
51907c478bd9Sstevel@tonic-gate 
51917c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&val, &lines))
51927c478bd9Sstevel@tonic-gate 	    return 1;
51937c478bd9Sstevel@tonic-gate 
51947c478bd9Sstevel@tonic-gate 	  /* Probably less than four is meaningless....  */
51957c478bd9Sstevel@tonic-gate 	  if (lines < 4)
51967c478bd9Sstevel@tonic-gate 	    {
51977c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
51987c478bd9Sstevel@tonic-gate 	      return 1;
51997c478bd9Sstevel@tonic-gate 	    }
52007c478bd9Sstevel@tonic-gate 	}
52017c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0)
52027c478bd9Sstevel@tonic-gate 	no_message = 1;
52037c478bd9Sstevel@tonic-gate       else
52047c478bd9Sstevel@tonic-gate 	break;
52057c478bd9Sstevel@tonic-gate 
52067c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
52077c478bd9Sstevel@tonic-gate     }
52087c478bd9Sstevel@tonic-gate 
52097c478bd9Sstevel@tonic-gate   /* If no argument is specified, show current setting.  */
52107c478bd9Sstevel@tonic-gate   if (! *arg)
52117c478bd9Sstevel@tonic-gate     {
52127c478bd9Sstevel@tonic-gate       grub_printf ("%s%s%s%s\n",
52137c478bd9Sstevel@tonic-gate 		   current_term->name,
52147c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_DUMB ? " (dumb)" : "",
52157c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_NO_EDIT ? " (no edit)" : "",
52167c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_NO_ECHO ? " (no echo)" : "");
52177c478bd9Sstevel@tonic-gate       return 0;
52187c478bd9Sstevel@tonic-gate     }
52197c478bd9Sstevel@tonic-gate 
52207c478bd9Sstevel@tonic-gate   while (*arg)
52217c478bd9Sstevel@tonic-gate     {
52227c478bd9Sstevel@tonic-gate       int i;
52237c478bd9Sstevel@tonic-gate       char *next = skip_to (0, arg);
52247c478bd9Sstevel@tonic-gate 
52257c478bd9Sstevel@tonic-gate       nul_terminate (arg);
52267c478bd9Sstevel@tonic-gate 
52277c478bd9Sstevel@tonic-gate       for (i = 0; term_table[i].name; i++)
52287c478bd9Sstevel@tonic-gate 	{
52297c478bd9Sstevel@tonic-gate 	  if (grub_strcmp (arg, term_table[i].name) == 0)
52307c478bd9Sstevel@tonic-gate 	    {
52317c478bd9Sstevel@tonic-gate 	      if (term_table[i].flags & TERM_NEED_INIT)
52327c478bd9Sstevel@tonic-gate 		{
52337c478bd9Sstevel@tonic-gate 		  errnum = ERR_DEV_NEED_INIT;
52347c478bd9Sstevel@tonic-gate 		  return 1;
52357c478bd9Sstevel@tonic-gate 		}
52367c478bd9Sstevel@tonic-gate 
52377c478bd9Sstevel@tonic-gate 	      if (default_term < 0)
52387c478bd9Sstevel@tonic-gate 		default_term = i;
52397c478bd9Sstevel@tonic-gate 
52407c478bd9Sstevel@tonic-gate 	      term_bitmap |= (1 << i);
52417c478bd9Sstevel@tonic-gate 	      break;
52427c478bd9Sstevel@tonic-gate 	    }
52437c478bd9Sstevel@tonic-gate 	}
52447c478bd9Sstevel@tonic-gate 
52457c478bd9Sstevel@tonic-gate       if (! term_table[i].name)
52467c478bd9Sstevel@tonic-gate 	{
52477c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
52487c478bd9Sstevel@tonic-gate 	  return 1;
52497c478bd9Sstevel@tonic-gate 	}
52507c478bd9Sstevel@tonic-gate 
52517c478bd9Sstevel@tonic-gate       arg = next;
52527c478bd9Sstevel@tonic-gate     }
52537c478bd9Sstevel@tonic-gate 
52547c478bd9Sstevel@tonic-gate   /* If multiple terminals are specified, wait until the user pushes any
52557c478bd9Sstevel@tonic-gate      key on one of the terminals.  */
52567c478bd9Sstevel@tonic-gate   if (term_bitmap & ~(1 << default_term))
52577c478bd9Sstevel@tonic-gate     {
52587c478bd9Sstevel@tonic-gate       int time1, time2 = -1;
52597c478bd9Sstevel@tonic-gate 
52607c478bd9Sstevel@tonic-gate       /* XXX: Disable the pager.  */
52617c478bd9Sstevel@tonic-gate       count_lines = -1;
52627c478bd9Sstevel@tonic-gate 
52637c478bd9Sstevel@tonic-gate       /* Get current time.  */
52647c478bd9Sstevel@tonic-gate       while ((time1 = getrtsecs ()) == 0xFF)
52657c478bd9Sstevel@tonic-gate 	;
52667c478bd9Sstevel@tonic-gate 
52677c478bd9Sstevel@tonic-gate       /* Wait for a key input.  */
52687c478bd9Sstevel@tonic-gate       while (to)
52697c478bd9Sstevel@tonic-gate 	{
52707c478bd9Sstevel@tonic-gate 	  int i;
52717c478bd9Sstevel@tonic-gate 
52727c478bd9Sstevel@tonic-gate 	  for (i = 0; term_table[i].name; i++)
52737c478bd9Sstevel@tonic-gate 	    {
52747c478bd9Sstevel@tonic-gate 	      if (term_bitmap & (1 << i))
52757c478bd9Sstevel@tonic-gate 		{
52767c478bd9Sstevel@tonic-gate 		  if (term_table[i].checkkey () >= 0)
52777c478bd9Sstevel@tonic-gate 		    {
52787c478bd9Sstevel@tonic-gate 		      (void) term_table[i].getkey ();
52797c478bd9Sstevel@tonic-gate 		      default_term = i;
52807c478bd9Sstevel@tonic-gate 
52817c478bd9Sstevel@tonic-gate 		      goto end;
52827c478bd9Sstevel@tonic-gate 		    }
52837c478bd9Sstevel@tonic-gate 		}
52847c478bd9Sstevel@tonic-gate 	    }
52857c478bd9Sstevel@tonic-gate 
52867c478bd9Sstevel@tonic-gate 	  /* Prompt the user, once per sec.  */
52877c478bd9Sstevel@tonic-gate 	  if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
52887c478bd9Sstevel@tonic-gate 	    {
52897c478bd9Sstevel@tonic-gate 	      if (! no_message)
52907c478bd9Sstevel@tonic-gate 		{
52917c478bd9Sstevel@tonic-gate 		  /* Need to set CURRENT_TERM to each of selected
52927c478bd9Sstevel@tonic-gate 		     terminals.  */
52937c478bd9Sstevel@tonic-gate 		  for (i = 0; term_table[i].name; i++)
52947c478bd9Sstevel@tonic-gate 		    if (term_bitmap & (1 << i))
52957c478bd9Sstevel@tonic-gate 		      {
52967c478bd9Sstevel@tonic-gate 			current_term = term_table + i;
52977c478bd9Sstevel@tonic-gate 			grub_printf ("\rPress any key to continue.\n");
52987c478bd9Sstevel@tonic-gate 		      }
52997c478bd9Sstevel@tonic-gate 
53007c478bd9Sstevel@tonic-gate 		  /* Restore CURRENT_TERM.  */
53017c478bd9Sstevel@tonic-gate 		  current_term = prev_term;
53027c478bd9Sstevel@tonic-gate 		}
53037c478bd9Sstevel@tonic-gate 
53047c478bd9Sstevel@tonic-gate 	      time2 = time1;
53057c478bd9Sstevel@tonic-gate 	      if (to > 0)
53067c478bd9Sstevel@tonic-gate 		to--;
53077c478bd9Sstevel@tonic-gate 	    }
53087c478bd9Sstevel@tonic-gate 	}
53097c478bd9Sstevel@tonic-gate     }
53107c478bd9Sstevel@tonic-gate 
53117c478bd9Sstevel@tonic-gate  end:
53127c478bd9Sstevel@tonic-gate   current_term = term_table + default_term;
53137c478bd9Sstevel@tonic-gate   current_term->flags = term_flags;
53149b4e3ac2SWilliam Kucharski 
53157c478bd9Sstevel@tonic-gate   if (lines)
53167c478bd9Sstevel@tonic-gate     max_lines = lines;
53177c478bd9Sstevel@tonic-gate   else
53187c478bd9Sstevel@tonic-gate     max_lines = current_term->max_lines;
53197c478bd9Sstevel@tonic-gate 
53207c478bd9Sstevel@tonic-gate   /* If the interface is currently the command-line,
53217c478bd9Sstevel@tonic-gate      restart it to repaint the screen.  */
53227c478bd9Sstevel@tonic-gate   if ((current_term != prev_term) && (flags & BUILTIN_CMDLINE)){
53237c478bd9Sstevel@tonic-gate     if (prev_term->shutdown)
53247c478bd9Sstevel@tonic-gate       prev_term->shutdown();
53257c478bd9Sstevel@tonic-gate     if (current_term->startup)
53267c478bd9Sstevel@tonic-gate       current_term->startup();
53277c478bd9Sstevel@tonic-gate     grub_longjmp (restart_cmdline_env, 0);
53287c478bd9Sstevel@tonic-gate   }
53297c478bd9Sstevel@tonic-gate 
53307c478bd9Sstevel@tonic-gate   return 0;
53317c478bd9Sstevel@tonic-gate }
53327c478bd9Sstevel@tonic-gate 
53337c478bd9Sstevel@tonic-gate static struct builtin builtin_terminal =
53347c478bd9Sstevel@tonic-gate {
53357c478bd9Sstevel@tonic-gate   "terminal",
53367c478bd9Sstevel@tonic-gate   terminal_func,
53377c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
53387c478bd9Sstevel@tonic-gate   "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules] [graphics]",
53397c478bd9Sstevel@tonic-gate   "Select a terminal. When multiple terminals are specified, wait until"
53407c478bd9Sstevel@tonic-gate   " you push any key to continue. If both console and serial are specified,"
53417c478bd9Sstevel@tonic-gate   " the terminal to which you input a key first will be selected. If no"
53427c478bd9Sstevel@tonic-gate   " argument is specified, print current setting. The option --dumb"
53437c478bd9Sstevel@tonic-gate   " specifies that your terminal is dumb, otherwise, vt100-compatibility"
53447c478bd9Sstevel@tonic-gate   " is assumed. If you specify --no-echo, input characters won't be echoed."
53457c478bd9Sstevel@tonic-gate   " If you specify --no-edit, the BASH-like editing feature will be disabled."
53467c478bd9Sstevel@tonic-gate   " If --timeout is present, this command will wait at most for SECS"
53477c478bd9Sstevel@tonic-gate   " seconds. The option --lines specifies the maximum number of lines."
53487c478bd9Sstevel@tonic-gate   " The option --silent is used to suppress messages."
53497c478bd9Sstevel@tonic-gate };
53507c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
53517c478bd9Sstevel@tonic-gate 
53527c478bd9Sstevel@tonic-gate 
53537c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
53547c478bd9Sstevel@tonic-gate static int
53557c478bd9Sstevel@tonic-gate terminfo_func (char *arg, int flags)
53567c478bd9Sstevel@tonic-gate {
53577c478bd9Sstevel@tonic-gate   struct terminfo term;
53587c478bd9Sstevel@tonic-gate 
53597c478bd9Sstevel@tonic-gate   if (*arg)
53607c478bd9Sstevel@tonic-gate     {
53617c478bd9Sstevel@tonic-gate       struct
53627c478bd9Sstevel@tonic-gate       {
53637c478bd9Sstevel@tonic-gate 	const char *name;
53647c478bd9Sstevel@tonic-gate 	char *var;
53657c478bd9Sstevel@tonic-gate       }
53667c478bd9Sstevel@tonic-gate       options[] =
53677c478bd9Sstevel@tonic-gate 	{
53687c478bd9Sstevel@tonic-gate 	  {"--name=", term.name},
53697c478bd9Sstevel@tonic-gate 	  {"--cursor-address=", term.cursor_address},
53707c478bd9Sstevel@tonic-gate 	  {"--clear-screen=", term.clear_screen},
53717c478bd9Sstevel@tonic-gate 	  {"--enter-standout-mode=", term.enter_standout_mode},
53727c478bd9Sstevel@tonic-gate 	  {"--exit-standout-mode=", term.exit_standout_mode}
53737c478bd9Sstevel@tonic-gate 	};
53747c478bd9Sstevel@tonic-gate 
53757c478bd9Sstevel@tonic-gate       grub_memset (&term, 0, sizeof (term));
53767c478bd9Sstevel@tonic-gate 
53777c478bd9Sstevel@tonic-gate       while (*arg)
53787c478bd9Sstevel@tonic-gate 	{
53797c478bd9Sstevel@tonic-gate 	  int i;
53807c478bd9Sstevel@tonic-gate 	  char *next = skip_to (0, arg);
53817c478bd9Sstevel@tonic-gate 
53827c478bd9Sstevel@tonic-gate 	  nul_terminate (arg);
53837c478bd9Sstevel@tonic-gate 
53847c478bd9Sstevel@tonic-gate 	  for (i = 0; i < sizeof (options) / sizeof (options[0]); i++)
53857c478bd9Sstevel@tonic-gate 	    {
53867c478bd9Sstevel@tonic-gate 	      const char *name = options[i].name;
53877c478bd9Sstevel@tonic-gate 	      int len = grub_strlen (name);
53887c478bd9Sstevel@tonic-gate 
53897c478bd9Sstevel@tonic-gate 	      if (! grub_memcmp (arg, name, len))
53907c478bd9Sstevel@tonic-gate 		{
53917c478bd9Sstevel@tonic-gate 		  grub_strcpy (options[i].var, ti_unescape_string (arg + len));
53927c478bd9Sstevel@tonic-gate 		  break;
53937c478bd9Sstevel@tonic-gate 		}
53947c478bd9Sstevel@tonic-gate 	    }
53957c478bd9Sstevel@tonic-gate 
53967c478bd9Sstevel@tonic-gate 	  if (i == sizeof (options) / sizeof (options[0]))
53977c478bd9Sstevel@tonic-gate 	    {
53987c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
53997c478bd9Sstevel@tonic-gate 	      return errnum;
54007c478bd9Sstevel@tonic-gate 	    }
54017c478bd9Sstevel@tonic-gate 
54027c478bd9Sstevel@tonic-gate 	  arg = next;
54037c478bd9Sstevel@tonic-gate 	}
54047c478bd9Sstevel@tonic-gate 
54057c478bd9Sstevel@tonic-gate       if (term.name[0] == 0 || term.cursor_address[0] == 0)
54067c478bd9Sstevel@tonic-gate 	{
54077c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
54087c478bd9Sstevel@tonic-gate 	  return errnum;
54097c478bd9Sstevel@tonic-gate 	}
54107c478bd9Sstevel@tonic-gate 
54117c478bd9Sstevel@tonic-gate       ti_set_term (&term);
54127c478bd9Sstevel@tonic-gate     }
54137c478bd9Sstevel@tonic-gate   else
54147c478bd9Sstevel@tonic-gate     {
54157c478bd9Sstevel@tonic-gate       /* No option specifies printing out current settings.  */
54167c478bd9Sstevel@tonic-gate       ti_get_term (&term);
54177c478bd9Sstevel@tonic-gate 
54187c478bd9Sstevel@tonic-gate       grub_printf ("name=%s\n",
54197c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.name));
54207c478bd9Sstevel@tonic-gate       grub_printf ("cursor_address=%s\n",
54217c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.cursor_address));
54227c478bd9Sstevel@tonic-gate       grub_printf ("clear_screen=%s\n",
54237c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.clear_screen));
54247c478bd9Sstevel@tonic-gate       grub_printf ("enter_standout_mode=%s\n",
54257c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.enter_standout_mode));
54267c478bd9Sstevel@tonic-gate       grub_printf ("exit_standout_mode=%s\n",
54277c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.exit_standout_mode));
54287c478bd9Sstevel@tonic-gate     }
54297c478bd9Sstevel@tonic-gate 
54307c478bd9Sstevel@tonic-gate   return 0;
54317c478bd9Sstevel@tonic-gate }
54327c478bd9Sstevel@tonic-gate 
54337c478bd9Sstevel@tonic-gate static struct builtin builtin_terminfo =
54347c478bd9Sstevel@tonic-gate {
54357c478bd9Sstevel@tonic-gate   "terminfo",
54367c478bd9Sstevel@tonic-gate   terminfo_func,
54377c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
54387c478bd9Sstevel@tonic-gate   "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]"
54397c478bd9Sstevel@tonic-gate   " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]",
54407c478bd9Sstevel@tonic-gate 
54417c478bd9Sstevel@tonic-gate   "Define the capabilities of your terminal. Use this command to"
54427c478bd9Sstevel@tonic-gate   " define escape sequences, if it is not vt100-compatible."
54437c478bd9Sstevel@tonic-gate   " You may use \\e for ESC and ^X for a control character."
54447c478bd9Sstevel@tonic-gate   " If no option is specified, the current settings are printed."
54457c478bd9Sstevel@tonic-gate };
54467c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
54477c478bd9Sstevel@tonic-gate 
54487c478bd9Sstevel@tonic-gate 
54497c478bd9Sstevel@tonic-gate /* testload */
54507c478bd9Sstevel@tonic-gate static int
54517c478bd9Sstevel@tonic-gate testload_func (char *arg, int flags)
54527c478bd9Sstevel@tonic-gate {
54537c478bd9Sstevel@tonic-gate   int i;
54547c478bd9Sstevel@tonic-gate 
54557c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_NONE;
54567c478bd9Sstevel@tonic-gate 
54577c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
54587c478bd9Sstevel@tonic-gate     return 1;
54597c478bd9Sstevel@tonic-gate 
54607c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_print_func;
54617c478bd9Sstevel@tonic-gate 
54627c478bd9Sstevel@tonic-gate   /* Perform filesystem test on the specified file.  */
54637c478bd9Sstevel@tonic-gate   /* Read whole file first. */
54647c478bd9Sstevel@tonic-gate   grub_printf ("Whole file: ");
54657c478bd9Sstevel@tonic-gate 
54667c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x100000), -1);
54677c478bd9Sstevel@tonic-gate 
54687c478bd9Sstevel@tonic-gate   /* Now compare two sections of the file read differently.  */
54697c478bd9Sstevel@tonic-gate 
54707c478bd9Sstevel@tonic-gate   for (i = 0; i < 0x10ac0; i++)
54717c478bd9Sstevel@tonic-gate     {
54727c478bd9Sstevel@tonic-gate       *((unsigned char *) RAW_ADDR (0x200000 + i)) = 0;
54737c478bd9Sstevel@tonic-gate       *((unsigned char *) RAW_ADDR (0x300000 + i)) = 1;
54747c478bd9Sstevel@tonic-gate     }
54757c478bd9Sstevel@tonic-gate 
54767c478bd9Sstevel@tonic-gate   /* First partial read.  */
54777c478bd9Sstevel@tonic-gate   grub_printf ("\nPartial read 1: ");
54787c478bd9Sstevel@tonic-gate 
54797c478bd9Sstevel@tonic-gate   grub_seek (0);
54807c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200000), 0x7);
54817c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200007), 0x100);
54827c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200107), 0x10);
54837c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200117), 0x999);
54847c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200ab0), 0x10);
54857c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000);
54867c478bd9Sstevel@tonic-gate 
54877c478bd9Sstevel@tonic-gate   /* Second partial read.  */
54887c478bd9Sstevel@tonic-gate   grub_printf ("\nPartial read 2: ");
54897c478bd9Sstevel@tonic-gate 
54907c478bd9Sstevel@tonic-gate   grub_seek (0);
54917c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x300000), 0x10000);
54927c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310000), 0x10);
54937c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310010), 0x7);
54947c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310017), 0x10);
54957c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310027), 0x999);
54967c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x3109c0), 0x100);
54977c478bd9Sstevel@tonic-gate 
54987c478bd9Sstevel@tonic-gate   grub_printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
54997c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200000)),
55007c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200004)),
55017c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200008)),
55027c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x20000c)));
55037c478bd9Sstevel@tonic-gate 
55047c478bd9Sstevel@tonic-gate   grub_printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
55057c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300000)),
55067c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300004)),
55077c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300008)),
55087c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x30000c)));
55097c478bd9Sstevel@tonic-gate 
55107c478bd9Sstevel@tonic-gate   for (i = 0; i < 0x10ac0; i++)
55117c478bd9Sstevel@tonic-gate     if (*((unsigned char *) RAW_ADDR (0x200000 + i))
55127c478bd9Sstevel@tonic-gate 	!= *((unsigned char *) RAW_ADDR (0x300000 + i)))
55137c478bd9Sstevel@tonic-gate       break;
55147c478bd9Sstevel@tonic-gate 
55157c478bd9Sstevel@tonic-gate   grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos);
55167c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
55177c478bd9Sstevel@tonic-gate   grub_close ();
55187c478bd9Sstevel@tonic-gate   return 0;
55197c478bd9Sstevel@tonic-gate }
55207c478bd9Sstevel@tonic-gate 
55217c478bd9Sstevel@tonic-gate static struct builtin builtin_testload =
55227c478bd9Sstevel@tonic-gate {
55237c478bd9Sstevel@tonic-gate   "testload",
55247c478bd9Sstevel@tonic-gate   testload_func,
55257c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
55267c478bd9Sstevel@tonic-gate   "testload FILE",
55277c478bd9Sstevel@tonic-gate   "Read the entire contents of FILE in several different ways and"
55287c478bd9Sstevel@tonic-gate   " compares them, to test the filesystem code. The output is somewhat"
55297c478bd9Sstevel@tonic-gate   " cryptic, but if no errors are reported and the final `i=X,"
55307c478bd9Sstevel@tonic-gate   " filepos=Y' reading has X and Y equal, then it is definitely"
55317c478bd9Sstevel@tonic-gate   " consistent, and very likely works correctly subject to a"
55327c478bd9Sstevel@tonic-gate   " consistent offset error. If this test succeeds, then a good next"
55337c478bd9Sstevel@tonic-gate   " step is to try loading a kernel."
55347c478bd9Sstevel@tonic-gate };
55357c478bd9Sstevel@tonic-gate 
55367c478bd9Sstevel@tonic-gate 
55377c478bd9Sstevel@tonic-gate /* testvbe MODE */
55387c478bd9Sstevel@tonic-gate static int
55397c478bd9Sstevel@tonic-gate testvbe_func (char *arg, int flags)
55407c478bd9Sstevel@tonic-gate {
55417c478bd9Sstevel@tonic-gate   int mode_number;
55427c478bd9Sstevel@tonic-gate   struct vbe_controller controller;
55437c478bd9Sstevel@tonic-gate   struct vbe_mode mode;
55447c478bd9Sstevel@tonic-gate 
55457c478bd9Sstevel@tonic-gate   if (! *arg)
55467c478bd9Sstevel@tonic-gate     {
55477c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
55487c478bd9Sstevel@tonic-gate       return 1;
55497c478bd9Sstevel@tonic-gate     }
55507c478bd9Sstevel@tonic-gate 
55517c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &mode_number))
55527c478bd9Sstevel@tonic-gate     return 1;
55537c478bd9Sstevel@tonic-gate 
55547c478bd9Sstevel@tonic-gate   /* Preset `VBE2'.  */
55557c478bd9Sstevel@tonic-gate   grub_memmove (controller.signature, "VBE2", 4);
55567c478bd9Sstevel@tonic-gate 
55577c478bd9Sstevel@tonic-gate   /* Detect VBE BIOS.  */
55587c478bd9Sstevel@tonic-gate   if (get_vbe_controller_info (&controller) != 0x004F)
55597c478bd9Sstevel@tonic-gate     {
55607c478bd9Sstevel@tonic-gate       grub_printf (" VBE BIOS is not present.\n");
55617c478bd9Sstevel@tonic-gate       return 0;
55627c478bd9Sstevel@tonic-gate     }
55637c478bd9Sstevel@tonic-gate 
55647c478bd9Sstevel@tonic-gate   if (controller.version < 0x0200)
55657c478bd9Sstevel@tonic-gate     {
55667c478bd9Sstevel@tonic-gate       grub_printf (" VBE version %d.%d is not supported.\n",
55677c478bd9Sstevel@tonic-gate 		   (int) (controller.version >> 8),
55687c478bd9Sstevel@tonic-gate 		   (int) (controller.version & 0xFF));
55697c478bd9Sstevel@tonic-gate       return 0;
55707c478bd9Sstevel@tonic-gate     }
55717c478bd9Sstevel@tonic-gate 
55727c478bd9Sstevel@tonic-gate   if (get_vbe_mode_info (mode_number, &mode) != 0x004F
55737c478bd9Sstevel@tonic-gate       || (mode.mode_attributes & 0x0091) != 0x0091)
55747c478bd9Sstevel@tonic-gate     {
55757c478bd9Sstevel@tonic-gate       grub_printf (" Mode 0x%x is not supported.\n", mode_number);
55767c478bd9Sstevel@tonic-gate       return 0;
55777c478bd9Sstevel@tonic-gate     }
55787c478bd9Sstevel@tonic-gate 
55797c478bd9Sstevel@tonic-gate   /* Now trip to the graphics mode.  */
55807c478bd9Sstevel@tonic-gate   if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
55817c478bd9Sstevel@tonic-gate     {
55827c478bd9Sstevel@tonic-gate       grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
55837c478bd9Sstevel@tonic-gate       return 0;
55847c478bd9Sstevel@tonic-gate     }
55857c478bd9Sstevel@tonic-gate 
55867c478bd9Sstevel@tonic-gate   /* Draw something on the screen...  */
55877c478bd9Sstevel@tonic-gate   {
55887c478bd9Sstevel@tonic-gate     unsigned char *base_buf = (unsigned char *) mode.phys_base;
55897c478bd9Sstevel@tonic-gate     int scanline = controller.version >= 0x0300
55907c478bd9Sstevel@tonic-gate       ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline;
55917c478bd9Sstevel@tonic-gate     /* FIXME: this assumes that any depth is a modulo of 8.  */
55927c478bd9Sstevel@tonic-gate     int bpp = mode.bits_per_pixel / 8;
55937c478bd9Sstevel@tonic-gate     int width = mode.x_resolution;
55947c478bd9Sstevel@tonic-gate     int height = mode.y_resolution;
55957c478bd9Sstevel@tonic-gate     int x, y;
55967c478bd9Sstevel@tonic-gate     unsigned color = 0;
55977c478bd9Sstevel@tonic-gate 
55987c478bd9Sstevel@tonic-gate     /* Iterate drawing on the screen, until the user hits any key.  */
55997c478bd9Sstevel@tonic-gate     while (checkkey () == -1)
56007c478bd9Sstevel@tonic-gate       {
56017c478bd9Sstevel@tonic-gate 	for (y = 0; y < height; y++)
56027c478bd9Sstevel@tonic-gate 	  {
56037c478bd9Sstevel@tonic-gate 	    unsigned char *line_buf = base_buf + scanline * y;
56047c478bd9Sstevel@tonic-gate 
56057c478bd9Sstevel@tonic-gate 	    for (x = 0; x < width; x++)
56067c478bd9Sstevel@tonic-gate 	      {
56077c478bd9Sstevel@tonic-gate 		unsigned char *buf = line_buf + bpp * x;
56087c478bd9Sstevel@tonic-gate 		int i;
56097c478bd9Sstevel@tonic-gate 
56107c478bd9Sstevel@tonic-gate 		for (i = 0; i < bpp; i++, buf++)
56117c478bd9Sstevel@tonic-gate 		  *buf = (color >> (i * 8)) & 0xff;
56127c478bd9Sstevel@tonic-gate 	      }
56137c478bd9Sstevel@tonic-gate 
56147c478bd9Sstevel@tonic-gate 	    color++;
56157c478bd9Sstevel@tonic-gate 	  }
56167c478bd9Sstevel@tonic-gate       }
56177c478bd9Sstevel@tonic-gate 
56187c478bd9Sstevel@tonic-gate     /* Discard the input.  */
56197c478bd9Sstevel@tonic-gate     getkey ();
56207c478bd9Sstevel@tonic-gate   }
56217c478bd9Sstevel@tonic-gate 
56227c478bd9Sstevel@tonic-gate   /* Back to the default text mode.  */
56237c478bd9Sstevel@tonic-gate   if (set_vbe_mode (0x03) != 0x004F)
56247c478bd9Sstevel@tonic-gate     {
56257c478bd9Sstevel@tonic-gate       /* Why?!  */
56267c478bd9Sstevel@tonic-gate       grub_reboot ();
56277c478bd9Sstevel@tonic-gate     }
56287c478bd9Sstevel@tonic-gate 
56297c478bd9Sstevel@tonic-gate   return 0;
56307c478bd9Sstevel@tonic-gate }
56317c478bd9Sstevel@tonic-gate 
56327c478bd9Sstevel@tonic-gate static struct builtin builtin_testvbe =
56337c478bd9Sstevel@tonic-gate {
56347c478bd9Sstevel@tonic-gate   "testvbe",
56357c478bd9Sstevel@tonic-gate   testvbe_func,
56367c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
56377c478bd9Sstevel@tonic-gate   "testvbe MODE",
56387c478bd9Sstevel@tonic-gate   "Test the VBE mode MODE. Hit any key to return."
56397c478bd9Sstevel@tonic-gate };
56407c478bd9Sstevel@tonic-gate 
56417c478bd9Sstevel@tonic-gate 
56427c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
56437c478bd9Sstevel@tonic-gate /* tftpserver */
56447c478bd9Sstevel@tonic-gate static int
56457c478bd9Sstevel@tonic-gate tftpserver_func (char *arg, int flags)
56467c478bd9Sstevel@tonic-gate {
56477c478bd9Sstevel@tonic-gate   if (! *arg || ! ifconfig (0, 0, 0, arg))
56487c478bd9Sstevel@tonic-gate     {
56497c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
56507c478bd9Sstevel@tonic-gate       return 1;
56517c478bd9Sstevel@tonic-gate     }
56527c478bd9Sstevel@tonic-gate 
56537c478bd9Sstevel@tonic-gate   print_network_configuration ();
56547c478bd9Sstevel@tonic-gate   return 0;
56557c478bd9Sstevel@tonic-gate }
56567c478bd9Sstevel@tonic-gate 
56577c478bd9Sstevel@tonic-gate static struct builtin builtin_tftpserver =
56587c478bd9Sstevel@tonic-gate {
56597c478bd9Sstevel@tonic-gate   "tftpserver",
56607c478bd9Sstevel@tonic-gate   tftpserver_func,
56617c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
56627c478bd9Sstevel@tonic-gate   "tftpserver IPADDR",
56637c478bd9Sstevel@tonic-gate   "Override the TFTP server address."
56647c478bd9Sstevel@tonic-gate };
56657c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
56667c478bd9Sstevel@tonic-gate 
56677c478bd9Sstevel@tonic-gate 
56687c478bd9Sstevel@tonic-gate /* timeout */
56697c478bd9Sstevel@tonic-gate static int
56707c478bd9Sstevel@tonic-gate timeout_func (char *arg, int flags)
56717c478bd9Sstevel@tonic-gate {
56727c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &grub_timeout))
56737c478bd9Sstevel@tonic-gate     return 1;
56747c478bd9Sstevel@tonic-gate 
56757c478bd9Sstevel@tonic-gate   return 0;
56767c478bd9Sstevel@tonic-gate }
56777c478bd9Sstevel@tonic-gate 
56787c478bd9Sstevel@tonic-gate static struct builtin builtin_timeout =
56797c478bd9Sstevel@tonic-gate {
56807c478bd9Sstevel@tonic-gate   "timeout",
56817c478bd9Sstevel@tonic-gate   timeout_func,
56827c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
56837c478bd9Sstevel@tonic-gate #if 0
56847c478bd9Sstevel@tonic-gate   "timeout SEC",
56857c478bd9Sstevel@tonic-gate   "Set a timeout, in SEC seconds, before automatically booting the"
56867c478bd9Sstevel@tonic-gate   " default entry (normally the first entry defined)."
56877c478bd9Sstevel@tonic-gate #endif
56887c478bd9Sstevel@tonic-gate };
56897c478bd9Sstevel@tonic-gate 
56907c478bd9Sstevel@tonic-gate 
56917c478bd9Sstevel@tonic-gate /* title */
56927c478bd9Sstevel@tonic-gate static int
56937c478bd9Sstevel@tonic-gate title_func (char *arg, int flags)
56947c478bd9Sstevel@tonic-gate {
56957c478bd9Sstevel@tonic-gate   /* This function is not actually used at least currently.  */
56967c478bd9Sstevel@tonic-gate   return 0;
56977c478bd9Sstevel@tonic-gate }
56987c478bd9Sstevel@tonic-gate 
56997c478bd9Sstevel@tonic-gate static struct builtin builtin_title =
57007c478bd9Sstevel@tonic-gate {
57017c478bd9Sstevel@tonic-gate   "title",
57027c478bd9Sstevel@tonic-gate   title_func,
57037c478bd9Sstevel@tonic-gate   BUILTIN_TITLE,
57047c478bd9Sstevel@tonic-gate #if 0
57057c478bd9Sstevel@tonic-gate   "title [NAME ...]",
57067c478bd9Sstevel@tonic-gate   "Start a new boot entry, and set its name to the contents of the"
57077c478bd9Sstevel@tonic-gate   " rest of the line, starting with the first non-space character."
57087c478bd9Sstevel@tonic-gate #endif
57097c478bd9Sstevel@tonic-gate };
57107c478bd9Sstevel@tonic-gate 
57117c478bd9Sstevel@tonic-gate 
57127c478bd9Sstevel@tonic-gate /* unhide */
57137c478bd9Sstevel@tonic-gate static int
57147c478bd9Sstevel@tonic-gate unhide_func (char *arg, int flags)
57157c478bd9Sstevel@tonic-gate {
57167c478bd9Sstevel@tonic-gate   if (! set_device (arg))
57177c478bd9Sstevel@tonic-gate     return 1;
57187c478bd9Sstevel@tonic-gate 
57197c478bd9Sstevel@tonic-gate   if (! set_partition_hidden_flag (0))
57207c478bd9Sstevel@tonic-gate     return 1;
57217c478bd9Sstevel@tonic-gate 
57227c478bd9Sstevel@tonic-gate   return 0;
57237c478bd9Sstevel@tonic-gate }
57247c478bd9Sstevel@tonic-gate 
57257c478bd9Sstevel@tonic-gate static struct builtin builtin_unhide =
57267c478bd9Sstevel@tonic-gate {
57277c478bd9Sstevel@tonic-gate   "unhide",
57287c478bd9Sstevel@tonic-gate   unhide_func,
57297c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
57307c478bd9Sstevel@tonic-gate   "unhide PARTITION",
57317c478bd9Sstevel@tonic-gate   "Unhide PARTITION by clearing the \"hidden\" bit in its"
57327c478bd9Sstevel@tonic-gate   " partition type code."
57337c478bd9Sstevel@tonic-gate };
57347c478bd9Sstevel@tonic-gate 
57357c478bd9Sstevel@tonic-gate 
57367c478bd9Sstevel@tonic-gate /* uppermem */
57377c478bd9Sstevel@tonic-gate static int
57387c478bd9Sstevel@tonic-gate uppermem_func (char *arg, int flags)
57397c478bd9Sstevel@tonic-gate {
57407c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, (int *) &mbi.mem_upper))
57417c478bd9Sstevel@tonic-gate     return 1;
57427c478bd9Sstevel@tonic-gate 
57437c478bd9Sstevel@tonic-gate   mbi.flags &= ~MB_INFO_MEM_MAP;
57447c478bd9Sstevel@tonic-gate   return 0;
57457c478bd9Sstevel@tonic-gate }
57467c478bd9Sstevel@tonic-gate 
57477c478bd9Sstevel@tonic-gate static struct builtin builtin_uppermem =
57487c478bd9Sstevel@tonic-gate {
57497c478bd9Sstevel@tonic-gate   "uppermem",
57507c478bd9Sstevel@tonic-gate   uppermem_func,
57517c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
57527c478bd9Sstevel@tonic-gate   "uppermem KBYTES",
57537c478bd9Sstevel@tonic-gate   "Force GRUB to assume that only KBYTES kilobytes of upper memory are"
57547c478bd9Sstevel@tonic-gate   " installed.  Any system address range maps are discarded."
57557c478bd9Sstevel@tonic-gate };
57567c478bd9Sstevel@tonic-gate 
57577c478bd9Sstevel@tonic-gate 
57587c478bd9Sstevel@tonic-gate /* vbeprobe */
57597c478bd9Sstevel@tonic-gate static int
57607c478bd9Sstevel@tonic-gate vbeprobe_func (char *arg, int flags)
57617c478bd9Sstevel@tonic-gate {
57627c478bd9Sstevel@tonic-gate   struct vbe_controller controller;
57637c478bd9Sstevel@tonic-gate   unsigned short *mode_list;
57647c478bd9Sstevel@tonic-gate   int mode_number = -1;
57657c478bd9Sstevel@tonic-gate 
57667c478bd9Sstevel@tonic-gate   auto unsigned long vbe_far_ptr_to_linear (unsigned long);
57677c478bd9Sstevel@tonic-gate 
57687c478bd9Sstevel@tonic-gate   unsigned long vbe_far_ptr_to_linear (unsigned long ptr)
57697c478bd9Sstevel@tonic-gate     {
57707c478bd9Sstevel@tonic-gate       unsigned short seg = (ptr >> 16);
57717c478bd9Sstevel@tonic-gate       unsigned short off = (ptr & 0xFFFF);
57727c478bd9Sstevel@tonic-gate 
57737c478bd9Sstevel@tonic-gate       return (seg << 4) + off;
57747c478bd9Sstevel@tonic-gate     }
57757c478bd9Sstevel@tonic-gate 
57767c478bd9Sstevel@tonic-gate   if (*arg)
57777c478bd9Sstevel@tonic-gate     {
57787c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&arg, &mode_number))
57797c478bd9Sstevel@tonic-gate 	return 1;
57807c478bd9Sstevel@tonic-gate     }
57817c478bd9Sstevel@tonic-gate 
57827c478bd9Sstevel@tonic-gate   /* Set the signature to `VBE2', to obtain VBE 3.0 information.  */
57837c478bd9Sstevel@tonic-gate   grub_memmove (controller.signature, "VBE2", 4);
57847c478bd9Sstevel@tonic-gate 
57857c478bd9Sstevel@tonic-gate   if (get_vbe_controller_info (&controller) != 0x004F)
57867c478bd9Sstevel@tonic-gate     {
57877c478bd9Sstevel@tonic-gate       grub_printf (" VBE BIOS is not present.\n");
57887c478bd9Sstevel@tonic-gate       return 0;
57897c478bd9Sstevel@tonic-gate     }
57907c478bd9Sstevel@tonic-gate 
57917c478bd9Sstevel@tonic-gate   /* Check the version.  */
57927c478bd9Sstevel@tonic-gate   if (controller.version < 0x0200)
57937c478bd9Sstevel@tonic-gate     {
57947c478bd9Sstevel@tonic-gate       grub_printf (" VBE version %d.%d is not supported.\n",
57957c478bd9Sstevel@tonic-gate 		   (int) (controller.version >> 8),
57967c478bd9Sstevel@tonic-gate 		   (int) (controller.version & 0xFF));
57977c478bd9Sstevel@tonic-gate       return 0;
57987c478bd9Sstevel@tonic-gate     }
57997c478bd9Sstevel@tonic-gate 
58007c478bd9Sstevel@tonic-gate   /* Print some information.  */
58017c478bd9Sstevel@tonic-gate   grub_printf (" VBE version %d.%d\n",
58027c478bd9Sstevel@tonic-gate 	       (int) (controller.version >> 8),
58037c478bd9Sstevel@tonic-gate 	       (int) (controller.version & 0xFF));
58047c478bd9Sstevel@tonic-gate 
58057c478bd9Sstevel@tonic-gate   /* Iterate probing modes.  */
58067c478bd9Sstevel@tonic-gate   for (mode_list
58077c478bd9Sstevel@tonic-gate 	 = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode);
58087c478bd9Sstevel@tonic-gate        *mode_list != 0xFFFF;
58097c478bd9Sstevel@tonic-gate        mode_list++)
58107c478bd9Sstevel@tonic-gate     {
58117c478bd9Sstevel@tonic-gate       struct vbe_mode mode;
58127c478bd9Sstevel@tonic-gate 
58137c478bd9Sstevel@tonic-gate       if (get_vbe_mode_info (*mode_list, &mode) != 0x004F)
58147c478bd9Sstevel@tonic-gate 	continue;
58157c478bd9Sstevel@tonic-gate 
58167c478bd9Sstevel@tonic-gate       /* Skip this, if this is not supported or linear frame buffer
58177c478bd9Sstevel@tonic-gate 	 mode is not support.  */
58187c478bd9Sstevel@tonic-gate       if ((mode.mode_attributes & 0x0081) != 0x0081)
58197c478bd9Sstevel@tonic-gate 	continue;
58207c478bd9Sstevel@tonic-gate 
58217c478bd9Sstevel@tonic-gate       if (mode_number == -1 || mode_number == *mode_list)
58227c478bd9Sstevel@tonic-gate 	{
58237c478bd9Sstevel@tonic-gate 	  char *model;
58247c478bd9Sstevel@tonic-gate 	  switch (mode.memory_model)
58257c478bd9Sstevel@tonic-gate 	    {
58267c478bd9Sstevel@tonic-gate 	    case 0x00: model = "Text"; break;
58277c478bd9Sstevel@tonic-gate 	    case 0x01: model = "CGA graphics"; break;
58287c478bd9Sstevel@tonic-gate 	    case 0x02: model = "Hercules graphics"; break;
58297c478bd9Sstevel@tonic-gate 	    case 0x03: model = "Planar"; break;
58307c478bd9Sstevel@tonic-gate 	    case 0x04: model = "Packed pixel"; break;
58317c478bd9Sstevel@tonic-gate 	    case 0x05: model = "Non-chain 4, 256 color"; break;
58327c478bd9Sstevel@tonic-gate 	    case 0x06: model = "Direct Color"; break;
58337c478bd9Sstevel@tonic-gate 	    case 0x07: model = "YUV"; break;
58347c478bd9Sstevel@tonic-gate 	    default: model = "Unknown"; break;
58357c478bd9Sstevel@tonic-gate 	    }
58367c478bd9Sstevel@tonic-gate 
58377c478bd9Sstevel@tonic-gate 	  grub_printf ("  0x%x: %s, %ux%ux%u\n",
58387c478bd9Sstevel@tonic-gate 		       (unsigned) *mode_list,
58397c478bd9Sstevel@tonic-gate 		       model,
58407c478bd9Sstevel@tonic-gate 		       (unsigned) mode.x_resolution,
58417c478bd9Sstevel@tonic-gate 		       (unsigned) mode.y_resolution,
58427c478bd9Sstevel@tonic-gate 		       (unsigned) mode.bits_per_pixel);
58437c478bd9Sstevel@tonic-gate 
58447c478bd9Sstevel@tonic-gate 	  if (mode_number != -1)
58457c478bd9Sstevel@tonic-gate 	    break;
58467c478bd9Sstevel@tonic-gate 	}
58477c478bd9Sstevel@tonic-gate     }
58487c478bd9Sstevel@tonic-gate 
58497c478bd9Sstevel@tonic-gate   if (mode_number != -1 && mode_number != *mode_list)
58507c478bd9Sstevel@tonic-gate     grub_printf ("  Mode 0x%x is not found or supported.\n", mode_number);
58517c478bd9Sstevel@tonic-gate 
58527c478bd9Sstevel@tonic-gate   return 0;
58537c478bd9Sstevel@tonic-gate }
58547c478bd9Sstevel@tonic-gate 
58557c478bd9Sstevel@tonic-gate static struct builtin builtin_vbeprobe =
58567c478bd9Sstevel@tonic-gate {
58577c478bd9Sstevel@tonic-gate   "vbeprobe",
58587c478bd9Sstevel@tonic-gate   vbeprobe_func,
58597c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
58607c478bd9Sstevel@tonic-gate   "vbeprobe [MODE]",
58617c478bd9Sstevel@tonic-gate   "Probe VBE information. If the mode number MODE is specified, show only"
58627c478bd9Sstevel@tonic-gate   " the information about only the mode."
58637c478bd9Sstevel@tonic-gate };
58647c478bd9Sstevel@tonic-gate 
58657c478bd9Sstevel@tonic-gate 
58667c478bd9Sstevel@tonic-gate /* The table of builtin commands. Sorted in dictionary order.  */
58677c478bd9Sstevel@tonic-gate struct builtin *builtin_table[] =
58687c478bd9Sstevel@tonic-gate {
58697c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
58707c478bd9Sstevel@tonic-gate   &builtin_background,
58717c478bd9Sstevel@tonic-gate #endif
58727c478bd9Sstevel@tonic-gate   &builtin_blocklist,
58737c478bd9Sstevel@tonic-gate   &builtin_boot,
5874b1b8ab34Slling   &builtin_bootfs,
58757c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58767c478bd9Sstevel@tonic-gate   &builtin_bootp,
58777c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58787c478bd9Sstevel@tonic-gate   &builtin_cat,
58797c478bd9Sstevel@tonic-gate   &builtin_chainloader,
58807c478bd9Sstevel@tonic-gate   &builtin_clear,
58817c478bd9Sstevel@tonic-gate   &builtin_cmp,
58827c478bd9Sstevel@tonic-gate   &builtin_color,
58837c478bd9Sstevel@tonic-gate   &builtin_configfile,
58847c478bd9Sstevel@tonic-gate   &builtin_debug,
58857c478bd9Sstevel@tonic-gate   &builtin_default,
58867c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
58877c478bd9Sstevel@tonic-gate   &builtin_device,
58887c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
58897c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
58907c478bd9Sstevel@tonic-gate   &builtin_dhcp,
58917c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
58927c478bd9Sstevel@tonic-gate   &builtin_displayapm,
58937c478bd9Sstevel@tonic-gate   &builtin_displaymem,
58947c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
58957c478bd9Sstevel@tonic-gate   &builtin_dump,
58967c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
58977c478bd9Sstevel@tonic-gate   &builtin_embed,
58987c478bd9Sstevel@tonic-gate   &builtin_fallback,
58997c478bd9Sstevel@tonic-gate   &builtin_find,
5900eb2bd662Svikram   &builtin_findroot,
59017c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
59027c478bd9Sstevel@tonic-gate   &builtin_foreground,
59037c478bd9Sstevel@tonic-gate #endif
59047c478bd9Sstevel@tonic-gate   &builtin_fstest,
59057c478bd9Sstevel@tonic-gate   &builtin_geometry,
59067c478bd9Sstevel@tonic-gate   &builtin_halt,
59077c478bd9Sstevel@tonic-gate   &builtin_help,
59087c478bd9Sstevel@tonic-gate   &builtin_hiddenmenu,
59097c478bd9Sstevel@tonic-gate   &builtin_hide,
59107c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
59117c478bd9Sstevel@tonic-gate   &builtin_ifconfig,
59127c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
59137c478bd9Sstevel@tonic-gate   &builtin_impsprobe,
59147ce76caaSEnrico Perla - Sun Microsystems   &builtin_info,
59157c478bd9Sstevel@tonic-gate   &builtin_initrd,
59167c478bd9Sstevel@tonic-gate   &builtin_install,
59177c478bd9Sstevel@tonic-gate   &builtin_ioprobe,
59187c478bd9Sstevel@tonic-gate   &builtin_kernel,
5919ae115bc7Smrj   &builtin_kernel_dollar,
59207c478bd9Sstevel@tonic-gate   &builtin_lock,
59217c478bd9Sstevel@tonic-gate   &builtin_makeactive,
59227c478bd9Sstevel@tonic-gate   &builtin_map,
59237c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
59247c478bd9Sstevel@tonic-gate   &builtin_md5crypt,
59257c478bd9Sstevel@tonic-gate #endif /* USE_MD5_PASSWORDS */
5926342440ecSPrasad Singamsetty   &builtin_min_mem64,
59277c478bd9Sstevel@tonic-gate   &builtin_module,
5928ae115bc7Smrj   &builtin_module_dollar,
59297c478bd9Sstevel@tonic-gate   &builtin_modulenounzip,
59307c478bd9Sstevel@tonic-gate   &builtin_pager,
59317c478bd9Sstevel@tonic-gate   &builtin_partnew,
59327c478bd9Sstevel@tonic-gate   &builtin_parttype,
59337c478bd9Sstevel@tonic-gate   &builtin_password,
59347c478bd9Sstevel@tonic-gate   &builtin_pause,
59357c478bd9Sstevel@tonic-gate #if defined(RPC_DEBUG) && defined(SUPPORT_NETBOOT)
59367c478bd9Sstevel@tonic-gate   &builtin_portmap,
59377c478bd9Sstevel@tonic-gate #endif /* RPC_DEBUG && SUPPORT_NETBOOT */
59387c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
59397c478bd9Sstevel@tonic-gate   &builtin_quit,
59407c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
59417c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
59427c478bd9Sstevel@tonic-gate   &builtin_rarp,
59437c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
59447c478bd9Sstevel@tonic-gate   &builtin_read,
59457c478bd9Sstevel@tonic-gate   &builtin_reboot,
59467c478bd9Sstevel@tonic-gate   &builtin_root,
59477c478bd9Sstevel@tonic-gate   &builtin_rootnoverify,
59487c478bd9Sstevel@tonic-gate   &builtin_savedefault,
59497c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
59507c478bd9Sstevel@tonic-gate   &builtin_serial,
59517c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
59527c478bd9Sstevel@tonic-gate   &builtin_setkey,
59537c478bd9Sstevel@tonic-gate   &builtin_setup,
59547c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
59557c478bd9Sstevel@tonic-gate   &builtin_splashimage,
59567c478bd9Sstevel@tonic-gate #endif /* SUPPORT_GRAPHICS */
59577c478bd9Sstevel@tonic-gate #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
59587c478bd9Sstevel@tonic-gate   &builtin_terminal,
59597c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
59607c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
59617c478bd9Sstevel@tonic-gate   &builtin_terminfo,
59627c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
59637c478bd9Sstevel@tonic-gate   &builtin_testload,
59647c478bd9Sstevel@tonic-gate   &builtin_testvbe,
59657c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
59667c478bd9Sstevel@tonic-gate   &builtin_tftpserver,
59677c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
59687c478bd9Sstevel@tonic-gate   &builtin_timeout,
59697c478bd9Sstevel@tonic-gate   &builtin_title,
59707c478bd9Sstevel@tonic-gate   &builtin_unhide,
59717c478bd9Sstevel@tonic-gate   &builtin_uppermem,
59727c478bd9Sstevel@tonic-gate   &builtin_vbeprobe,
59731fac5a60Ssetje   &builtin_verbose,
59747c478bd9Sstevel@tonic-gate   0
59757c478bd9Sstevel@tonic-gate };
5976