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.
5*1a065e93SAndrew Stormont  *  Copyright 2021 RackTop Systems, Inc.
67c478bd9Sstevel@tonic-gate  *
77c478bd9Sstevel@tonic-gate  *  This program is free software; you can redistribute it and/or modify
87c478bd9Sstevel@tonic-gate  *  it under the terms of the GNU General Public License as published by
97c478bd9Sstevel@tonic-gate  *  the Free Software Foundation; either version 2 of the License, or
107c478bd9Sstevel@tonic-gate  *  (at your option) any later version.
117c478bd9Sstevel@tonic-gate  *
127c478bd9Sstevel@tonic-gate  *  This program is distributed in the hope that it will be useful,
137c478bd9Sstevel@tonic-gate  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
147c478bd9Sstevel@tonic-gate  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
157c478bd9Sstevel@tonic-gate  *  GNU General Public License for more details.
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  *  You should have received a copy of the GNU General Public License
187c478bd9Sstevel@tonic-gate  *  along with this program; if not, write to the Free Software
197c478bd9Sstevel@tonic-gate  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
207c478bd9Sstevel@tonic-gate  */
21342440ecSPrasad Singamsetty 
227c478bd9Sstevel@tonic-gate /* Include stdio.h before shared.h, because we can't define
237c478bd9Sstevel@tonic-gate    WITHOUT_LIBC_STUBS here.  */
247c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
257c478bd9Sstevel@tonic-gate # include <stdio.h>
267c478bd9Sstevel@tonic-gate #endif
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <shared.h>
297c478bd9Sstevel@tonic-gate #include <filesys.h>
307c478bd9Sstevel@tonic-gate #include <term.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
337c478bd9Sstevel@tonic-gate # include <grub.h>
347c478bd9Sstevel@tonic-gate #endif
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
377c478bd9Sstevel@tonic-gate # include <serial.h>
387c478bd9Sstevel@tonic-gate # include <terminfo.h>
397c478bd9Sstevel@tonic-gate #endif
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
427c478bd9Sstevel@tonic-gate # include <device.h>
437c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
447c478bd9Sstevel@tonic-gate # include <apic.h>
457c478bd9Sstevel@tonic-gate # include <smp-imps.h>
467c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
497c478bd9Sstevel@tonic-gate # include <md5.h>
507c478bd9Sstevel@tonic-gate #endif
517c478bd9Sstevel@tonic-gate 
52ae115bc7Smrj #include <cpu.h>
53a5602e1bSKeith M Wesolowski #include <expand.h>
54ae115bc7Smrj 
557c478bd9Sstevel@tonic-gate /* The type of kernel loaded.  */
567c478bd9Sstevel@tonic-gate kernel_t kernel_type;
577c478bd9Sstevel@tonic-gate /* The boot device.  */
587c478bd9Sstevel@tonic-gate static int bootdev;
597c478bd9Sstevel@tonic-gate /* True when the debug mode is turned on, and false
607c478bd9Sstevel@tonic-gate    when it is turned off.  */
617c478bd9Sstevel@tonic-gate int debug = 0;
627c478bd9Sstevel@tonic-gate /* The default entry.  */
637c478bd9Sstevel@tonic-gate int default_entry = 0;
647c478bd9Sstevel@tonic-gate /* The fallback entry.  */
657c478bd9Sstevel@tonic-gate int fallback_entryno;
667c478bd9Sstevel@tonic-gate int fallback_entries[MAX_FALLBACK_ENTRIES];
677c478bd9Sstevel@tonic-gate /* The number of current entry.  */
687c478bd9Sstevel@tonic-gate int current_entryno;
697c478bd9Sstevel@tonic-gate /* The address for Multiboot command-line buffer.  */
707c478bd9Sstevel@tonic-gate static char *mb_cmdline;
717c478bd9Sstevel@tonic-gate /* The password.  */
727c478bd9Sstevel@tonic-gate char *password;
737c478bd9Sstevel@tonic-gate /* The password type.  */
747c478bd9Sstevel@tonic-gate password_t password_type;
757c478bd9Sstevel@tonic-gate /* The flag for indicating that the user is authoritative.  */
767c478bd9Sstevel@tonic-gate int auth = 0;
777c478bd9Sstevel@tonic-gate /* The timeout.  */
787c478bd9Sstevel@tonic-gate int grub_timeout = -1;
797c478bd9Sstevel@tonic-gate /* Whether to show the menu or not.  */
807c478bd9Sstevel@tonic-gate int show_menu = 1;
817c478bd9Sstevel@tonic-gate /* The BIOS drive map.  */
827c478bd9Sstevel@tonic-gate static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /* Prototypes for allowing straightfoward calling of builtins functions
857c478bd9Sstevel@tonic-gate    inside other functions.  */
867c478bd9Sstevel@tonic-gate static int configfile_func (char *arg, int flags);
877c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
887c478bd9Sstevel@tonic-gate static void solaris_config_file (void);
897c478bd9Sstevel@tonic-gate #endif
907c478bd9Sstevel@tonic-gate 
91a5602e1bSKeith M Wesolowski unsigned int min_mem64 = 0;
92342440ecSPrasad Singamsetty 
937c478bd9Sstevel@tonic-gate #if defined(__sun) && !defined(GRUB_UTIL)
947c478bd9Sstevel@tonic-gate extern void __enable_execute_stack (void *);
957c478bd9Sstevel@tonic-gate void
__enable_execute_stack(void * addr)967c478bd9Sstevel@tonic-gate __enable_execute_stack (void *addr)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate }
997c478bd9Sstevel@tonic-gate #endif /* __sun && !GRUB_UTIL */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /* Initialize the data for builtins.  */
1027c478bd9Sstevel@tonic-gate void
init_builtins(void)1037c478bd9Sstevel@tonic-gate init_builtins (void)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_NONE;
1067c478bd9Sstevel@tonic-gate   /* BSD and chainloading evil hacks!  */
1077c478bd9Sstevel@tonic-gate   bootdev = set_bootdev (0);
1087c478bd9Sstevel@tonic-gate   mb_cmdline = (char *) MB_CMDLINE_BUF;
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /* Initialize the data for the configuration file.  */
1127c478bd9Sstevel@tonic-gate void
init_config(void)1137c478bd9Sstevel@tonic-gate init_config (void)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate   default_entry = 0;
1167c478bd9Sstevel@tonic-gate   password = 0;
1177c478bd9Sstevel@tonic-gate   fallback_entryno = -1;
1187c478bd9Sstevel@tonic-gate   fallback_entries[0] = -1;
1197c478bd9Sstevel@tonic-gate   grub_timeout = -1;
120b1b8ab34Slling   current_rootpool[0] = '\0';
121b1b8ab34Slling   current_bootfs[0] = '\0';
122e7cbe64fSgw   current_bootpath[0] = '\0';
123b1b8ab34Slling   current_bootfs_obj = 0;
124051aabe6Staylor   current_devid[0] = '\0';
125*1a065e93SAndrew Stormont   current_bootguid = 0;
126*1a065e93SAndrew Stormont   current_bootvdev = 0;
127b1b8ab34Slling   is_zfs_mount = 0;
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /* Check a password for correctness.  Returns 0 if password was
1317c478bd9Sstevel@tonic-gate    correct, and a value != 0 for error, similarly to strcmp. */
1327c478bd9Sstevel@tonic-gate int
check_password(char * entered,char * expected,password_t type)1337c478bd9Sstevel@tonic-gate check_password (char *entered, char* expected, password_t type)
1347c478bd9Sstevel@tonic-gate {
1357c478bd9Sstevel@tonic-gate   switch (type)
1367c478bd9Sstevel@tonic-gate     {
1377c478bd9Sstevel@tonic-gate     case PASSWORD_PLAIN:
1387c478bd9Sstevel@tonic-gate       return strcmp (entered, expected);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
1417c478bd9Sstevel@tonic-gate     case PASSWORD_MD5:
1427c478bd9Sstevel@tonic-gate       return check_md5_password (entered, expected);
1437c478bd9Sstevel@tonic-gate #endif
1447c478bd9Sstevel@tonic-gate     default:
1457c478bd9Sstevel@tonic-gate       /* unsupported password type: be secure */
1467c478bd9Sstevel@tonic-gate       return 1;
1477c478bd9Sstevel@tonic-gate     }
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /* Print which sector is read when loading a file.  */
1517c478bd9Sstevel@tonic-gate static void
disk_read_print_func(unsigned long long sector,int offset,int length)1529890706eSHans Rosenfeld disk_read_print_func(unsigned long long sector, int offset, int length)
1537c478bd9Sstevel@tonic-gate {
1549890706eSHans Rosenfeld   grub_printf ("[%llu,%d,%d]", sector, offset, length);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /* blocklist */
1597c478bd9Sstevel@tonic-gate static int
blocklist_func(char * arg,int flags)1607c478bd9Sstevel@tonic-gate blocklist_func (char *arg, int flags)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate   char *dummy = (char *) RAW_ADDR (0x100000);
1639890706eSHans Rosenfeld   unsigned long long start_sector = 0;
1647c478bd9Sstevel@tonic-gate   int num_sectors = 0;
1657c478bd9Sstevel@tonic-gate   int num_entries = 0;
1667c478bd9Sstevel@tonic-gate   int last_length = 0;
1677c478bd9Sstevel@tonic-gate 
1689890706eSHans Rosenfeld   auto void disk_read_blocklist_func (unsigned long long sector, int offset,
1691b8adde7SWilliam Kucharski       int length);
1701b8adde7SWilliam Kucharski 
1717c478bd9Sstevel@tonic-gate   /* Collect contiguous blocks into one entry as many as possible,
1727c478bd9Sstevel@tonic-gate      and print the blocklist notation on the screen.  */
1739890706eSHans Rosenfeld   auto void disk_read_blocklist_func (unsigned long long sector, int offset,
1741b8adde7SWilliam Kucharski       int length)
1757c478bd9Sstevel@tonic-gate     {
1767c478bd9Sstevel@tonic-gate       if (num_sectors > 0)
1777c478bd9Sstevel@tonic-gate 	{
1787c478bd9Sstevel@tonic-gate 	  if (start_sector + num_sectors == sector
1797c478bd9Sstevel@tonic-gate 	      && offset == 0 && last_length == SECTOR_SIZE)
1807c478bd9Sstevel@tonic-gate 	    {
1817c478bd9Sstevel@tonic-gate 	      num_sectors++;
1827c478bd9Sstevel@tonic-gate 	      last_length = length;
1837c478bd9Sstevel@tonic-gate 	      return;
1847c478bd9Sstevel@tonic-gate 	    }
1857c478bd9Sstevel@tonic-gate 	  else
1867c478bd9Sstevel@tonic-gate 	    {
1877c478bd9Sstevel@tonic-gate 	      if (last_length == SECTOR_SIZE)
1882e1aefd1SJoshua M. Clulow 		grub_printf ("%s%llu+%d", num_entries ? "," : "",
1897c478bd9Sstevel@tonic-gate 			     start_sector - part_start, num_sectors);
1907c478bd9Sstevel@tonic-gate 	      else if (num_sectors > 1)
1912e1aefd1SJoshua M. Clulow 		grub_printf ("%s%llu+%d,%lld[0-%d]", num_entries ? "," : "",
1927c478bd9Sstevel@tonic-gate 			     start_sector - part_start, num_sectors-1,
1937c478bd9Sstevel@tonic-gate 			     start_sector + num_sectors-1 - part_start,
1947c478bd9Sstevel@tonic-gate 			     last_length);
1957c478bd9Sstevel@tonic-gate 	      else
1962e1aefd1SJoshua M. Clulow 		grub_printf ("%s%llu[0-%d]", num_entries ? "," : "",
1977c478bd9Sstevel@tonic-gate 			     start_sector - part_start, last_length);
1987c478bd9Sstevel@tonic-gate 	      num_entries++;
1997c478bd9Sstevel@tonic-gate 	      num_sectors = 0;
2007c478bd9Sstevel@tonic-gate 	    }
2017c478bd9Sstevel@tonic-gate 	}
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate       if (offset > 0)
2047c478bd9Sstevel@tonic-gate 	{
2059890706eSHans Rosenfeld 	  grub_printf("%s%llu[%d-%d]", num_entries ? "," : "",
2067c478bd9Sstevel@tonic-gate 		      sector-part_start, offset, offset+length);
2077c478bd9Sstevel@tonic-gate 	  num_entries++;
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate       else
2107c478bd9Sstevel@tonic-gate 	{
2117c478bd9Sstevel@tonic-gate 	  start_sector = sector;
2127c478bd9Sstevel@tonic-gate 	  num_sectors = 1;
2137c478bd9Sstevel@tonic-gate 	  last_length = length;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate     }
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate   /* Open the file.  */
2187c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
2197c478bd9Sstevel@tonic-gate     return 1;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate   /* Print the device name.  */
2227c478bd9Sstevel@tonic-gate   grub_printf ("(%cd%d",
2237c478bd9Sstevel@tonic-gate 	       (current_drive & 0x80) ? 'h' : 'f',
2247c478bd9Sstevel@tonic-gate 	       current_drive & ~0x80);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate   if ((current_partition & 0xFF0000) != 0xFF0000)
2277c478bd9Sstevel@tonic-gate     grub_printf (",%d", (current_partition >> 16) & 0xFF);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate   if ((current_partition & 0x00FF00) != 0x00FF00)
2307c478bd9Sstevel@tonic-gate     grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate   grub_printf (")");
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate   /* Read in the whole file to DUMMY.  */
2357c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_blocklist_func;
2367c478bd9Sstevel@tonic-gate   if (! grub_read (dummy, -1))
2377c478bd9Sstevel@tonic-gate     goto fail;
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate   /* The last entry may not be printed yet.  Don't check if it is a
2407c478bd9Sstevel@tonic-gate    * full sector, since it doesn't matter if we read too much. */
2417c478bd9Sstevel@tonic-gate   if (num_sectors > 0)
2422e1aefd1SJoshua M. Clulow     grub_printf ("%s%llu+%d", num_entries ? "," : "",
2437c478bd9Sstevel@tonic-gate 		 start_sector - part_start, num_sectors);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate   grub_printf ("\n");
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate  fail:
2487c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
2497c478bd9Sstevel@tonic-gate   grub_close ();
2507c478bd9Sstevel@tonic-gate   return errnum;
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate static struct builtin builtin_blocklist =
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate   "blocklist",
2567c478bd9Sstevel@tonic-gate   blocklist_func,
2577c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
2587c478bd9Sstevel@tonic-gate   "blocklist FILE",
2597c478bd9Sstevel@tonic-gate   "Print the blocklist notation of the file FILE."
2607c478bd9Sstevel@tonic-gate };
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate /* boot */
2637c478bd9Sstevel@tonic-gate static int
boot_func(char * arg,int flags)2647c478bd9Sstevel@tonic-gate boot_func (char *arg, int flags)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate   /* Clear the int15 handler if we can boot the kernel successfully.
2677c478bd9Sstevel@tonic-gate      This assumes that the boot code never fails only if KERNEL_TYPE is
2687c478bd9Sstevel@tonic-gate      not KERNEL_TYPE_NONE. Is this assumption is bad?  */
2697c478bd9Sstevel@tonic-gate   if (kernel_type != KERNEL_TYPE_NONE)
2707c478bd9Sstevel@tonic-gate     unset_int15_handler ();
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
2737c478bd9Sstevel@tonic-gate   /* Shut down the networking.  */
2747c478bd9Sstevel@tonic-gate   cleanup_net ();
2757c478bd9Sstevel@tonic-gate #endif
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate   switch (kernel_type)
2787c478bd9Sstevel@tonic-gate     {
2797c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_FREEBSD:
2807c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_NETBSD:
2817c478bd9Sstevel@tonic-gate       /* *BSD */
2827c478bd9Sstevel@tonic-gate       bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline);
2837c478bd9Sstevel@tonic-gate       break;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
2867c478bd9Sstevel@tonic-gate       /* Linux */
2877c478bd9Sstevel@tonic-gate       linux_boot ();
2887c478bd9Sstevel@tonic-gate       break;
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
2917c478bd9Sstevel@tonic-gate       /* Big Linux */
2927c478bd9Sstevel@tonic-gate       big_linux_boot ();
2937c478bd9Sstevel@tonic-gate       break;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_CHAINLOADER:
2967c478bd9Sstevel@tonic-gate       /* Chainloader */
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate       /* Check if we should set the int13 handler.  */
2997c478bd9Sstevel@tonic-gate       if (bios_drive_map[0] != 0)
3007c478bd9Sstevel@tonic-gate 	{
3017c478bd9Sstevel@tonic-gate 	  int i;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	  /* Search for SAVED_DRIVE.  */
3047c478bd9Sstevel@tonic-gate 	  for (i = 0; i < DRIVE_MAP_SIZE; i++)
3057c478bd9Sstevel@tonic-gate 	    {
3067c478bd9Sstevel@tonic-gate 	      if (! bios_drive_map[i])
3077c478bd9Sstevel@tonic-gate 		break;
3087c478bd9Sstevel@tonic-gate 	      else if ((bios_drive_map[i] & 0xFF) == saved_drive)
3097c478bd9Sstevel@tonic-gate 		{
3107c478bd9Sstevel@tonic-gate 		  /* Exchage SAVED_DRIVE with the mapped drive.  */
3117c478bd9Sstevel@tonic-gate 		  saved_drive = (bios_drive_map[i] >> 8) & 0xFF;
3127c478bd9Sstevel@tonic-gate 		  break;
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate 	    }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	  /* Set the handler. This is somewhat dangerous.  */
3177c478bd9Sstevel@tonic-gate 	  set_int13_handler (bios_drive_map);
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate       gateA20 (0);
3217c478bd9Sstevel@tonic-gate       boot_drive = saved_drive;
3227c478bd9Sstevel@tonic-gate       chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr);
3237c478bd9Sstevel@tonic-gate       break;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_MULTIBOOT:
3267c478bd9Sstevel@tonic-gate       /* Multiboot */
3277c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
3287c478bd9Sstevel@tonic-gate #ifdef SOLARIS_NETBOOT
3297c478bd9Sstevel@tonic-gate       if (current_drive == NETWORK_DRIVE) {
3307c478bd9Sstevel@tonic-gate     	/*
3317c478bd9Sstevel@tonic-gate 	 *  XXX Solaris hack: use drive_info to pass network information
3327c478bd9Sstevel@tonic-gate 	 *  Turn off the flag bit to the loader is technically
3337c478bd9Sstevel@tonic-gate 	 *  multiboot compliant.
3347c478bd9Sstevel@tonic-gate 	 */
3357c478bd9Sstevel@tonic-gate     	mbi.flags &= ~MB_INFO_DRIVE_INFO;
3367c478bd9Sstevel@tonic-gate   	mbi.drives_length = dhcpack_length;
3377c478bd9Sstevel@tonic-gate   	mbi.drives_addr = dhcpack_buf;
3387c478bd9Sstevel@tonic-gate       }
3397c478bd9Sstevel@tonic-gate #endif /* SOLARIS_NETBOOT */
3407c478bd9Sstevel@tonic-gate #endif
3417c478bd9Sstevel@tonic-gate       multi_boot ((int) entry_addr, (int) &mbi);
3427c478bd9Sstevel@tonic-gate       break;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate     default:
3457c478bd9Sstevel@tonic-gate       errnum = ERR_BOOT_COMMAND;
3467c478bd9Sstevel@tonic-gate       return 1;
3477c478bd9Sstevel@tonic-gate     }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate   return 0;
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate static struct builtin builtin_boot =
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate   "boot",
3557c478bd9Sstevel@tonic-gate   boot_func,
3567c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3577c478bd9Sstevel@tonic-gate   "boot",
3587c478bd9Sstevel@tonic-gate   "Boot the OS/chain-loader which has been loaded."
3597c478bd9Sstevel@tonic-gate };
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
3637c478bd9Sstevel@tonic-gate /* bootp */
3647c478bd9Sstevel@tonic-gate static int
bootp_func(char * arg,int flags)3657c478bd9Sstevel@tonic-gate bootp_func (char *arg, int flags)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate   int with_configfile = 0;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
3707c478bd9Sstevel@tonic-gate       == 0)
3717c478bd9Sstevel@tonic-gate     {
3727c478bd9Sstevel@tonic-gate       with_configfile = 1;
3737c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
3747c478bd9Sstevel@tonic-gate     }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate   if (! bootp ())
3777c478bd9Sstevel@tonic-gate     {
3787c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
3797c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate       return 1;
3827c478bd9Sstevel@tonic-gate     }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
3857c478bd9Sstevel@tonic-gate   print_network_configuration ();
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate   /* XXX: this can cause an endless loop, but there is no easy way to
3887c478bd9Sstevel@tonic-gate      detect such a loop unfortunately.  */
3897c478bd9Sstevel@tonic-gate   if (with_configfile)
3907c478bd9Sstevel@tonic-gate     configfile_func (config_file, flags);
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate   return 0;
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate static struct builtin builtin_bootp =
3967c478bd9Sstevel@tonic-gate {
3977c478bd9Sstevel@tonic-gate   "bootp",
3987c478bd9Sstevel@tonic-gate   bootp_func,
3997c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
4007c478bd9Sstevel@tonic-gate   "bootp [--with-configfile]",
4017c478bd9Sstevel@tonic-gate   "Initialize a network device via BOOTP. If the option `--with-configfile'"
4027c478bd9Sstevel@tonic-gate   " is given, try to load a configuration file specified by the 150 vendor"
4037c478bd9Sstevel@tonic-gate   " tag."
4047c478bd9Sstevel@tonic-gate };
4057c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate /* cat */
4097c478bd9Sstevel@tonic-gate static int
cat_func(char * arg,int flags)4107c478bd9Sstevel@tonic-gate cat_func (char *arg, int flags)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate   char c;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
4157c478bd9Sstevel@tonic-gate     return 1;
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate   while (grub_read (&c, 1))
4187c478bd9Sstevel@tonic-gate     {
4197c478bd9Sstevel@tonic-gate       /* Because running "cat" with a binary file can confuse the terminal,
4207c478bd9Sstevel@tonic-gate 	 print only some characters as they are.  */
4217c478bd9Sstevel@tonic-gate       if (grub_isspace (c) || (c >= ' ' && c <= '~'))
4227c478bd9Sstevel@tonic-gate 	grub_putchar (c);
4237c478bd9Sstevel@tonic-gate       else
4247c478bd9Sstevel@tonic-gate 	grub_putchar ('?');
4257c478bd9Sstevel@tonic-gate     }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate   grub_close ();
4287c478bd9Sstevel@tonic-gate   return 0;
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate static struct builtin builtin_cat =
4327c478bd9Sstevel@tonic-gate {
4337c478bd9Sstevel@tonic-gate   "cat",
4347c478bd9Sstevel@tonic-gate   cat_func,
4357c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
4367c478bd9Sstevel@tonic-gate   "cat FILE",
4377c478bd9Sstevel@tonic-gate   "Print the contents of the file FILE."
4387c478bd9Sstevel@tonic-gate };
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate /* chainloader */
4427c478bd9Sstevel@tonic-gate static int
chainloader_func(char * arg,int flags)4437c478bd9Sstevel@tonic-gate chainloader_func (char *arg, int flags)
4447c478bd9Sstevel@tonic-gate {
4457c478bd9Sstevel@tonic-gate   int force = 0;
4467c478bd9Sstevel@tonic-gate   char *file = arg;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate   /* If the option `--force' is specified?  */
4497c478bd9Sstevel@tonic-gate   if (substring ("--force", arg) <= 0)
4507c478bd9Sstevel@tonic-gate     {
4517c478bd9Sstevel@tonic-gate       force = 1;
4527c478bd9Sstevel@tonic-gate       file = skip_to (0, arg);
4537c478bd9Sstevel@tonic-gate     }
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate   /* Open the file.  */
4567c478bd9Sstevel@tonic-gate   if (! grub_open (file))
4577c478bd9Sstevel@tonic-gate     {
4587c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4597c478bd9Sstevel@tonic-gate       return 1;
4607c478bd9Sstevel@tonic-gate     }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate   /* Read the first block.  */
4637c478bd9Sstevel@tonic-gate   if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE)
4647c478bd9Sstevel@tonic-gate     {
4657c478bd9Sstevel@tonic-gate       grub_close ();
4667c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate       /* This below happens, if a file whose size is less than 512 bytes
4697c478bd9Sstevel@tonic-gate 	 is loaded.  */
4707c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
4717c478bd9Sstevel@tonic-gate 	errnum = ERR_EXEC_FORMAT;
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate       return 1;
4747c478bd9Sstevel@tonic-gate     }
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate   /* If not loading it forcibly, check for the signature.  */
4777c478bd9Sstevel@tonic-gate   if (! force
4787c478bd9Sstevel@tonic-gate       && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET))
4797c478bd9Sstevel@tonic-gate 	  != BOOTSEC_SIGNATURE))
4807c478bd9Sstevel@tonic-gate     {
4817c478bd9Sstevel@tonic-gate       grub_close ();
4827c478bd9Sstevel@tonic-gate       errnum = ERR_EXEC_FORMAT;
4837c478bd9Sstevel@tonic-gate       kernel_type = KERNEL_TYPE_NONE;
4847c478bd9Sstevel@tonic-gate       return 1;
4857c478bd9Sstevel@tonic-gate     }
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate   grub_close ();
4887c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_CHAINLOADER;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate   /* XXX: Windows evil hack. For now, only the first five letters are
4917c478bd9Sstevel@tonic-gate      checked.  */
4927c478bd9Sstevel@tonic-gate   if (IS_PC_SLICE_TYPE_FAT (current_slice)
4937c478bd9Sstevel@tonic-gate       && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID,
4947c478bd9Sstevel@tonic-gate 			"MSWIN", 5))
4957c478bd9Sstevel@tonic-gate     *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS))
4967c478bd9Sstevel@tonic-gate       = part_start;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate   errnum = ERR_NONE;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate   return 0;
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate static struct builtin builtin_chainloader =
5047c478bd9Sstevel@tonic-gate {
5057c478bd9Sstevel@tonic-gate   "chainloader",
5067c478bd9Sstevel@tonic-gate   chainloader_func,
5077c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
5087c478bd9Sstevel@tonic-gate   "chainloader [--force] FILE",
5097c478bd9Sstevel@tonic-gate   "Load the chain-loader FILE. If --force is specified, then load it"
5107c478bd9Sstevel@tonic-gate   " forcibly, whether the boot loader signature is present or not."
5117c478bd9Sstevel@tonic-gate };
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate /* This function could be used to debug new filesystem code. Put a file
5157c478bd9Sstevel@tonic-gate    in the new filesystem and the same file in a well-tested filesystem.
5167c478bd9Sstevel@tonic-gate    Then, run "cmp" with the files. If no output is obtained, probably
5177c478bd9Sstevel@tonic-gate    the code is good, otherwise investigate what's wrong...  */
5187c478bd9Sstevel@tonic-gate /* cmp FILE1 FILE2 */
5197c478bd9Sstevel@tonic-gate static int
cmp_func(char * arg,int flags)5207c478bd9Sstevel@tonic-gate cmp_func (char *arg, int flags)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate   /* The filenames.  */
5237c478bd9Sstevel@tonic-gate   char *file1, *file2;
5247c478bd9Sstevel@tonic-gate   /* The addresses.  */
5257c478bd9Sstevel@tonic-gate   char *addr1, *addr2;
5267c478bd9Sstevel@tonic-gate   int i;
5277c478bd9Sstevel@tonic-gate   /* The size of the file.  */
5287c478bd9Sstevel@tonic-gate   int size;
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate   /* Get the filenames from ARG.  */
5317c478bd9Sstevel@tonic-gate   file1 = arg;
5327c478bd9Sstevel@tonic-gate   file2 = skip_to (0, arg);
5337c478bd9Sstevel@tonic-gate   if (! *file1 || ! *file2)
5347c478bd9Sstevel@tonic-gate     {
5357c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
5367c478bd9Sstevel@tonic-gate       return 1;
5377c478bd9Sstevel@tonic-gate     }
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate   /* Terminate the filenames for convenience.  */
5407c478bd9Sstevel@tonic-gate   nul_terminate (file1);
5417c478bd9Sstevel@tonic-gate   nul_terminate (file2);
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate   /* Read the whole data from FILE1.  */
5447c478bd9Sstevel@tonic-gate   addr1 = (char *) RAW_ADDR (0x100000);
5457c478bd9Sstevel@tonic-gate   if (! grub_open (file1))
5467c478bd9Sstevel@tonic-gate     return 1;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate   /* Get the size.  */
5497c478bd9Sstevel@tonic-gate   size = filemax;
5507c478bd9Sstevel@tonic-gate   if (grub_read (addr1, -1) != size)
5517c478bd9Sstevel@tonic-gate     {
5527c478bd9Sstevel@tonic-gate       grub_close ();
5537c478bd9Sstevel@tonic-gate       return 1;
5547c478bd9Sstevel@tonic-gate     }
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate   grub_close ();
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate   /* Read the whole data from FILE2.  */
5597c478bd9Sstevel@tonic-gate   addr2 = addr1 + size;
5607c478bd9Sstevel@tonic-gate   if (! grub_open (file2))
5617c478bd9Sstevel@tonic-gate     return 1;
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate   /* Check if the size of FILE2 is equal to the one of FILE2.  */
5647c478bd9Sstevel@tonic-gate   if (size != filemax)
5657c478bd9Sstevel@tonic-gate     {
5667c478bd9Sstevel@tonic-gate       grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n",
5677c478bd9Sstevel@tonic-gate 		   size, file1, filemax, file2);
5687c478bd9Sstevel@tonic-gate       grub_close ();
5697c478bd9Sstevel@tonic-gate       return 0;
5707c478bd9Sstevel@tonic-gate     }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate   if (! grub_read (addr2, -1))
5737c478bd9Sstevel@tonic-gate     {
5747c478bd9Sstevel@tonic-gate       grub_close ();
5757c478bd9Sstevel@tonic-gate       return 1;
5767c478bd9Sstevel@tonic-gate     }
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate   grub_close ();
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate   /* Now compare ADDR1 with ADDR2.  */
5817c478bd9Sstevel@tonic-gate   for (i = 0; i < size; i++)
5827c478bd9Sstevel@tonic-gate     {
5837c478bd9Sstevel@tonic-gate       if (addr1[i] != addr2[i])
5847c478bd9Sstevel@tonic-gate 	grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n",
5857c478bd9Sstevel@tonic-gate 		     i, (unsigned) addr1[i], file1,
5867c478bd9Sstevel@tonic-gate 		     (unsigned) addr2[i], file2);
5877c478bd9Sstevel@tonic-gate     }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate   return 0;
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate static struct builtin builtin_cmp =
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate   "cmp",
5957c478bd9Sstevel@tonic-gate   cmp_func,
5967c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
5977c478bd9Sstevel@tonic-gate   "cmp FILE1 FILE2",
5987c478bd9Sstevel@tonic-gate   "Compare the file FILE1 with the FILE2 and inform the different values"
5997c478bd9Sstevel@tonic-gate   " if any."
6007c478bd9Sstevel@tonic-gate };
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate /* color */
6047c478bd9Sstevel@tonic-gate /* Set new colors used for the menu interface. Support two methods to
6057c478bd9Sstevel@tonic-gate    specify a color name: a direct integer representation and a symbolic
6067c478bd9Sstevel@tonic-gate    color name. An example of the latter is "blink-light-gray/blue".  */
6077c478bd9Sstevel@tonic-gate static int
color_func(char * arg,int flags)6087c478bd9Sstevel@tonic-gate color_func (char *arg, int flags)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate   char *normal;
6117c478bd9Sstevel@tonic-gate   char *highlight;
6127c478bd9Sstevel@tonic-gate   int new_normal_color;
6137c478bd9Sstevel@tonic-gate   int new_highlight_color;
6147c478bd9Sstevel@tonic-gate   static char *color_list[16] =
6157c478bd9Sstevel@tonic-gate   {
6167c478bd9Sstevel@tonic-gate     "black",
6177c478bd9Sstevel@tonic-gate     "blue",
6187c478bd9Sstevel@tonic-gate     "green",
6197c478bd9Sstevel@tonic-gate     "cyan",
6207c478bd9Sstevel@tonic-gate     "red",
6217c478bd9Sstevel@tonic-gate     "magenta",
6227c478bd9Sstevel@tonic-gate     "brown",
6237c478bd9Sstevel@tonic-gate     "light-gray",
6247c478bd9Sstevel@tonic-gate     "dark-gray",
6257c478bd9Sstevel@tonic-gate     "light-blue",
6267c478bd9Sstevel@tonic-gate     "light-green",
6277c478bd9Sstevel@tonic-gate     "light-cyan",
6287c478bd9Sstevel@tonic-gate     "light-red",
6297c478bd9Sstevel@tonic-gate     "light-magenta",
6307c478bd9Sstevel@tonic-gate     "yellow",
6317c478bd9Sstevel@tonic-gate     "white"
6327c478bd9Sstevel@tonic-gate   };
6337c478bd9Sstevel@tonic-gate 
6341b8adde7SWilliam Kucharski   auto int color_number (char *str);
6351b8adde7SWilliam Kucharski 
6367c478bd9Sstevel@tonic-gate   /* Convert the color name STR into the magical number.  */
6371b8adde7SWilliam Kucharski   auto int color_number (char *str)
6387c478bd9Sstevel@tonic-gate     {
6397c478bd9Sstevel@tonic-gate       char *ptr;
6407c478bd9Sstevel@tonic-gate       int i;
6417c478bd9Sstevel@tonic-gate       int color = 0;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate       /* Find the separator.  */
6447c478bd9Sstevel@tonic-gate       for (ptr = str; *ptr && *ptr != '/'; ptr++)
6457c478bd9Sstevel@tonic-gate 	;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate       /* If not found, return -1.  */
6487c478bd9Sstevel@tonic-gate       if (! *ptr)
6497c478bd9Sstevel@tonic-gate 	return -1;
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate       /* Terminate the string STR.  */
6527c478bd9Sstevel@tonic-gate       *ptr++ = 0;
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate       /* If STR contains the prefix "blink-", then set the `blink' bit
6557c478bd9Sstevel@tonic-gate 	 in COLOR.  */
6567c478bd9Sstevel@tonic-gate       if (substring ("blink-", str) <= 0)
6577c478bd9Sstevel@tonic-gate 	{
6587c478bd9Sstevel@tonic-gate 	  color = 0x80;
6597c478bd9Sstevel@tonic-gate 	  str += 6;
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate       /* Search for the color name.  */
6637c478bd9Sstevel@tonic-gate       for (i = 0; i < 16; i++)
6647c478bd9Sstevel@tonic-gate 	if (grub_strcmp (color_list[i], str) == 0)
6657c478bd9Sstevel@tonic-gate 	  {
6667c478bd9Sstevel@tonic-gate 	    color |= i;
6677c478bd9Sstevel@tonic-gate 	    break;
6687c478bd9Sstevel@tonic-gate 	  }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate       if (i == 16)
6717c478bd9Sstevel@tonic-gate 	return -1;
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate       str = ptr;
6747c478bd9Sstevel@tonic-gate       nul_terminate (str);
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate       /* Search for the color name.  */
6777c478bd9Sstevel@tonic-gate       for (i = 0; i < 8; i++)
6787c478bd9Sstevel@tonic-gate 	if (grub_strcmp (color_list[i], str) == 0)
6797c478bd9Sstevel@tonic-gate 	  {
6807c478bd9Sstevel@tonic-gate 	    color |= i << 4;
6817c478bd9Sstevel@tonic-gate 	    break;
6827c478bd9Sstevel@tonic-gate 	  }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate       if (i == 8)
6857c478bd9Sstevel@tonic-gate 	return -1;
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate       return color;
6887c478bd9Sstevel@tonic-gate     }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate   normal = arg;
6917c478bd9Sstevel@tonic-gate   highlight = skip_to (0, arg);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate   new_normal_color = color_number (normal);
6947c478bd9Sstevel@tonic-gate   if (new_normal_color < 0 && ! safe_parse_maxint (&normal, &new_normal_color))
6957c478bd9Sstevel@tonic-gate     return 1;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate   /* The second argument is optional, so set highlight_color
6987c478bd9Sstevel@tonic-gate      to inverted NORMAL_COLOR.  */
6997c478bd9Sstevel@tonic-gate   if (! *highlight)
7007c478bd9Sstevel@tonic-gate     new_highlight_color = ((new_normal_color >> 4)
7017c478bd9Sstevel@tonic-gate 			   | ((new_normal_color & 0xf) << 4));
7027c478bd9Sstevel@tonic-gate   else
7037c478bd9Sstevel@tonic-gate     {
7047c478bd9Sstevel@tonic-gate       new_highlight_color = color_number (highlight);
7057c478bd9Sstevel@tonic-gate       if (new_highlight_color < 0
7067c478bd9Sstevel@tonic-gate 	  && ! safe_parse_maxint (&highlight, &new_highlight_color))
7077c478bd9Sstevel@tonic-gate 	return 1;
7087c478bd9Sstevel@tonic-gate     }
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate   if (current_term->setcolor)
7117c478bd9Sstevel@tonic-gate     current_term->setcolor (new_normal_color, new_highlight_color);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate   return 0;
7147c478bd9Sstevel@tonic-gate }
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate static struct builtin builtin_color =
7177c478bd9Sstevel@tonic-gate {
7187c478bd9Sstevel@tonic-gate   "color",
7197c478bd9Sstevel@tonic-gate   color_func,
7207c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
7217c478bd9Sstevel@tonic-gate   "color NORMAL [HIGHLIGHT]",
7227c478bd9Sstevel@tonic-gate   "Change the menu colors. The color NORMAL is used for most"
7237c478bd9Sstevel@tonic-gate   " lines in the menu, and the color HIGHLIGHT is used to highlight the"
7247c478bd9Sstevel@tonic-gate   " line where the cursor points. If you omit HIGHLIGHT, then the"
7257c478bd9Sstevel@tonic-gate   " inverted color of NORMAL is used for the highlighted line."
7267c478bd9Sstevel@tonic-gate   " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
7277c478bd9Sstevel@tonic-gate   " A symbolic color name must be one of these: black, blue, green,"
7287c478bd9Sstevel@tonic-gate   " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
7297c478bd9Sstevel@tonic-gate   " light-green, light-cyan, light-red, light-magenta, yellow and white."
7307c478bd9Sstevel@tonic-gate   " But only the first eight names can be used for BG. You can prefix"
7317c478bd9Sstevel@tonic-gate   " \"blink-\" to FG if you want a blinking foreground color."
7327c478bd9Sstevel@tonic-gate };
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate /* configfile */
7367c478bd9Sstevel@tonic-gate static int
configfile_func(char * arg,int flags)7377c478bd9Sstevel@tonic-gate configfile_func (char *arg, int flags)
7387c478bd9Sstevel@tonic-gate {
7397c478bd9Sstevel@tonic-gate   char *new_config = config_file;
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate   /* Check if the file ARG is present.  */
7427c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
7437c478bd9Sstevel@tonic-gate     return 1;
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate   grub_close ();
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate   /* Copy ARG to CONFIG_FILE.  */
7487c478bd9Sstevel@tonic-gate   while ((*new_config++ = *arg++) != 0)
7497c478bd9Sstevel@tonic-gate     ;
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
7527c478bd9Sstevel@tonic-gate   /* Force to load the configuration file.  */
7537c478bd9Sstevel@tonic-gate   use_config_file = 1;
7547c478bd9Sstevel@tonic-gate #endif
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate   /* Make sure that the user will not be authoritative.  */
7577c478bd9Sstevel@tonic-gate   auth = 0;
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate   /* Restart cmain.  */
7607c478bd9Sstevel@tonic-gate   grub_longjmp (restart_env, 0);
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate   /* Never reach here.  */
7637c478bd9Sstevel@tonic-gate   return 0;
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate static struct builtin builtin_configfile =
7677c478bd9Sstevel@tonic-gate {
7687c478bd9Sstevel@tonic-gate   "configfile",
7697c478bd9Sstevel@tonic-gate   configfile_func,
7707c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
7717c478bd9Sstevel@tonic-gate   "configfile FILE",
7727c478bd9Sstevel@tonic-gate   "Load FILE as the configuration file."
7737c478bd9Sstevel@tonic-gate };
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate /* debug */
7777c478bd9Sstevel@tonic-gate static int
debug_func(char * arg,int flags)7787c478bd9Sstevel@tonic-gate debug_func (char *arg, int flags)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate   if (debug)
7817c478bd9Sstevel@tonic-gate     {
7827c478bd9Sstevel@tonic-gate       debug = 0;
7837c478bd9Sstevel@tonic-gate       grub_printf (" Debug mode is turned off\n");
7847c478bd9Sstevel@tonic-gate     }
7857c478bd9Sstevel@tonic-gate   else
7867c478bd9Sstevel@tonic-gate     {
7877c478bd9Sstevel@tonic-gate       debug = 1;
7887c478bd9Sstevel@tonic-gate       grub_printf (" Debug mode is turned on\n");
7897c478bd9Sstevel@tonic-gate     }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate   return 0;
7927c478bd9Sstevel@tonic-gate }
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate static struct builtin builtin_debug =
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate   "debug",
7977c478bd9Sstevel@tonic-gate   debug_func,
7987c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
7997c478bd9Sstevel@tonic-gate   "debug",
8007c478bd9Sstevel@tonic-gate   "Turn on/off the debug mode."
8017c478bd9Sstevel@tonic-gate };
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate /* default */
8057c478bd9Sstevel@tonic-gate static int
default_func(char * arg,int flags)8067c478bd9Sstevel@tonic-gate default_func (char *arg, int flags)
8077c478bd9Sstevel@tonic-gate {
8087c478bd9Sstevel@tonic-gate #ifndef SUPPORT_DISKLESS
8097c478bd9Sstevel@tonic-gate   if (grub_strcmp (arg, "saved") == 0)
8107c478bd9Sstevel@tonic-gate     {
8117c478bd9Sstevel@tonic-gate       default_entry = saved_entryno;
8127c478bd9Sstevel@tonic-gate       return 0;
8137c478bd9Sstevel@tonic-gate     }
8147c478bd9Sstevel@tonic-gate #endif /* SUPPORT_DISKLESS */
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &default_entry))
8177c478bd9Sstevel@tonic-gate     return 1;
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate   return 0;
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate static struct builtin builtin_default =
8237c478bd9Sstevel@tonic-gate {
8247c478bd9Sstevel@tonic-gate   "default",
8257c478bd9Sstevel@tonic-gate   default_func,
8267c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
8277c478bd9Sstevel@tonic-gate #if 0
8287c478bd9Sstevel@tonic-gate   "default [NUM | `saved']",
8297c478bd9Sstevel@tonic-gate   "Set the default entry to entry number NUM (if not specified, it is"
8307c478bd9Sstevel@tonic-gate   " 0, the first entry) or the entry number saved by savedefault."
8317c478bd9Sstevel@tonic-gate #endif
8327c478bd9Sstevel@tonic-gate };
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
8367c478bd9Sstevel@tonic-gate /* device */
8377c478bd9Sstevel@tonic-gate static int
device_func(char * arg,int flags)8387c478bd9Sstevel@tonic-gate device_func (char *arg, int flags)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate   char *drive = arg;
8417c478bd9Sstevel@tonic-gate   char *device;
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate   /* Get the drive number from DRIVE.  */
8447c478bd9Sstevel@tonic-gate   if (! set_device (drive))
8457c478bd9Sstevel@tonic-gate     return 1;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate   /* Get the device argument.  */
8487c478bd9Sstevel@tonic-gate   device = skip_to (0, drive);
8497c478bd9Sstevel@tonic-gate 
8507c478bd9Sstevel@tonic-gate   /* Terminate DEVICE.  */
8517c478bd9Sstevel@tonic-gate   nul_terminate (device);
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate   if (! *device || ! check_device (device))
8547c478bd9Sstevel@tonic-gate     {
8557c478bd9Sstevel@tonic-gate       errnum = ERR_FILE_NOT_FOUND;
8567c478bd9Sstevel@tonic-gate       return 1;
8577c478bd9Sstevel@tonic-gate     }
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate   assign_device_name (current_drive, device);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate   return 0;
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate static struct builtin builtin_device =
8657c478bd9Sstevel@tonic-gate {
8667c478bd9Sstevel@tonic-gate   "device",
8677c478bd9Sstevel@tonic-gate   device_func,
8687c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
8697c478bd9Sstevel@tonic-gate   "device DRIVE DEVICE",
8707c478bd9Sstevel@tonic-gate   "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command"
8717c478bd9Sstevel@tonic-gate   " can be used only in the grub shell."
8727c478bd9Sstevel@tonic-gate };
8737c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
8767c478bd9Sstevel@tonic-gate /* Debug Function for RPC */
8777c478bd9Sstevel@tonic-gate #ifdef RPC_DEBUG
8787c478bd9Sstevel@tonic-gate /* portmap */
8797c478bd9Sstevel@tonic-gate static int
portmap_func(char * arg,int flags)8807c478bd9Sstevel@tonic-gate portmap_func (char *arg, int flags)
8817c478bd9Sstevel@tonic-gate {
8827c478bd9Sstevel@tonic-gate 	int port, prog, ver;
8837c478bd9Sstevel@tonic-gate 	if (! grub_eth_probe ()){
8847c478bd9Sstevel@tonic-gate 		grub_printf ("No ethernet card found.\n");
8857c478bd9Sstevel@tonic-gate 		errnum = ERR_DEV_VALUES;
8867c478bd9Sstevel@tonic-gate 		return 1;
8877c478bd9Sstevel@tonic-gate 	}
8887c478bd9Sstevel@tonic-gate 	if ((prog = getdec(&arg)) == -1){
8897c478bd9Sstevel@tonic-gate 		grub_printf("Error prog number\n");
8907c478bd9Sstevel@tonic-gate 		return 1;
8917c478bd9Sstevel@tonic-gate 	}
8927c478bd9Sstevel@tonic-gate 	arg = skip_to (0, arg);
8937c478bd9Sstevel@tonic-gate 	if ((ver = getdec(&arg)) == -1){
8947c478bd9Sstevel@tonic-gate 		grub_printf("Error ver number\n");
8957c478bd9Sstevel@tonic-gate 		return 1;
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate 	port = __pmapudp_getport(ARP_SERVER, prog, ver);
8987c478bd9Sstevel@tonic-gate 	printf("portmap getport %d", port);
8997c478bd9Sstevel@tonic-gate 	return 0;
9007c478bd9Sstevel@tonic-gate }
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate static struct builtin builtin_portmap =
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate 	"portmap",
9057c478bd9Sstevel@tonic-gate 	portmap_func,
9067c478bd9Sstevel@tonic-gate 	BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
9077c478bd9Sstevel@tonic-gate 	"portmap prog_number vers_number",
9087c478bd9Sstevel@tonic-gate 	"Do portmap with the prog_number and vers_number"
9097c478bd9Sstevel@tonic-gate };
9107c478bd9Sstevel@tonic-gate #endif /* RPC_DEBUG */
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate /* dhcp */
9137c478bd9Sstevel@tonic-gate static int
dhcp_func(char * arg,int flags)9147c478bd9Sstevel@tonic-gate dhcp_func (char *arg, int flags)
9157c478bd9Sstevel@tonic-gate {
9167c478bd9Sstevel@tonic-gate   int with_configfile = 0;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
9197c478bd9Sstevel@tonic-gate       == 0)
9207c478bd9Sstevel@tonic-gate     {
9217c478bd9Sstevel@tonic-gate       with_configfile = 1;
9227c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
9237c478bd9Sstevel@tonic-gate     }
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate   if (! dhcp ())
9267c478bd9Sstevel@tonic-gate     {
9277c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
9287c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate       return 1;
9317c478bd9Sstevel@tonic-gate     }
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
9347c478bd9Sstevel@tonic-gate   print_network_configuration ();
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate   /* XXX: this can cause an endless loop, but there is no easy way to
9377c478bd9Sstevel@tonic-gate      detect such a loop unfortunately.  */
9387c478bd9Sstevel@tonic-gate   if (with_configfile)
9397c478bd9Sstevel@tonic-gate     configfile_func (config_file, flags);
9407c478bd9Sstevel@tonic-gate   else
9417c478bd9Sstevel@tonic-gate     solaris_config_file();
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate   return 0;
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate 
9462506833eSJan Setje-Eilers static int
test_config_file(char * menufile)9472506833eSJan Setje-Eilers test_config_file(char *menufile)
9482506833eSJan Setje-Eilers {
9492506833eSJan Setje-Eilers 	int err;
9502506833eSJan Setje-Eilers 
9512506833eSJan Setje-Eilers 	/*
9522506833eSJan Setje-Eilers 	 * If the file exists, make it the default. Else, fallback
9532506833eSJan Setje-Eilers 	 * to what it was.  Make sure we don't change errnum in the
9542506833eSJan Setje-Eilers 	 * process.
9552506833eSJan Setje-Eilers 	 */
9562506833eSJan Setje-Eilers 	err = errnum;
9572506833eSJan Setje-Eilers 	if (grub_open(menufile)) {
9582506833eSJan Setje-Eilers 		grub_strcpy(config_file, menufile);
9592506833eSJan Setje-Eilers 		grub_close();
9602506833eSJan Setje-Eilers 		errnum = err;
9612506833eSJan Setje-Eilers 		return (1);
9622506833eSJan Setje-Eilers 	}
9632506833eSJan Setje-Eilers 	errnum = err;
9642506833eSJan Setje-Eilers 	return (0);
9652506833eSJan Setje-Eilers }
9662506833eSJan Setje-Eilers 
solaris_config_file(void)9677c478bd9Sstevel@tonic-gate static void solaris_config_file (void)
9687c478bd9Sstevel@tonic-gate {
9697c478bd9Sstevel@tonic-gate 	static char menufile[64];
9707c478bd9Sstevel@tonic-gate 	static char hexdigit[] = "0123456789ABCDEF";
9717c478bd9Sstevel@tonic-gate 	char *c = menufile;
9727c478bd9Sstevel@tonic-gate 	int i;
9737c478bd9Sstevel@tonic-gate 
9742506833eSJan Setje-Eilers 	/*
9752506833eSJan Setje-Eilers 	 * if DHCP option 150 has been provided, config_file will
9762506833eSJan Setje-Eilers 	 * already contain the string, try it.
9772506833eSJan Setje-Eilers 	 */
9782506833eSJan Setje-Eilers 	if (configfile_origin == CFG_150) {
9792506833eSJan Setje-Eilers 		if (test_config_file(config_file))
9802506833eSJan Setje-Eilers 			return;
9812506833eSJan Setje-Eilers 	}
9827c478bd9Sstevel@tonic-gate 
9832506833eSJan Setje-Eilers 	/*
9842506833eSJan Setje-Eilers 	 * try to find host (MAC address) specific configfile:
9852506833eSJan Setje-Eilers 	 * menu.lst.01<ether_addr>
9862506833eSJan Setje-Eilers 	 */
9872269adc8Sszhou 	grub_strcpy(c, "menu.lst.01");
9887c478bd9Sstevel@tonic-gate 	c += grub_strlen(c);
9897c478bd9Sstevel@tonic-gate 	for (i = 0; i < ETH_ALEN; i++) {
9907c478bd9Sstevel@tonic-gate 		unsigned char b = arptable[ARP_CLIENT].node[i];
9917c478bd9Sstevel@tonic-gate 		*c++ = hexdigit[b >> 4];
9927c478bd9Sstevel@tonic-gate 		*c++ = hexdigit[b & 0xf];
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 	*c = 0;
9952506833eSJan Setje-Eilers 	configfile_origin = CFG_MAC;
9962506833eSJan Setje-Eilers 	if (test_config_file(menufile))
9972506833eSJan Setje-Eilers 		return;
9987c478bd9Sstevel@tonic-gate 
9996759d08fScasper 	/*
10002506833eSJan Setje-Eilers 	 * try to find a configfile derived from the DHCP/bootp
10012506833eSJan Setje-Eilers 	 * BootFile string: menu.lst.<BootFile>
10027c478bd9Sstevel@tonic-gate 	 */
10032506833eSJan Setje-Eilers 	if (bootfile != NULL && bootfile[0] != 0) {
10042506833eSJan Setje-Eilers 		c = menufile;
10052506833eSJan Setje-Eilers 		grub_strcpy(c, "menu.lst.");
10062506833eSJan Setje-Eilers 		c += grub_strlen("menu.lst.");
10072506833eSJan Setje-Eilers 		i = grub_strlen("pxegrub.");
10082506833eSJan Setje-Eilers 		if (grub_memcmp(bootfile, "pxegrub.", i) == 0)
10092506833eSJan Setje-Eilers 			grub_strcpy(c, bootfile + i);
10102506833eSJan Setje-Eilers 		else
10112506833eSJan Setje-Eilers 			grub_strcpy(c, bootfile);
10122506833eSJan Setje-Eilers 		configfile_origin = CFG_BOOTFILE;
10132506833eSJan Setje-Eilers 		if (test_config_file(menufile))
10142506833eSJan Setje-Eilers 			return;
10157c478bd9Sstevel@tonic-gate 	}
10162506833eSJan Setje-Eilers 
10172506833eSJan Setje-Eilers 	/*
10182506833eSJan Setje-Eilers 	 * Default to hard coded "/boot/grub/menu.lst" config file.
10192506833eSJan Setje-Eilers 	 * This is the last resort, so there's no need to test it,
10202506833eSJan Setje-Eilers 	 * as there's nothing else to try.
10212506833eSJan Setje-Eilers 	 */
10222506833eSJan Setje-Eilers 	char *cp = config_file;
10232506833eSJan Setje-Eilers 	/* skip leading slashes for tftp */
10242506833eSJan Setje-Eilers 	while (*cp == '/')
10252506833eSJan Setje-Eilers 		++cp;
10262506833eSJan Setje-Eilers   	grub_memmove (config_file, cp, strlen(cp) + 1);
10272506833eSJan Setje-Eilers 	configfile_origin = CFG_HARDCODED;
10287c478bd9Sstevel@tonic-gate }
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate static struct builtin builtin_dhcp =
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate   "dhcp",
10337c478bd9Sstevel@tonic-gate   dhcp_func,
10347c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
10357c478bd9Sstevel@tonic-gate   "dhcp",
10367c478bd9Sstevel@tonic-gate   "Initialize a network device via DHCP."
10377c478bd9Sstevel@tonic-gate };
10387c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
10397c478bd9Sstevel@tonic-gate 
10407c478bd9Sstevel@tonic-gate static int terminal_func (char *arg, int flags);
10417c478bd9Sstevel@tonic-gate 
verbose_func(char * arg,int flags)10421fac5a60Ssetje static int verbose_func(char *arg, int flags) {
10431fac5a60Ssetje 
10441fac5a60Ssetje     if (grub_strcmp(arg, "off") == 0) {
10451fac5a60Ssetje       silent.status = DEFER_SILENT;
10461fac5a60Ssetje       return;
10471fac5a60Ssetje     } else
10481fac5a60Ssetje         if (flags == BUILTIN_CMDLINE) {
10491fac5a60Ssetje           silent.status = DEFER_VERBOSE;
10501fac5a60Ssetje           return;
10511fac5a60Ssetje         }
10521fac5a60Ssetje 
10531fac5a60Ssetje   silent.status = VERBOSE;
10541fac5a60Ssetje 
1055ae115bc7Smrj   /* get back to text console */
10561fac5a60Ssetje   if (current_term->shutdown) {
10571fac5a60Ssetje     (*current_term->shutdown)();
10581fac5a60Ssetje     current_term = term_table; /* assumption: console is first */
10591fac5a60Ssetje   }
10601fac5a60Ssetje 
10611fac5a60Ssetje   /* dump the buffer */
10621fac5a60Ssetje   if (!silent.looped) {
10631fac5a60Ssetje     /* if the buffer hasn't looped, just print it */
10641fac5a60Ssetje     printf("%s", silent.buffer);
10651fac5a60Ssetje   } else {
10661fac5a60Ssetje     /*
10671fac5a60Ssetje      * If the buffer has looped, first print the oldest part of the buffer,
10681fac5a60Ssetje      * which is one past the current null. Then print the newer part which
10691fac5a60Ssetje      * starts at the beginning of the buffer.
10701fac5a60Ssetje      */
10711fac5a60Ssetje     printf("%s", silent.buffer_start + 1);
10721fac5a60Ssetje     printf("%s", silent.buffer);
10731fac5a60Ssetje   }
10741fac5a60Ssetje 
10751fac5a60Ssetje   return 0;
10761fac5a60Ssetje }
10771fac5a60Ssetje 
10781fac5a60Ssetje static struct builtin builtin_verbose =
10791fac5a60Ssetje {
10801fac5a60Ssetje   "verbose",
10811fac5a60Ssetje   verbose_func,
10821fac5a60Ssetje   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
10831fac5a60Ssetje   "verbose",
10841fac5a60Ssetje   "Verbose output during menu entry (script) execution."
10851fac5a60Ssetje };
10861fac5a60Ssetje 
10877c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
10887c478bd9Sstevel@tonic-gate 
splashimage_func(char * arg,int flags)10897c478bd9Sstevel@tonic-gate static int splashimage_func(char *arg, int flags) {
10907c478bd9Sstevel@tonic-gate     char splashimage[64];
10917c478bd9Sstevel@tonic-gate     int i;
10921fac5a60Ssetje 
10937c478bd9Sstevel@tonic-gate     /* filename can only be 64 characters due to our buffer size */
10947c478bd9Sstevel@tonic-gate     if (strlen(arg) > 63)
10957c478bd9Sstevel@tonic-gate 	return 1;
10967c478bd9Sstevel@tonic-gate 
10971fac5a60Ssetje     if (flags == BUILTIN_SCRIPT)
10981fac5a60Ssetje         flags = BUILTIN_CMDLINE;
10991fac5a60Ssetje 
1100a6e28364SSuhasini Peddada     if (flags == BUILTIN_CMDLINE) {
1101a6e28364SSuhasini Peddada 	if (!grub_open(arg))
1102a6e28364SSuhasini Peddada 	    return 1;
1103a6e28364SSuhasini Peddada 	grub_close();
1104a6e28364SSuhasini Peddada     }
11057c478bd9Sstevel@tonic-gate 
1106a6e28364SSuhasini Peddada     strcpy(splashimage, arg);
110741c4174fSWilliam Kucharski 
11087c478bd9Sstevel@tonic-gate     /* get rid of TERM_NEED_INIT from the graphics terminal. */
11097c478bd9Sstevel@tonic-gate     for (i = 0; term_table[i].name; i++) {
11107c478bd9Sstevel@tonic-gate 	if (grub_strcmp (term_table[i].name, "graphics") == 0) {
11117c478bd9Sstevel@tonic-gate 	    term_table[i].flags &= ~TERM_NEED_INIT;
11127c478bd9Sstevel@tonic-gate 	    break;
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate     }
11159b4e3ac2SWilliam Kucharski 
1116a6e28364SSuhasini Peddada     graphics_set_splash(splashimage);
1117a6e28364SSuhasini Peddada 
11187c478bd9Sstevel@tonic-gate     if (flags == BUILTIN_CMDLINE && graphics_inited) {
11191fac5a60Ssetje 	/*
11201fac5a60Ssetje 	 * calling graphics_end() here flickers the screen black. OTOH not
11211fac5a60Ssetje 	 * calling it gets us odd plane interlacing / early palette switching ?
11221fac5a60Ssetje 	 * ideally one should figure out how to double buffer and switch...
11231fac5a60Ssetje 	 */
11247c478bd9Sstevel@tonic-gate 	graphics_end();
11257c478bd9Sstevel@tonic-gate 	graphics_init();
11267c478bd9Sstevel@tonic-gate 	graphics_cls();
11277c478bd9Sstevel@tonic-gate     }
11287c478bd9Sstevel@tonic-gate 
11299b4e3ac2SWilliam Kucharski     /*
11309b4e3ac2SWilliam Kucharski      * This call does not explicitly initialize graphics mode, but rather
11319b4e3ac2SWilliam Kucharski      * simply sets the terminal type unless we're in command line mode and
11329b4e3ac2SWilliam Kucharski      * call this function while in terminal mode.
11339b4e3ac2SWilliam Kucharski      */
11347c478bd9Sstevel@tonic-gate     terminal_func("graphics", flags);
11357c478bd9Sstevel@tonic-gate 
11361fac5a60Ssetje     reset_term = 0;
11371fac5a60Ssetje 
11387c478bd9Sstevel@tonic-gate     return 0;
11397c478bd9Sstevel@tonic-gate }
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate static struct builtin builtin_splashimage =
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate   "splashimage",
11447c478bd9Sstevel@tonic-gate   splashimage_func,
11451fac5a60Ssetje   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
11467c478bd9Sstevel@tonic-gate   "splashimage FILE",
11477c478bd9Sstevel@tonic-gate   "Load FILE as the background image when in graphics mode."
11487c478bd9Sstevel@tonic-gate };
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate /* foreground */
11527c478bd9Sstevel@tonic-gate static int
foreground_func(char * arg,int flags)11537c478bd9Sstevel@tonic-gate foreground_func(char *arg, int flags)
11547c478bd9Sstevel@tonic-gate {
11557c478bd9Sstevel@tonic-gate     if (grub_strlen(arg) == 6) {
11567c478bd9Sstevel@tonic-gate 	int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
11577c478bd9Sstevel@tonic-gate 	int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
11587c478bd9Sstevel@tonic-gate 	int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 	foreground = (r << 16) | (g << 8) | b;
11617c478bd9Sstevel@tonic-gate 	if (graphics_inited)
11627c478bd9Sstevel@tonic-gate 	    graphics_set_palette(15, r, g, b);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	return (0);
11657c478bd9Sstevel@tonic-gate     }
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate     return (1);
11687c478bd9Sstevel@tonic-gate }
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate static struct builtin builtin_foreground =
11717c478bd9Sstevel@tonic-gate {
11727c478bd9Sstevel@tonic-gate   "foreground",
11737c478bd9Sstevel@tonic-gate   foreground_func,
117467ce1dadSJan Setje-Eilers   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
11757c478bd9Sstevel@tonic-gate   "foreground RRGGBB",
11767c478bd9Sstevel@tonic-gate   "Sets the foreground color when in graphics mode."
11777c478bd9Sstevel@tonic-gate   "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
11787c478bd9Sstevel@tonic-gate };
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate /* background */
11827c478bd9Sstevel@tonic-gate static int
background_func(char * arg,int flags)11837c478bd9Sstevel@tonic-gate background_func(char *arg, int flags)
11847c478bd9Sstevel@tonic-gate {
11857c478bd9Sstevel@tonic-gate     if (grub_strlen(arg) == 6) {
11867c478bd9Sstevel@tonic-gate 	int r = ((hex(arg[0]) << 4) | hex(arg[1])) >> 2;
11877c478bd9Sstevel@tonic-gate 	int g = ((hex(arg[2]) << 4) | hex(arg[3])) >> 2;
11887c478bd9Sstevel@tonic-gate 	int b = ((hex(arg[4]) << 4) | hex(arg[5])) >> 2;
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	background = (r << 16) | (g << 8) | b;
11917c478bd9Sstevel@tonic-gate 	if (graphics_inited)
11927c478bd9Sstevel@tonic-gate 	    graphics_set_palette(0, r, g, b);
11937c478bd9Sstevel@tonic-gate 	return (0);
11947c478bd9Sstevel@tonic-gate     }
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate     return (1);
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate static struct builtin builtin_background =
12007c478bd9Sstevel@tonic-gate {
12017c478bd9Sstevel@tonic-gate   "background",
12027c478bd9Sstevel@tonic-gate   background_func,
120367ce1dadSJan Setje-Eilers   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST | BUILTIN_SCRIPT,
12047c478bd9Sstevel@tonic-gate   "background RRGGBB",
12057c478bd9Sstevel@tonic-gate   "Sets the background color when in graphics mode."
12067c478bd9Sstevel@tonic-gate   "RR is red, GG is green, and BB blue. Numbers must be in hexadecimal."
12077c478bd9Sstevel@tonic-gate };
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate #endif /* SUPPORT_GRAPHICS */
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate /* clear */
12137c478bd9Sstevel@tonic-gate static int
clear_func()12147c478bd9Sstevel@tonic-gate clear_func()
12157c478bd9Sstevel@tonic-gate {
12167c478bd9Sstevel@tonic-gate   if (current_term->cls)
12177c478bd9Sstevel@tonic-gate     current_term->cls();
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate   return 0;
12207c478bd9Sstevel@tonic-gate }
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate static struct builtin builtin_clear =
12237c478bd9Sstevel@tonic-gate {
12247c478bd9Sstevel@tonic-gate   "clear",
12257c478bd9Sstevel@tonic-gate   clear_func,
12267c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
12277c478bd9Sstevel@tonic-gate   "clear",
12287c478bd9Sstevel@tonic-gate   "Clear the screen"
12297c478bd9Sstevel@tonic-gate };
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate /* displayapm */
12327c478bd9Sstevel@tonic-gate static int
displayapm_func(char * arg,int flags)12337c478bd9Sstevel@tonic-gate displayapm_func (char *arg, int flags)
12347c478bd9Sstevel@tonic-gate {
12357c478bd9Sstevel@tonic-gate   if (mbi.flags & MB_INFO_APM_TABLE)
12367c478bd9Sstevel@tonic-gate     {
12377c478bd9Sstevel@tonic-gate       grub_printf ("APM BIOS information:\n"
12387c478bd9Sstevel@tonic-gate 		   " Version:          0x%x\n"
12397c478bd9Sstevel@tonic-gate 		   " 32-bit CS:        0x%x\n"
12407c478bd9Sstevel@tonic-gate 		   " Offset:           0x%x\n"
12417c478bd9Sstevel@tonic-gate 		   " 16-bit CS:        0x%x\n"
12427c478bd9Sstevel@tonic-gate 		   " 16-bit DS:        0x%x\n"
12437c478bd9Sstevel@tonic-gate 		   " 32-bit CS length: 0x%x\n"
12447c478bd9Sstevel@tonic-gate 		   " 16-bit CS length: 0x%x\n"
12457c478bd9Sstevel@tonic-gate 		   " 16-bit DS length: 0x%x\n",
12467c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.version,
12477c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg,
12487c478bd9Sstevel@tonic-gate 		   apm_bios_info.offset,
12497c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_16,
12507c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.dseg_16,
12517c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_len,
12527c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.cseg_16_len,
12537c478bd9Sstevel@tonic-gate 		   (unsigned) apm_bios_info.dseg_16_len);
12547c478bd9Sstevel@tonic-gate     }
12557c478bd9Sstevel@tonic-gate   else
12567c478bd9Sstevel@tonic-gate     {
12577c478bd9Sstevel@tonic-gate       grub_printf ("No APM BIOS found or probe failed\n");
12587c478bd9Sstevel@tonic-gate     }
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate   return 0;
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate static struct builtin builtin_displayapm =
12647c478bd9Sstevel@tonic-gate {
12657c478bd9Sstevel@tonic-gate   "displayapm",
12667c478bd9Sstevel@tonic-gate   displayapm_func,
12677c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
12687c478bd9Sstevel@tonic-gate   "displayapm",
12697c478bd9Sstevel@tonic-gate   "Display APM BIOS information."
12707c478bd9Sstevel@tonic-gate };
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate /* displaymem */
12747c478bd9Sstevel@tonic-gate static int
displaymem_func(char * arg,int flags)12757c478bd9Sstevel@tonic-gate displaymem_func (char *arg, int flags)
12767c478bd9Sstevel@tonic-gate {
12777c478bd9Sstevel@tonic-gate   if (get_eisamemsize () != -1)
12787c478bd9Sstevel@tonic-gate     grub_printf (" EISA Memory BIOS Interface is present\n");
12797c478bd9Sstevel@tonic-gate   if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0
12807c478bd9Sstevel@tonic-gate       || *((int *) SCRATCHADDR) != 0)
12817c478bd9Sstevel@tonic-gate     grub_printf (" Address Map BIOS Interface is present\n");
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate   grub_printf (" Lower memory: %uK, "
12847c478bd9Sstevel@tonic-gate 	       "Upper memory (to first chipset hole): %uK\n",
12857c478bd9Sstevel@tonic-gate 	       mbi.mem_lower, mbi.mem_upper);
12867c478bd9Sstevel@tonic-gate 
1287342440ecSPrasad Singamsetty   if (min_mem64 != 0)
1288342440ecSPrasad Singamsetty   	grub_printf (" Memory limit for 64-bit ISADIR expansion: %uMB\n",
1289342440ecSPrasad Singamsetty 	    min_mem64);
1290342440ecSPrasad Singamsetty 
12917c478bd9Sstevel@tonic-gate   if (mbi.flags & MB_INFO_MEM_MAP)
12927c478bd9Sstevel@tonic-gate     {
12937c478bd9Sstevel@tonic-gate       struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr;
12947c478bd9Sstevel@tonic-gate       int end_addr = mbi.mmap_addr + mbi.mmap_length;
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate       grub_printf (" [Address Range Descriptor entries "
12977c478bd9Sstevel@tonic-gate 		   "immediately follow (values are 64-bit)]\n");
12987c478bd9Sstevel@tonic-gate       while (end_addr > (int) map)
12997c478bd9Sstevel@tonic-gate 	{
13007c478bd9Sstevel@tonic-gate 	  char *str;
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 	  if (map->Type == MB_ARD_MEMORY)
13037c478bd9Sstevel@tonic-gate 	    str = "Usable RAM";
13047c478bd9Sstevel@tonic-gate 	  else
13057c478bd9Sstevel@tonic-gate 	    str = "Reserved";
13067c478bd9Sstevel@tonic-gate 	  grub_printf ("   %s:  Base Address:  0x%x X 4GB + 0x%x,\n"
1307342440ecSPrasad Singamsetty 		"      Length:   0x%x X 4GB + 0x%x bytes\n",
1308342440ecSPrasad Singamsetty 		str,
1309342440ecSPrasad Singamsetty 		(unsigned long) (map->BaseAddr >> 32),
1310342440ecSPrasad Singamsetty 		(unsigned long) (map->BaseAddr & 0xFFFFFFFF),
1311342440ecSPrasad Singamsetty 		(unsigned long) (map->Length >> 32),
1312342440ecSPrasad Singamsetty 		(unsigned long) (map->Length & 0xFFFFFFFF));
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	  map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size));
13157c478bd9Sstevel@tonic-gate 	}
13167c478bd9Sstevel@tonic-gate     }
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate   return 0;
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate static struct builtin builtin_displaymem =
13227c478bd9Sstevel@tonic-gate {
13237c478bd9Sstevel@tonic-gate   "displaymem",
13247c478bd9Sstevel@tonic-gate   displaymem_func,
13257c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
13267c478bd9Sstevel@tonic-gate   "displaymem",
13277c478bd9Sstevel@tonic-gate   "Display what GRUB thinks the system address space map of the"
13287c478bd9Sstevel@tonic-gate   " machine is, including all regions of physical RAM installed."
13297c478bd9Sstevel@tonic-gate };
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate /* dump FROM TO */
13337c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
13347c478bd9Sstevel@tonic-gate static int
dump_func(char * arg,int flags)13357c478bd9Sstevel@tonic-gate dump_func (char *arg, int flags)
13367c478bd9Sstevel@tonic-gate {
13377c478bd9Sstevel@tonic-gate   char *from, *to;
13387c478bd9Sstevel@tonic-gate   FILE *fp;
13397c478bd9Sstevel@tonic-gate   char c;
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate   from = arg;
13427c478bd9Sstevel@tonic-gate   to = skip_to (0, arg);
13437c478bd9Sstevel@tonic-gate   if (! *from || ! *to)
13447c478bd9Sstevel@tonic-gate     {
13457c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
13467c478bd9Sstevel@tonic-gate       return 1;
13477c478bd9Sstevel@tonic-gate     }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate   nul_terminate (from);
13507c478bd9Sstevel@tonic-gate   nul_terminate (to);
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate   if (! grub_open (from))
13537c478bd9Sstevel@tonic-gate     return 1;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate   fp = fopen (to, "w");
13567c478bd9Sstevel@tonic-gate   if (! fp)
13577c478bd9Sstevel@tonic-gate     {
13587c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
13597c478bd9Sstevel@tonic-gate       return 1;
13607c478bd9Sstevel@tonic-gate     }
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate   while (grub_read (&c, 1))
13637c478bd9Sstevel@tonic-gate     if (fputc (c, fp) == EOF)
13647c478bd9Sstevel@tonic-gate       {
13657c478bd9Sstevel@tonic-gate 	errnum = ERR_WRITE;
13667c478bd9Sstevel@tonic-gate 	fclose (fp);
13677c478bd9Sstevel@tonic-gate 	return 1;
13687c478bd9Sstevel@tonic-gate       }
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate   if (fclose (fp) == EOF)
13717c478bd9Sstevel@tonic-gate     {
13727c478bd9Sstevel@tonic-gate       errnum = ERR_WRITE;
13737c478bd9Sstevel@tonic-gate       return 1;
13747c478bd9Sstevel@tonic-gate     }
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate   grub_close ();
13777c478bd9Sstevel@tonic-gate   return 0;
13787c478bd9Sstevel@tonic-gate }
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate static struct builtin builtin_dump =
13817c478bd9Sstevel@tonic-gate   {
13827c478bd9Sstevel@tonic-gate     "dump",
13837c478bd9Sstevel@tonic-gate     dump_func,
13847c478bd9Sstevel@tonic-gate     BUILTIN_CMDLINE,
13857c478bd9Sstevel@tonic-gate     "dump FROM TO",
13867c478bd9Sstevel@tonic-gate     "Dump the contents of the file FROM to the file TO. FROM must be"
13877c478bd9Sstevel@tonic-gate     " a GRUB file and TO must be an OS file."
13887c478bd9Sstevel@tonic-gate   };
13897c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate static char embed_info[32];
13937c478bd9Sstevel@tonic-gate /* embed */
13947c478bd9Sstevel@tonic-gate /* Embed a Stage 1.5 in the first cylinder after MBR or in the
13957c478bd9Sstevel@tonic-gate    bootloader block in a FFS.  */
13967c478bd9Sstevel@tonic-gate static int
embed_func(char * arg,int flags)13977c478bd9Sstevel@tonic-gate embed_func (char *arg, int flags)
13987c478bd9Sstevel@tonic-gate {
13997c478bd9Sstevel@tonic-gate   char *stage1_5;
14007c478bd9Sstevel@tonic-gate   char *device;
14017c478bd9Sstevel@tonic-gate   char *stage1_5_buffer = (char *) RAW_ADDR (0x100000);
14027c478bd9Sstevel@tonic-gate   int len, size;
14032e1aefd1SJoshua M. Clulow   unsigned long long sector;
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate   stage1_5 = arg;
14067c478bd9Sstevel@tonic-gate   device = skip_to (0, stage1_5);
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate   /* Open a Stage 1.5.  */
14097c478bd9Sstevel@tonic-gate   if (! grub_open (stage1_5))
14107c478bd9Sstevel@tonic-gate     return 1;
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate   /* Read the whole of the Stage 1.5.  */
14137c478bd9Sstevel@tonic-gate   len = grub_read (stage1_5_buffer, -1);
14147c478bd9Sstevel@tonic-gate   grub_close ();
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate   if (errnum)
14177c478bd9Sstevel@tonic-gate     return 1;
14187c478bd9Sstevel@tonic-gate 
14197c478bd9Sstevel@tonic-gate   size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE;
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate   /* Get the device where the Stage 1.5 will be embedded.  */
14227c478bd9Sstevel@tonic-gate   set_device (device);
14237c478bd9Sstevel@tonic-gate   if (errnum)
14247c478bd9Sstevel@tonic-gate     return 1;
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate   if (current_partition == 0xFFFFFF)
14277c478bd9Sstevel@tonic-gate     {
14287c478bd9Sstevel@tonic-gate       /* Embed it after the MBR.  */
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate       char mbr[SECTOR_SIZE];
14317c478bd9Sstevel@tonic-gate       char ezbios_check[2*SECTOR_SIZE];
14327c478bd9Sstevel@tonic-gate       int i;
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate       /* Open the partition.  */
14357c478bd9Sstevel@tonic-gate       if (! open_partition ())
14367c478bd9Sstevel@tonic-gate 	return 1;
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate       /* No floppy has MBR.  */
14397c478bd9Sstevel@tonic-gate       if (! (current_drive & 0x80))
14407c478bd9Sstevel@tonic-gate 	{
14417c478bd9Sstevel@tonic-gate 	  errnum = ERR_DEV_VALUES;
14427c478bd9Sstevel@tonic-gate 	  return 1;
14437c478bd9Sstevel@tonic-gate 	}
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate       /* Read the MBR of CURRENT_DRIVE.  */
14467c478bd9Sstevel@tonic-gate       if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr))
14477c478bd9Sstevel@tonic-gate 	return 1;
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate       /* Sanity check.  */
14507c478bd9Sstevel@tonic-gate       if (! PC_MBR_CHECK_SIG (mbr))
14517c478bd9Sstevel@tonic-gate 	{
14527c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_PART_TABLE;
14537c478bd9Sstevel@tonic-gate 	  return 1;
14547c478bd9Sstevel@tonic-gate 	}
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate       /* Check if the disk can store the Stage 1.5.  */
14577c478bd9Sstevel@tonic-gate       for (i = 0; i < 4; i++)
14587c478bd9Sstevel@tonic-gate 	if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size)
14597c478bd9Sstevel@tonic-gate 	  {
14607c478bd9Sstevel@tonic-gate 	    errnum = ERR_NO_DISK_SPACE;
14617c478bd9Sstevel@tonic-gate 	    return 1;
14627c478bd9Sstevel@tonic-gate 	  }
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate       /* Check for EZ-BIOS signature. It should be in the third
14657c478bd9Sstevel@tonic-gate        * sector, but due to remapping it can appear in the second, so
14667c478bd9Sstevel@tonic-gate        * load and check both.
14677c478bd9Sstevel@tonic-gate        */
14687c478bd9Sstevel@tonic-gate       if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check))
14697c478bd9Sstevel@tonic-gate 	return 1;
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate       if (! memcmp (ezbios_check + 3, "AERMH", 5)
14727c478bd9Sstevel@tonic-gate 	  || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5))
14737c478bd9Sstevel@tonic-gate 	{
14747c478bd9Sstevel@tonic-gate 	  /* The space after the MBR is used by EZ-BIOS which we must
14757c478bd9Sstevel@tonic-gate 	   * not overwrite.
14767c478bd9Sstevel@tonic-gate 	   */
14777c478bd9Sstevel@tonic-gate 	  errnum = ERR_NO_DISK_SPACE;
14787c478bd9Sstevel@tonic-gate 	  return 1;
14797c478bd9Sstevel@tonic-gate 	}
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate       sector = 1;
14827c478bd9Sstevel@tonic-gate     }
14837c478bd9Sstevel@tonic-gate   else
14847c478bd9Sstevel@tonic-gate     {
14857c478bd9Sstevel@tonic-gate       /* Embed it in the bootloader block in the filesystem.  */
14862e1aefd1SJoshua M. Clulow       unsigned long long start_sector;
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate       /* Open the partition.  */
14897c478bd9Sstevel@tonic-gate       if (! open_device ())
14907c478bd9Sstevel@tonic-gate 	return 1;
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate       /* Check if the current slice supports embedding.  */
14937c478bd9Sstevel@tonic-gate       if (fsys_table[fsys_type].embed_func == 0
14947c478bd9Sstevel@tonic-gate 	  || ! fsys_table[fsys_type].embed_func (&start_sector, size))
14957c478bd9Sstevel@tonic-gate 	{
14967c478bd9Sstevel@tonic-gate 	  errnum = ERR_DEV_VALUES;
14977c478bd9Sstevel@tonic-gate 	  return 1;
14987c478bd9Sstevel@tonic-gate 	}
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate       sector = part_start + start_sector;
15017c478bd9Sstevel@tonic-gate     }
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate   /* Clear the cache.  */
1504342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate   /* Now perform the embedding.  */
15077c478bd9Sstevel@tonic-gate   if (! devwrite (sector - part_start, size, stage1_5_buffer))
15087c478bd9Sstevel@tonic-gate     return 1;
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate   grub_printf (" %d sectors are embedded.\n", size);
15112e1aefd1SJoshua M. Clulow   grub_sprintf (embed_info, "%llu+%d", sector - part_start, size);
15127c478bd9Sstevel@tonic-gate   return 0;
15137c478bd9Sstevel@tonic-gate }
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate static struct builtin builtin_embed =
15167c478bd9Sstevel@tonic-gate {
15177c478bd9Sstevel@tonic-gate   "embed",
15187c478bd9Sstevel@tonic-gate   embed_func,
15197c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
15207c478bd9Sstevel@tonic-gate   "embed STAGE1_5 DEVICE",
15217c478bd9Sstevel@tonic-gate   "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE"
15227c478bd9Sstevel@tonic-gate   " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition."
15237c478bd9Sstevel@tonic-gate   " Print the number of sectors which STAGE1_5 occupies if successful."
15247c478bd9Sstevel@tonic-gate };
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate /* fallback */
15287c478bd9Sstevel@tonic-gate static int
fallback_func(char * arg,int flags)15297c478bd9Sstevel@tonic-gate fallback_func (char *arg, int flags)
15307c478bd9Sstevel@tonic-gate {
15317c478bd9Sstevel@tonic-gate   int i = 0;
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate   while (*arg)
15347c478bd9Sstevel@tonic-gate     {
15357c478bd9Sstevel@tonic-gate       int entry;
15367c478bd9Sstevel@tonic-gate       int j;
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&arg, &entry))
15397c478bd9Sstevel@tonic-gate 	return 1;
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate       /* Remove duplications to prevent infinite looping.  */
15427c478bd9Sstevel@tonic-gate       for (j = 0; j < i; j++)
15437c478bd9Sstevel@tonic-gate 	if (entry == fallback_entries[j])
15447c478bd9Sstevel@tonic-gate 	  break;
15457c478bd9Sstevel@tonic-gate       if (j != i)
15467c478bd9Sstevel@tonic-gate 	continue;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate       fallback_entries[i++] = entry;
15497c478bd9Sstevel@tonic-gate       if (i == MAX_FALLBACK_ENTRIES)
15507c478bd9Sstevel@tonic-gate 	break;
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
15537c478bd9Sstevel@tonic-gate     }
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate   if (i < MAX_FALLBACK_ENTRIES)
15567c478bd9Sstevel@tonic-gate     fallback_entries[i] = -1;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate   fallback_entryno = (i == 0) ? -1 : 0;
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate   return 0;
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate static struct builtin builtin_fallback =
15647c478bd9Sstevel@tonic-gate {
15657c478bd9Sstevel@tonic-gate   "fallback",
15667c478bd9Sstevel@tonic-gate   fallback_func,
15677c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
15687c478bd9Sstevel@tonic-gate #if 0
15697c478bd9Sstevel@tonic-gate   "fallback NUM...",
15707c478bd9Sstevel@tonic-gate   "Go into unattended boot mode: if the default boot entry has any"
15717c478bd9Sstevel@tonic-gate   " errors, instead of waiting for the user to do anything, it"
15727c478bd9Sstevel@tonic-gate   " immediately starts over using the NUM entry (same numbering as the"
15737c478bd9Sstevel@tonic-gate   " `default' command). This obviously won't help if the machine"
15747c478bd9Sstevel@tonic-gate   " was rebooted by a kernel that GRUB loaded."
15757c478bd9Sstevel@tonic-gate #endif
15767c478bd9Sstevel@tonic-gate };
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 
1579051aabe6Staylor 
1580051aabe6Staylor void
set_root(char * root,unsigned long drive,unsigned long part)1581051aabe6Staylor set_root (char *root, unsigned long drive, unsigned long part)
1582051aabe6Staylor {
1583051aabe6Staylor   int bsd_part = (part >> 8) & 0xFF;
1584051aabe6Staylor   int pc_slice = part >> 16;
1585051aabe6Staylor 
1586051aabe6Staylor   if (bsd_part == 0xFF) {
1587051aabe6Staylor     grub_sprintf (root, "(hd%d,%d)\n", drive - 0x80, pc_slice);
1588051aabe6Staylor   } else {
1589051aabe6Staylor     grub_sprintf (root, "(hd%d,%d,%c)\n",
1590051aabe6Staylor 		 drive - 0x80, pc_slice, bsd_part + 'a');
1591051aabe6Staylor   }
1592051aabe6Staylor }
1593051aabe6Staylor 
15947c478bd9Sstevel@tonic-gate static int
find_common(char * arg,char * root,int for_root,int flags)1595eb2bd662Svikram find_common (char *arg, char *root, int for_root, int flags)
15967c478bd9Sstevel@tonic-gate {
1597eb2bd662Svikram   char *filename = NULL;
1598eb2bd662Svikram   static char argpart[32];
1599eb2bd662Svikram   static char device[32];
1600eb2bd662Svikram   char *tmp_argpart = NULL;
16017c478bd9Sstevel@tonic-gate   unsigned long drive;
16027c478bd9Sstevel@tonic-gate   unsigned long tmp_drive = saved_drive;
16037c478bd9Sstevel@tonic-gate   unsigned long tmp_partition = saved_partition;
16047c478bd9Sstevel@tonic-gate   int got_file = 0;
1605eb2bd662Svikram   static char bootsign[BOOTSIGN_LEN];
1606eb2bd662Svikram 
1607eb2bd662Svikram   /*
1608eb2bd662Svikram    * If argument has partition information (findroot command only), then
1609eb2bd662Svikram    * it can't be a floppy
1610eb2bd662Svikram    */
1611eb2bd662Svikram   if (for_root && arg[0] == '(') {
1612eb2bd662Svikram 	tmp_argpart = grub_strchr(arg + 1, ',');
1613eb2bd662Svikram         if (tmp_argpart == NULL)
1614eb2bd662Svikram 		goto out;
1615eb2bd662Svikram 	grub_strcpy(argpart, tmp_argpart);
1616eb2bd662Svikram 	*tmp_argpart = '\0';
1617eb2bd662Svikram 	arg++;
1618eb2bd662Svikram         grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
1619eb2bd662Svikram 	filename = bootsign;
1620eb2bd662Svikram 	goto harddisk;
162121ecdf64SLin Ling   } else if (for_root && !grub_strchr(arg, '/')) {
1622eb2bd662Svikram 	/* Boot signature without partition/slice information */
1623eb2bd662Svikram         grub_sprintf(bootsign, "%s/%s", BOOTSIGN_DIR, arg);
1624eb2bd662Svikram 	filename = bootsign;
1625eb2bd662Svikram   } else {
1626eb2bd662Svikram 	/* plain vanilla find cmd */
1627eb2bd662Svikram 	filename = arg;
1628eb2bd662Svikram   }
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate   /* Floppies.  */
16317c478bd9Sstevel@tonic-gate   for (drive = 0; drive < 8; drive++)
16327c478bd9Sstevel@tonic-gate     {
16337c478bd9Sstevel@tonic-gate       current_drive = drive;
16347c478bd9Sstevel@tonic-gate       current_partition = 0xFFFFFF;
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate       if (open_device ())
16377c478bd9Sstevel@tonic-gate 	{
16387c478bd9Sstevel@tonic-gate 	  saved_drive = current_drive;
16397c478bd9Sstevel@tonic-gate 	  saved_partition = current_partition;
16407c478bd9Sstevel@tonic-gate 	  if (grub_open (filename))
16417c478bd9Sstevel@tonic-gate 	    {
16427c478bd9Sstevel@tonic-gate 	      grub_close ();
16437c478bd9Sstevel@tonic-gate 	      got_file = 1;
1644eb2bd662Svikram 	      if (for_root) {
1645eb2bd662Svikram 		 grub_sprintf(root, "(fd%d)", drive);
1646eb2bd662Svikram 		 goto out;
1647eb2bd662Svikram 	      } else
1648eb2bd662Svikram 	         grub_printf (" (fd%d)\n", drive);
16497c478bd9Sstevel@tonic-gate 	    }
16507c478bd9Sstevel@tonic-gate 	}
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate       errnum = ERR_NONE;
16537c478bd9Sstevel@tonic-gate     }
16547c478bd9Sstevel@tonic-gate 
1655eb2bd662Svikram harddisk:
16567c478bd9Sstevel@tonic-gate   /* Hard disks.  */
16577c478bd9Sstevel@tonic-gate   for (drive = 0x80; drive < 0x88; drive++)
16587c478bd9Sstevel@tonic-gate     {
16597c478bd9Sstevel@tonic-gate       unsigned long part = 0xFFFFFF;
16609890706eSHans Rosenfeld       unsigned long long start, len, offset, ext_offset, gpt_offset;
166144bc9120SRichard Yao       int type, entry, gpt_count, gpt_size;
16627c478bd9Sstevel@tonic-gate       char buf[SECTOR_SIZE];
16637c478bd9Sstevel@tonic-gate 
1664eb2bd662Svikram       if (for_root && tmp_argpart) {
1665051aabe6Staylor 	grub_sprintf(device, "(hd%d%s", drive - 0x80, argpart);
1666eb2bd662Svikram 	set_device(device);
1667eb2bd662Svikram         errnum = ERR_NONE;
1668eb2bd662Svikram 	part = current_partition;
1669eb2bd662Svikram 	if (open_device ()) {
1670eb2bd662Svikram 	   saved_drive = current_drive;
1671eb2bd662Svikram 	   saved_partition = current_partition;
1672eb2bd662Svikram            errnum = ERR_NONE;
1673eb2bd662Svikram 	   if (grub_open (filename)) {
1674eb2bd662Svikram 	      grub_close ();
1675eb2bd662Svikram 	      got_file = 1;
1676051aabe6Staylor 	      if (is_zfs_mount == 0) {
1677051aabe6Staylor 	        set_root(root, current_drive, current_partition);
1678051aabe6Staylor 	        goto out;
1679051aabe6Staylor 	      } else {
1680051aabe6Staylor 		best_drive = current_drive;
1681051aabe6Staylor 		best_part = current_partition;
1682051aabe6Staylor 	      }
1683eb2bd662Svikram            }
1684eb2bd662Svikram 	}
1685eb2bd662Svikram         errnum = ERR_NONE;
1686eb2bd662Svikram 	continue;
1687eb2bd662Svikram       }
16887c478bd9Sstevel@tonic-gate       current_drive = drive;
16897c478bd9Sstevel@tonic-gate       while (next_partition (drive, 0xFFFFFF, &part, &type,
16907c478bd9Sstevel@tonic-gate 			     &start, &len, &offset, &entry,
169144bc9120SRichard Yao 			     &ext_offset, &gpt_offset,
169244bc9120SRichard Yao 			     &gpt_count, &gpt_size, 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
find_func(char * arg,int flags)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
fstest_func(char * arg,int flags)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
geometry_func(char * arg,int flags)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, "
18769890706eSHans Rosenfeld 	       "The number of sectors = %llu, %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
halt_func(char * arg,int flags)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
help_func(char * arg,int flags)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
hiddenmenu_func(char * arg,int flags)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
hide_func(char * arg,int flags)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
ifconfig_func(char * arg,int flags)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
impsprobe_func(char * arg,int flags)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 
21787c478bd9Sstevel@tonic-gate /* initrd */
21797c478bd9Sstevel@tonic-gate static int
initrd_func(char * arg,int flags)21807c478bd9Sstevel@tonic-gate initrd_func (char *arg, int flags)
21817c478bd9Sstevel@tonic-gate {
21827c478bd9Sstevel@tonic-gate   switch (kernel_type)
21837c478bd9Sstevel@tonic-gate     {
21847c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
21857c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
21867c478bd9Sstevel@tonic-gate       if (! load_initrd (arg))
21877c478bd9Sstevel@tonic-gate 	return 1;
21887c478bd9Sstevel@tonic-gate       break;
21897c478bd9Sstevel@tonic-gate 
21907c478bd9Sstevel@tonic-gate     default:
21917c478bd9Sstevel@tonic-gate       errnum = ERR_NEED_LX_KERNEL;
21927c478bd9Sstevel@tonic-gate       return 1;
21937c478bd9Sstevel@tonic-gate     }
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate   return 0;
21967c478bd9Sstevel@tonic-gate }
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate static struct builtin builtin_initrd =
21997c478bd9Sstevel@tonic-gate {
22007c478bd9Sstevel@tonic-gate   "initrd",
22017c478bd9Sstevel@tonic-gate   initrd_func,
22027c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
22037c478bd9Sstevel@tonic-gate   "initrd FILE [ARG ...]",
22047c478bd9Sstevel@tonic-gate   "Load an initial ramdisk FILE for a Linux format boot image and set the"
22057c478bd9Sstevel@tonic-gate   " appropriate parameters in the Linux setup area in memory."
22067c478bd9Sstevel@tonic-gate };
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate /* install */
22107c478bd9Sstevel@tonic-gate static int
install_func(char * arg,int flags)22117c478bd9Sstevel@tonic-gate install_func (char *arg, int flags)
22127c478bd9Sstevel@tonic-gate {
22137c478bd9Sstevel@tonic-gate   char *stage1_file, *dest_dev, *file, *addr;
22147c478bd9Sstevel@tonic-gate   char *stage1_buffer = (char *) RAW_ADDR (0x100000);
22157c478bd9Sstevel@tonic-gate   char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
22167c478bd9Sstevel@tonic-gate   char *old_sect = stage2_buffer + SECTOR_SIZE;
22177c478bd9Sstevel@tonic-gate   char *stage2_first_buffer = old_sect + SECTOR_SIZE;
22187c478bd9Sstevel@tonic-gate   char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
22197c478bd9Sstevel@tonic-gate   /* XXX: Probably SECTOR_SIZE is reasonable.  */
22207c478bd9Sstevel@tonic-gate   char *config_filename = stage2_second_buffer + SECTOR_SIZE;
22217c478bd9Sstevel@tonic-gate   char *dummy = config_filename + SECTOR_SIZE;
22227c478bd9Sstevel@tonic-gate   int new_drive = GRUB_INVALID_DRIVE;
2223342440ecSPrasad Singamsetty   int dest_drive, dest_partition;
2224342440ecSPrasad Singamsetty   unsigned int dest_sector;
22257c478bd9Sstevel@tonic-gate   int src_drive, src_partition, src_part_start;
22267c478bd9Sstevel@tonic-gate   int i;
22277c478bd9Sstevel@tonic-gate   struct geometry dest_geom, src_geom;
22289890706eSHans Rosenfeld   unsigned long long saved_sector;
22299890706eSHans Rosenfeld   unsigned long long stage2_first_sector, stage2_second_sector;
22307c478bd9Sstevel@tonic-gate   char *ptr;
22317c478bd9Sstevel@tonic-gate   int installaddr, installlist;
22327c478bd9Sstevel@tonic-gate   /* Point to the location of the name of a configuration file in Stage 2.  */
22337c478bd9Sstevel@tonic-gate   char *config_file_location;
22347c478bd9Sstevel@tonic-gate   /* If FILE is a Stage 1.5?  */
22357c478bd9Sstevel@tonic-gate   int is_stage1_5 = 0;
22367c478bd9Sstevel@tonic-gate   /* Must call grub_close?  */
22377c478bd9Sstevel@tonic-gate   int is_open = 0;
22387c478bd9Sstevel@tonic-gate   /* If LBA is forced?  */
22397c478bd9Sstevel@tonic-gate   int is_force_lba = 0;
22407c478bd9Sstevel@tonic-gate   /* Was the last sector full? */
22417c478bd9Sstevel@tonic-gate   int last_length = SECTOR_SIZE;
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
22447c478bd9Sstevel@tonic-gate   /* If the Stage 2 is in a partition mounted by an OS, this will store
22457c478bd9Sstevel@tonic-gate      the filename under the OS.  */
22467c478bd9Sstevel@tonic-gate   char *stage2_os_file = 0;
22477c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
22487c478bd9Sstevel@tonic-gate 
22499890706eSHans Rosenfeld   auto void disk_read_savesect_func (unsigned long long sector, int offset,
22501b8adde7SWilliam Kucharski       int length);
22519890706eSHans Rosenfeld   auto void disk_read_blocklist_func (unsigned long long sector, int offset,
22521b8adde7SWilliam Kucharski       int length);
22531b8adde7SWilliam Kucharski 
22547c478bd9Sstevel@tonic-gate   /* Save the first sector of Stage2 in STAGE2_SECT.  */
22559890706eSHans Rosenfeld   auto void disk_read_savesect_func (unsigned long long sector, int offset,
22561b8adde7SWilliam Kucharski       int length)
22577c478bd9Sstevel@tonic-gate     {
22587c478bd9Sstevel@tonic-gate       if (debug)
22599890706eSHans Rosenfeld 	printf ("[%llu]", sector);
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate       /* ReiserFS has files which sometimes contain data not aligned
22627c478bd9Sstevel@tonic-gate          on sector boundaries.  Returning an error is better than
22637c478bd9Sstevel@tonic-gate          silently failing. */
22647c478bd9Sstevel@tonic-gate       if (offset != 0 || length != SECTOR_SIZE)
22657c478bd9Sstevel@tonic-gate 	errnum = ERR_UNALIGNED;
22667c478bd9Sstevel@tonic-gate 
22677c478bd9Sstevel@tonic-gate       saved_sector = sector;
22687c478bd9Sstevel@tonic-gate     }
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate   /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
22717c478bd9Sstevel@tonic-gate      INSTALLSECT.  */
22729890706eSHans Rosenfeld   auto void disk_read_blocklist_func (unsigned long long sector, int offset,
22731b8adde7SWilliam Kucharski       int length)
22747c478bd9Sstevel@tonic-gate     {
22757c478bd9Sstevel@tonic-gate       if (debug)
22769890706eSHans Rosenfeld 	printf("[%llu]", sector);
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate       if (offset != 0 || last_length != SECTOR_SIZE)
22797c478bd9Sstevel@tonic-gate 	{
22807c478bd9Sstevel@tonic-gate 	  /* We found a non-sector-aligned data block. */
22817c478bd9Sstevel@tonic-gate 	  errnum = ERR_UNALIGNED;
22827c478bd9Sstevel@tonic-gate 	  return;
22837c478bd9Sstevel@tonic-gate 	}
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate       last_length = length;
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate       if (*((unsigned long *) (installlist - 4))
22887c478bd9Sstevel@tonic-gate 	  + *((unsigned short *) installlist) != sector
22897c478bd9Sstevel@tonic-gate 	  || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4)
22907c478bd9Sstevel@tonic-gate 	{
22917c478bd9Sstevel@tonic-gate 	  installlist -= 8;
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	  if (*((unsigned long *) (installlist - 8)))
22947c478bd9Sstevel@tonic-gate 	    errnum = ERR_WONT_FIT;
22957c478bd9Sstevel@tonic-gate 	  else
22967c478bd9Sstevel@tonic-gate 	    {
22977c478bd9Sstevel@tonic-gate 	      *((unsigned short *) (installlist + 2)) = (installaddr >> 4);
22987c478bd9Sstevel@tonic-gate 	      *((unsigned long *) (installlist - 4)) = sector;
22997c478bd9Sstevel@tonic-gate 	    }
23007c478bd9Sstevel@tonic-gate 	}
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate       *((unsigned short *) installlist) += 1;
23037c478bd9Sstevel@tonic-gate       installaddr += 512;
23047c478bd9Sstevel@tonic-gate     }
23057c478bd9Sstevel@tonic-gate 
23067c478bd9Sstevel@tonic-gate   /* First, check the GNU-style long option.  */
23077c478bd9Sstevel@tonic-gate   while (1)
23087c478bd9Sstevel@tonic-gate     {
23097c478bd9Sstevel@tonic-gate       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
23107c478bd9Sstevel@tonic-gate 	{
23117c478bd9Sstevel@tonic-gate 	  is_force_lba = 1;
23127c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
23137c478bd9Sstevel@tonic-gate 	}
23147c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
23157c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
23167c478bd9Sstevel@tonic-gate 	{
23177c478bd9Sstevel@tonic-gate 	  stage2_os_file = arg + sizeof ("--stage2=") - 1;
23187c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
23197c478bd9Sstevel@tonic-gate 	  nul_terminate (stage2_os_file);
23207c478bd9Sstevel@tonic-gate 	}
23217c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
23227c478bd9Sstevel@tonic-gate       else
23237c478bd9Sstevel@tonic-gate 	break;
23247c478bd9Sstevel@tonic-gate     }
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate   stage1_file = arg;
23277c478bd9Sstevel@tonic-gate   dest_dev = skip_to (0, stage1_file);
23287c478bd9Sstevel@tonic-gate   if (*dest_dev == 'd')
23297c478bd9Sstevel@tonic-gate     {
23307c478bd9Sstevel@tonic-gate       new_drive = 0;
23317c478bd9Sstevel@tonic-gate       dest_dev = skip_to (0, dest_dev);
23327c478bd9Sstevel@tonic-gate     }
23337c478bd9Sstevel@tonic-gate   file = skip_to (0, dest_dev);
23347c478bd9Sstevel@tonic-gate   addr = skip_to (0, file);
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate   /* Get the installation address.  */
23377c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&addr, &installaddr))
23387c478bd9Sstevel@tonic-gate     {
23397c478bd9Sstevel@tonic-gate       /* ADDR is not specified.  */
23407c478bd9Sstevel@tonic-gate       installaddr = 0;
23417c478bd9Sstevel@tonic-gate       ptr = addr;
23427c478bd9Sstevel@tonic-gate       errnum = 0;
23437c478bd9Sstevel@tonic-gate     }
23447c478bd9Sstevel@tonic-gate   else
23457c478bd9Sstevel@tonic-gate     ptr = skip_to (0, addr);
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
23487c478bd9Sstevel@tonic-gate   /* Do not decompress Stage 1 or Stage 2.  */
23497c478bd9Sstevel@tonic-gate   no_decompression = 1;
23507c478bd9Sstevel@tonic-gate #endif
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate   /* Read Stage 1.  */
23537c478bd9Sstevel@tonic-gate   is_open = grub_open (stage1_file);
23547c478bd9Sstevel@tonic-gate   if (! is_open
23557c478bd9Sstevel@tonic-gate       || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE)
23567c478bd9Sstevel@tonic-gate     goto fail;
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate   /* Read the old sector from DEST_DEV.  */
23597c478bd9Sstevel@tonic-gate   if (! set_device (dest_dev)
23607c478bd9Sstevel@tonic-gate       || ! open_partition ()
23617c478bd9Sstevel@tonic-gate       || ! devread (0, 0, SECTOR_SIZE, old_sect))
23627c478bd9Sstevel@tonic-gate     goto fail;
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate   /* Store the information for the destination device.  */
23657c478bd9Sstevel@tonic-gate   dest_drive = current_drive;
23667c478bd9Sstevel@tonic-gate   dest_partition = current_partition;
23677c478bd9Sstevel@tonic-gate   dest_geom = buf_geom;
23687c478bd9Sstevel@tonic-gate   dest_sector = part_start;
23697c478bd9Sstevel@tonic-gate 
23707c478bd9Sstevel@tonic-gate   /* Copy the possible DOS BPB, 59 bytes at byte offset 3.  */
23717c478bd9Sstevel@tonic-gate   grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET,
23727c478bd9Sstevel@tonic-gate 		old_sect + BOOTSEC_BPB_OFFSET,
23737c478bd9Sstevel@tonic-gate 		BOOTSEC_BPB_LENGTH);
23747c478bd9Sstevel@tonic-gate 
23757c478bd9Sstevel@tonic-gate   /* If for a hard disk, copy the possible MBR/extended part table.  */
23767c478bd9Sstevel@tonic-gate   if (dest_drive & 0x80)
23777c478bd9Sstevel@tonic-gate     grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC,
23787c478bd9Sstevel@tonic-gate 		  old_sect + STAGE1_WINDOWS_NT_MAGIC,
23797c478bd9Sstevel@tonic-gate 		  STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC);
23807c478bd9Sstevel@tonic-gate 
23817c478bd9Sstevel@tonic-gate   /* Check for the version and the signature of Stage 1.  */
23827c478bd9Sstevel@tonic-gate   if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
23837c478bd9Sstevel@tonic-gate       || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET))
23847c478bd9Sstevel@tonic-gate 	  != BOOTSEC_SIGNATURE))
23857c478bd9Sstevel@tonic-gate     {
23867c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
23877c478bd9Sstevel@tonic-gate       goto fail;
23887c478bd9Sstevel@tonic-gate     }
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate   /* This below is not true any longer. But should we leave this alone?  */
23917c478bd9Sstevel@tonic-gate 
23927c478bd9Sstevel@tonic-gate   /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe
23937c478bd9Sstevel@tonic-gate      routine.  */
23947c478bd9Sstevel@tonic-gate   if (! (dest_drive & 0x80)
23957c478bd9Sstevel@tonic-gate       && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80
23967c478bd9Sstevel@tonic-gate 	  || stage1_buffer[BOOTSEC_PART_OFFSET] == 0))
23977c478bd9Sstevel@tonic-gate     {
23987c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
23997c478bd9Sstevel@tonic-gate       goto fail;
24007c478bd9Sstevel@tonic-gate     }
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate   grub_close ();
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate   /* Open Stage 2.  */
24057c478bd9Sstevel@tonic-gate   is_open = grub_open (file);
24067c478bd9Sstevel@tonic-gate   if (! is_open)
24077c478bd9Sstevel@tonic-gate     goto fail;
24087c478bd9Sstevel@tonic-gate 
24097c478bd9Sstevel@tonic-gate   src_drive = current_drive;
24107c478bd9Sstevel@tonic-gate   src_partition = current_partition;
24117c478bd9Sstevel@tonic-gate   src_part_start = part_start;
24127c478bd9Sstevel@tonic-gate   src_geom = buf_geom;
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate   if (! new_drive)
24157c478bd9Sstevel@tonic-gate     new_drive = src_drive;
24167c478bd9Sstevel@tonic-gate   else if (src_drive != dest_drive)
24177c478bd9Sstevel@tonic-gate     grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
24187c478bd9Sstevel@tonic-gate 		 " be installed on a\ndifferent drive than the drive where"
24197c478bd9Sstevel@tonic-gate 		 " the Stage 2 resides.\n");
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate   /* Set the boot drive.  */
24227c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate   /* Set the "force LBA" flag.  */
24257c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba;
24267c478bd9Sstevel@tonic-gate 
24271b8adde7SWilliam Kucharski   /* If DEST_DRIVE is a hard disk, enable the workaround, which is
24281b8adde7SWilliam Kucharski      for buggy BIOSes which don't pass boot drive correctly. Instead,
24291b8adde7SWilliam Kucharski      they pass 0x00 or 0x01 even when booted from 0x80.  */
24301b8adde7SWilliam Kucharski   if (dest_drive & BIOS_FLAG_FIXED_DISK)
24311b8adde7SWilliam Kucharski     /* Replace the jmp (2 bytes) with double nop's.  */
24321b8adde7SWilliam Kucharski     *((unsigned short *) (stage1_buffer + STAGE1_BOOT_DRIVE_CHECK))
24331b8adde7SWilliam Kucharski       = 0x9090;
24341b8adde7SWilliam Kucharski 
24357c478bd9Sstevel@tonic-gate   /* Read the first sector of Stage 2.  */
24367c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_savesect_func;
24377c478bd9Sstevel@tonic-gate   if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
24387c478bd9Sstevel@tonic-gate     goto fail;
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate   stage2_first_sector = saved_sector;
24419890706eSHans Rosenfeld   if (stage2_first_sector >= 0xffffffffUL) {
24429890706eSHans Rosenfeld     grub_printf ("Error: stage2 first sector must be below 2TB\n");
24439890706eSHans Rosenfeld     goto fail;
24449890706eSHans Rosenfeld   }
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate   /* Read the second sector of Stage 2.  */
24477c478bd9Sstevel@tonic-gate   if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
24487c478bd9Sstevel@tonic-gate     goto fail;
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate   stage2_second_sector = saved_sector;
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate   /* Check for the version of Stage 2.  */
24537c478bd9Sstevel@tonic-gate   if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
24547c478bd9Sstevel@tonic-gate       != COMPAT_VERSION)
24557c478bd9Sstevel@tonic-gate     {
24567c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_VERSION;
24577c478bd9Sstevel@tonic-gate       goto fail;
24587c478bd9Sstevel@tonic-gate     }
24597c478bd9Sstevel@tonic-gate 
24607c478bd9Sstevel@tonic-gate   /* Check for the Stage 2 id.  */
24617c478bd9Sstevel@tonic-gate   if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2)
24627c478bd9Sstevel@tonic-gate     is_stage1_5 = 1;
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate   /* If INSTALLADDR is not specified explicitly in the command-line,
24657c478bd9Sstevel@tonic-gate      determine it by the Stage 2 id.  */
24667c478bd9Sstevel@tonic-gate   if (! installaddr)
24677c478bd9Sstevel@tonic-gate     {
24687c478bd9Sstevel@tonic-gate       if (! is_stage1_5)
24697c478bd9Sstevel@tonic-gate 	/* Stage 2.  */
24707c478bd9Sstevel@tonic-gate 	installaddr = 0x8000;
24717c478bd9Sstevel@tonic-gate       else
24727c478bd9Sstevel@tonic-gate 	/* Stage 1.5.  */
24737c478bd9Sstevel@tonic-gate 	installaddr = 0x2000;
24747c478bd9Sstevel@tonic-gate     }
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate   *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
24777c478bd9Sstevel@tonic-gate     = stage2_first_sector;
24787c478bd9Sstevel@tonic-gate   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
24797c478bd9Sstevel@tonic-gate     = installaddr;
24807c478bd9Sstevel@tonic-gate   *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
24817c478bd9Sstevel@tonic-gate     = installaddr >> 4;
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate   i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
24847c478bd9Sstevel@tonic-gate   while (*((unsigned long *) i))
24857c478bd9Sstevel@tonic-gate     {
24867c478bd9Sstevel@tonic-gate       if (i < (int) stage2_first_buffer
24877c478bd9Sstevel@tonic-gate 	  || (*((int *) (i - 4)) & 0x80000000)
24887c478bd9Sstevel@tonic-gate 	  || *((unsigned short *) i) >= 0xA00
24897c478bd9Sstevel@tonic-gate 	  || *((short *) (i + 2)) == 0)
24907c478bd9Sstevel@tonic-gate 	{
24917c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_VERSION;
24927c478bd9Sstevel@tonic-gate 	  goto fail;
24937c478bd9Sstevel@tonic-gate 	}
24947c478bd9Sstevel@tonic-gate 
24957c478bd9Sstevel@tonic-gate       *((int *) i) = 0;
24967c478bd9Sstevel@tonic-gate       *((int *) (i - 4)) = 0;
24977c478bd9Sstevel@tonic-gate       i -= 8;
24987c478bd9Sstevel@tonic-gate     }
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate   installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
25017c478bd9Sstevel@tonic-gate   installaddr += SECTOR_SIZE;
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate   /* Read the whole of Stage2 except for the first sector.  */
25047c478bd9Sstevel@tonic-gate   grub_seek (SECTOR_SIZE);
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_blocklist_func;
25077c478bd9Sstevel@tonic-gate   if (! grub_read (dummy, -1))
25087c478bd9Sstevel@tonic-gate     goto fail;
25097c478bd9Sstevel@tonic-gate 
25107c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate   /* Find a string for the configuration filename.  */
25137c478bd9Sstevel@tonic-gate   config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS;
25147c478bd9Sstevel@tonic-gate   while (*(config_file_location++))
25157c478bd9Sstevel@tonic-gate     ;
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate   /* Set the "force LBA" flag for Stage2.  */
25187c478bd9Sstevel@tonic-gate   *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA))
25197c478bd9Sstevel@tonic-gate     = is_force_lba;
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate   if (*ptr == 'p')
25227c478bd9Sstevel@tonic-gate     {
25237c478bd9Sstevel@tonic-gate       *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
25247c478bd9Sstevel@tonic-gate 	= src_partition;
25257c478bd9Sstevel@tonic-gate       if (is_stage1_5)
25267c478bd9Sstevel@tonic-gate 	{
25277c478bd9Sstevel@tonic-gate 	  /* Reset the device information in FILE if it is a Stage 1.5.  */
25287c478bd9Sstevel@tonic-gate 	  unsigned long device = 0xFFFFFFFF;
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate 	  grub_memmove (config_file_location, (char *) &device,
25317c478bd9Sstevel@tonic-gate 			sizeof (device));
25327c478bd9Sstevel@tonic-gate 	}
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate       ptr = skip_to (0, ptr);
25357c478bd9Sstevel@tonic-gate     }
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate   if (*ptr)
25387c478bd9Sstevel@tonic-gate     {
25397c478bd9Sstevel@tonic-gate       grub_strcpy (config_filename, ptr);
25407c478bd9Sstevel@tonic-gate       nul_terminate (config_filename);
25417c478bd9Sstevel@tonic-gate 
25427c478bd9Sstevel@tonic-gate       if (! is_stage1_5)
25437c478bd9Sstevel@tonic-gate 	/* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION.  */
25447c478bd9Sstevel@tonic-gate 	grub_strcpy (config_file_location, ptr);
25457c478bd9Sstevel@tonic-gate       else
25467c478bd9Sstevel@tonic-gate 	{
25477c478bd9Sstevel@tonic-gate 	  char *real_config;
25487c478bd9Sstevel@tonic-gate 	  unsigned long device;
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	  /* Translate the external device syntax to the internal device
25517c478bd9Sstevel@tonic-gate 	     syntax.  */
25527c478bd9Sstevel@tonic-gate 	  if (! (real_config = set_device (ptr)))
25537c478bd9Sstevel@tonic-gate 	    {
25547c478bd9Sstevel@tonic-gate 	      /* The Stage 2 PTR does not contain the device name, so
25557c478bd9Sstevel@tonic-gate 		 use the root device instead.  */
25567c478bd9Sstevel@tonic-gate 	      errnum = ERR_NONE;
25577c478bd9Sstevel@tonic-gate 	      current_drive = saved_drive;
25587c478bd9Sstevel@tonic-gate 	      current_partition = saved_partition;
25597c478bd9Sstevel@tonic-gate 	      real_config = ptr;
25607c478bd9Sstevel@tonic-gate 	    }
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate 	  if (current_drive == src_drive)
25637c478bd9Sstevel@tonic-gate 	    {
25647c478bd9Sstevel@tonic-gate 	      /* If the drive where the Stage 2 resides is the same as
25657c478bd9Sstevel@tonic-gate 		 the one where the Stage 1.5 resides, do not embed the
25667c478bd9Sstevel@tonic-gate 		 drive number.  */
25677c478bd9Sstevel@tonic-gate 	      current_drive = GRUB_INVALID_DRIVE;
25687c478bd9Sstevel@tonic-gate 	    }
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	  device = (current_drive << 24) | current_partition;
25717c478bd9Sstevel@tonic-gate 	  grub_memmove (config_file_location, (char *) &device,
25727c478bd9Sstevel@tonic-gate 			sizeof (device));
25737c478bd9Sstevel@tonic-gate 	  grub_strcpy (config_file_location + sizeof (device),
25747c478bd9Sstevel@tonic-gate 		       real_config);
25757c478bd9Sstevel@tonic-gate 	}
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate       /* If a Stage 1.5 is used, then we need to modify the Stage2.  */
25787c478bd9Sstevel@tonic-gate       if (is_stage1_5)
25797c478bd9Sstevel@tonic-gate 	{
25807c478bd9Sstevel@tonic-gate 	  char *real_config_filename = skip_to (0, ptr);
25817c478bd9Sstevel@tonic-gate 
25827c478bd9Sstevel@tonic-gate 	  is_open = grub_open (config_filename);
25837c478bd9Sstevel@tonic-gate 	  if (! is_open)
25847c478bd9Sstevel@tonic-gate 	    goto fail;
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	  /* Skip the first sector.  */
25877c478bd9Sstevel@tonic-gate 	  grub_seek (SECTOR_SIZE);
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate 	  disk_read_hook = disk_read_savesect_func;
25907c478bd9Sstevel@tonic-gate 	  if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
25917c478bd9Sstevel@tonic-gate 	    goto fail;
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	  disk_read_hook = 0;
25947c478bd9Sstevel@tonic-gate 	  grub_close ();
25957c478bd9Sstevel@tonic-gate 	  is_open = 0;
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 	  /* Sanity check.  */
25987c478bd9Sstevel@tonic-gate 	  if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2)
25997c478bd9Sstevel@tonic-gate 	    {
26007c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_VERSION;
26017c478bd9Sstevel@tonic-gate 	      goto fail;
26027c478bd9Sstevel@tonic-gate 	    }
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 	  /* Set the "force LBA" flag for Stage2.  */
26057c478bd9Sstevel@tonic-gate 	  *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba;
26067c478bd9Sstevel@tonic-gate 
26077c478bd9Sstevel@tonic-gate 	  /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2.  */
26087c478bd9Sstevel@tonic-gate 	  if (*real_config_filename)
26097c478bd9Sstevel@tonic-gate 	    {
26107c478bd9Sstevel@tonic-gate 	      /* Specified */
26117c478bd9Sstevel@tonic-gate 	      char *location;
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate 	      /* Find a string for the configuration filename.  */
26147c478bd9Sstevel@tonic-gate 	      location = stage2_buffer + STAGE2_VER_STR_OFFS;
26157c478bd9Sstevel@tonic-gate 	      while (*(location++))
26167c478bd9Sstevel@tonic-gate 		;
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 	      /* Copy the name.  */
26197c478bd9Sstevel@tonic-gate 	      grub_strcpy (location, real_config_filename);
26207c478bd9Sstevel@tonic-gate 	    }
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate 	  /* Write it to the disk.  */
2623342440ecSPrasad Singamsetty 	  buf_track = BUF_CACHE_INVALID;
26247c478bd9Sstevel@tonic-gate 
26257c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
26267c478bd9Sstevel@tonic-gate 	  /* In the grub shell, access the Stage 2 via the OS filesystem
26277c478bd9Sstevel@tonic-gate 	     service, if possible.  */
26287c478bd9Sstevel@tonic-gate 	  if (stage2_os_file)
26297c478bd9Sstevel@tonic-gate 	    {
26307c478bd9Sstevel@tonic-gate 	      FILE *fp;
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate 	      fp = fopen (stage2_os_file, "r+");
26337c478bd9Sstevel@tonic-gate 	      if (! fp)
26347c478bd9Sstevel@tonic-gate 		{
26357c478bd9Sstevel@tonic-gate 		  errnum = ERR_FILE_NOT_FOUND;
26367c478bd9Sstevel@tonic-gate 		  goto fail;
26377c478bd9Sstevel@tonic-gate 		}
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 	      if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
26407c478bd9Sstevel@tonic-gate 		{
26417c478bd9Sstevel@tonic-gate 		  fclose (fp);
26427c478bd9Sstevel@tonic-gate 		  errnum = ERR_BAD_VERSION;
26437c478bd9Sstevel@tonic-gate 		  goto fail;
26447c478bd9Sstevel@tonic-gate 		}
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 	      if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp)
26477c478bd9Sstevel@tonic-gate 		  != SECTOR_SIZE)
26487c478bd9Sstevel@tonic-gate 		{
26497c478bd9Sstevel@tonic-gate 		  fclose (fp);
26507c478bd9Sstevel@tonic-gate 		  errnum = ERR_WRITE;
26517c478bd9Sstevel@tonic-gate 		  goto fail;
26527c478bd9Sstevel@tonic-gate 		}
26537c478bd9Sstevel@tonic-gate 
26547c478bd9Sstevel@tonic-gate 	      fclose (fp);
26557c478bd9Sstevel@tonic-gate 	    }
26567c478bd9Sstevel@tonic-gate 	  else
26577c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
26587c478bd9Sstevel@tonic-gate 	    {
26597c478bd9Sstevel@tonic-gate 	      if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
26607c478bd9Sstevel@tonic-gate 		goto fail;
26617c478bd9Sstevel@tonic-gate 	    }
26627c478bd9Sstevel@tonic-gate 	}
26637c478bd9Sstevel@tonic-gate     }
26647c478bd9Sstevel@tonic-gate 
26657c478bd9Sstevel@tonic-gate   /* Clear the cache.  */
2666342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate   /* Write the modified sectors of Stage2 to the disk.  */
26697c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
26707c478bd9Sstevel@tonic-gate   if (! is_stage1_5 && stage2_os_file)
26717c478bd9Sstevel@tonic-gate     {
26727c478bd9Sstevel@tonic-gate       FILE *fp;
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate       fp = fopen (stage2_os_file, "r+");
26757c478bd9Sstevel@tonic-gate       if (! fp)
26767c478bd9Sstevel@tonic-gate 	{
26777c478bd9Sstevel@tonic-gate 	  errnum = ERR_FILE_NOT_FOUND;
26787c478bd9Sstevel@tonic-gate 	  goto fail;
26797c478bd9Sstevel@tonic-gate 	}
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate       if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
26827c478bd9Sstevel@tonic-gate 	{
26837c478bd9Sstevel@tonic-gate 	  fclose (fp);
26847c478bd9Sstevel@tonic-gate 	  errnum = ERR_WRITE;
26857c478bd9Sstevel@tonic-gate 	  goto fail;
26867c478bd9Sstevel@tonic-gate 	}
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate       if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
26897c478bd9Sstevel@tonic-gate 	{
26907c478bd9Sstevel@tonic-gate 	  fclose (fp);
26917c478bd9Sstevel@tonic-gate 	  errnum = ERR_WRITE;
26927c478bd9Sstevel@tonic-gate 	  goto fail;
26937c478bd9Sstevel@tonic-gate 	}
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate       fclose (fp);
26967c478bd9Sstevel@tonic-gate     }
26977c478bd9Sstevel@tonic-gate   else
26987c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
26997c478bd9Sstevel@tonic-gate     {
27007c478bd9Sstevel@tonic-gate       /* The first.  */
27017c478bd9Sstevel@tonic-gate       current_drive = src_drive;
27027c478bd9Sstevel@tonic-gate       current_partition = src_partition;
27037c478bd9Sstevel@tonic-gate 
27047c478bd9Sstevel@tonic-gate       if (! open_partition ())
27057c478bd9Sstevel@tonic-gate 	goto fail;
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate       if (! devwrite (stage2_first_sector - src_part_start, 1,
27087c478bd9Sstevel@tonic-gate 		      stage2_first_buffer))
27097c478bd9Sstevel@tonic-gate 	goto fail;
27107c478bd9Sstevel@tonic-gate 
27117c478bd9Sstevel@tonic-gate       if (! devwrite (stage2_second_sector - src_part_start, 1,
27127c478bd9Sstevel@tonic-gate 		      stage2_second_buffer))
27137c478bd9Sstevel@tonic-gate 	goto fail;
27147c478bd9Sstevel@tonic-gate     }
27157c478bd9Sstevel@tonic-gate 
27167c478bd9Sstevel@tonic-gate   /* Write the modified sector of Stage 1 to the disk.  */
27177c478bd9Sstevel@tonic-gate   current_drive = dest_drive;
27187c478bd9Sstevel@tonic-gate   current_partition = dest_partition;
27197c478bd9Sstevel@tonic-gate   if (! open_partition ())
27207c478bd9Sstevel@tonic-gate     goto fail;
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate   devwrite (0, 1, stage1_buffer);
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate  fail:
27257c478bd9Sstevel@tonic-gate   if (is_open)
27267c478bd9Sstevel@tonic-gate     grub_close ();
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
27317c478bd9Sstevel@tonic-gate   no_decompression = 0;
27327c478bd9Sstevel@tonic-gate #endif
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate   return errnum;
27357c478bd9Sstevel@tonic-gate }
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate static struct builtin builtin_install =
27387c478bd9Sstevel@tonic-gate {
27397c478bd9Sstevel@tonic-gate   "install",
27407c478bd9Sstevel@tonic-gate   install_func,
27417c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
27427c478bd9Sstevel@tonic-gate   "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
27437c478bd9Sstevel@tonic-gate   "Install STAGE1 on DEVICE, and install a blocklist for loading STAGE2"
27447c478bd9Sstevel@tonic-gate   " as a Stage 2. If the option `d' is present, the Stage 1 will always"
27457c478bd9Sstevel@tonic-gate   " look for the disk where STAGE2 was installed, rather than using"
27467c478bd9Sstevel@tonic-gate   " the booting drive. The Stage 2 will be loaded at address ADDR, which"
27477c478bd9Sstevel@tonic-gate   " will be determined automatically if you don't specify it. If"
27487c478bd9Sstevel@tonic-gate   " the option `p' or CONFIG_FILE is present, then the first block"
27497c478bd9Sstevel@tonic-gate   " of Stage 2 is patched with new values of the partition and name"
27507c478bd9Sstevel@tonic-gate   " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
27517c478bd9Sstevel@tonic-gate   " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage"
27527c478bd9Sstevel@tonic-gate   " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
27537c478bd9Sstevel@tonic-gate   " patched with the configuration filename REAL_CONFIG_FILE."
27547c478bd9Sstevel@tonic-gate   " If the option `--force-lba' is specified, disable some sanity checks"
27557c478bd9Sstevel@tonic-gate   " for LBA mode. If the option `--stage2' is specified, rewrite the Stage"
27567c478bd9Sstevel@tonic-gate   " 2 via your OS's filesystem instead of the raw device."
27577c478bd9Sstevel@tonic-gate };
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 
27607c478bd9Sstevel@tonic-gate /* ioprobe */
27617c478bd9Sstevel@tonic-gate static int
ioprobe_func(char * arg,int flags)27627c478bd9Sstevel@tonic-gate ioprobe_func (char *arg, int flags)
27637c478bd9Sstevel@tonic-gate {
27647c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
27657c478bd9Sstevel@tonic-gate 
27667c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
27677c478bd9Sstevel@tonic-gate   return 1;
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate #else /* ! GRUB_UTIL */
27707c478bd9Sstevel@tonic-gate 
27717c478bd9Sstevel@tonic-gate   unsigned short *port;
27727c478bd9Sstevel@tonic-gate 
27737c478bd9Sstevel@tonic-gate   /* Get the drive number.  */
27747c478bd9Sstevel@tonic-gate   set_device (arg);
27757c478bd9Sstevel@tonic-gate   if (errnum)
27767c478bd9Sstevel@tonic-gate     return 1;
27777c478bd9Sstevel@tonic-gate 
27787c478bd9Sstevel@tonic-gate   /* Clean out IO_MAP.  */
27797c478bd9Sstevel@tonic-gate   grub_memset ((char *) io_map, 0, IO_MAP_SIZE * sizeof (unsigned short));
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate   /* Track the int13 handler.  */
27827c478bd9Sstevel@tonic-gate   track_int13 (current_drive);
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate   /* Print out the result.  */
27857c478bd9Sstevel@tonic-gate   for (port = io_map; *port != 0; port++)
27867c478bd9Sstevel@tonic-gate     grub_printf (" 0x%x", (unsigned int) *port);
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate   return 0;
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate #endif /* ! GRUB_UTIL */
27917c478bd9Sstevel@tonic-gate }
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate static struct builtin builtin_ioprobe =
27947c478bd9Sstevel@tonic-gate {
27957c478bd9Sstevel@tonic-gate   "ioprobe",
27967c478bd9Sstevel@tonic-gate   ioprobe_func,
27977c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
27987c478bd9Sstevel@tonic-gate   "ioprobe DRIVE",
27997c478bd9Sstevel@tonic-gate   "Probe I/O ports used for the drive DRIVE."
28007c478bd9Sstevel@tonic-gate };
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate /* kernel */
28047c478bd9Sstevel@tonic-gate static int
kernel_func(char * arg,int flags)28057c478bd9Sstevel@tonic-gate kernel_func (char *arg, int flags)
28067c478bd9Sstevel@tonic-gate {
28077c478bd9Sstevel@tonic-gate   int len;
28087c478bd9Sstevel@tonic-gate   kernel_t suggested_type = KERNEL_TYPE_NONE;
28097c478bd9Sstevel@tonic-gate   unsigned long load_flags = 0;
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate #ifndef AUTO_LINUX_MEM_OPT
28127c478bd9Sstevel@tonic-gate   load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
28137c478bd9Sstevel@tonic-gate #endif
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate   /* Deal with GNU-style long options.  */
28167c478bd9Sstevel@tonic-gate   while (1)
28177c478bd9Sstevel@tonic-gate     {
28187c478bd9Sstevel@tonic-gate       /* If the option `--type=TYPE' is specified, convert the string to
28197c478bd9Sstevel@tonic-gate 	 a kernel type.  */
28207c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--type=", 7) == 0)
28217c478bd9Sstevel@tonic-gate 	{
28227c478bd9Sstevel@tonic-gate 	  arg += 7;
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate 	  if (grub_memcmp (arg, "netbsd", 6) == 0)
28257c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_NETBSD;
28267c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "freebsd", 7) == 0)
28277c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_FREEBSD;
28287c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "openbsd", 7) == 0)
28297c478bd9Sstevel@tonic-gate 	    /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's
28307c478bd9Sstevel@tonic-gate 	       point of view.  */
28317c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_NETBSD;
28327c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "linux", 5) == 0)
28337c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_LINUX;
28347c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "biglinux", 8) == 0)
28357c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_BIG_LINUX;
28367c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (arg, "multiboot", 9) == 0)
28377c478bd9Sstevel@tonic-gate 	    suggested_type = KERNEL_TYPE_MULTIBOOT;
28387c478bd9Sstevel@tonic-gate 	  else
28397c478bd9Sstevel@tonic-gate 	    {
28407c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
28417c478bd9Sstevel@tonic-gate 	      return 1;
28427c478bd9Sstevel@tonic-gate 	    }
28437c478bd9Sstevel@tonic-gate 	}
28447c478bd9Sstevel@tonic-gate       /* If the `--no-mem-option' is specified, don't pass a Linux's mem
28457c478bd9Sstevel@tonic-gate 	 option automatically. If the kernel is another type, this flag
28467c478bd9Sstevel@tonic-gate 	 has no effect.  */
28477c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
28487c478bd9Sstevel@tonic-gate 	load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
28497c478bd9Sstevel@tonic-gate       else
28507c478bd9Sstevel@tonic-gate 	break;
28517c478bd9Sstevel@tonic-gate 
28527c478bd9Sstevel@tonic-gate       /* Try the next.  */
28537c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
28547c478bd9Sstevel@tonic-gate     }
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate   len = grub_strlen (arg);
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate   /* Reset MB_CMDLINE.  */
28597c478bd9Sstevel@tonic-gate   mb_cmdline = (char *) MB_CMDLINE_BUF;
28607c478bd9Sstevel@tonic-gate   if (len + 1 > MB_CMDLINE_BUFLEN)
28617c478bd9Sstevel@tonic-gate     {
28627c478bd9Sstevel@tonic-gate       errnum = ERR_WONT_FIT;
28637c478bd9Sstevel@tonic-gate       return 1;
28647c478bd9Sstevel@tonic-gate     }
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate   /* Copy the command-line to MB_CMDLINE.  */
28677c478bd9Sstevel@tonic-gate   grub_memmove (mb_cmdline, arg, len + 1);
28687c478bd9Sstevel@tonic-gate   kernel_type = load_image (arg, mb_cmdline, suggested_type, load_flags);
28697c478bd9Sstevel@tonic-gate   if (kernel_type == KERNEL_TYPE_NONE)
28707c478bd9Sstevel@tonic-gate     return 1;
28717c478bd9Sstevel@tonic-gate 
2872b1b8ab34Slling   mb_cmdline += grub_strlen(mb_cmdline) + 1;
28737c478bd9Sstevel@tonic-gate   return 0;
28747c478bd9Sstevel@tonic-gate }
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate static struct builtin builtin_kernel =
28777c478bd9Sstevel@tonic-gate {
28787c478bd9Sstevel@tonic-gate   "kernel",
28797c478bd9Sstevel@tonic-gate   kernel_func,
28807c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
28817c478bd9Sstevel@tonic-gate   "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
28827c478bd9Sstevel@tonic-gate   "Attempt to load the primary boot image from FILE. The rest of the"
28837c478bd9Sstevel@tonic-gate   " line is passed verbatim as the \"kernel command line\".  Any modules"
28847c478bd9Sstevel@tonic-gate   " must be reloaded after using this command. The option --type is used"
28857c478bd9Sstevel@tonic-gate   " to suggest what type of kernel to be loaded. TYPE must be either of"
28867c478bd9Sstevel@tonic-gate   " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
28877c478bd9Sstevel@tonic-gate   " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
28887c478bd9Sstevel@tonic-gate   " Linux's mem option automatically."
28897c478bd9Sstevel@tonic-gate };
28907c478bd9Sstevel@tonic-gate 
2891342440ecSPrasad Singamsetty int
min_mem64_func(char * arg,int flags)2892342440ecSPrasad Singamsetty min_mem64_func(char *arg, int flags)
2893342440ecSPrasad Singamsetty {
2894342440ecSPrasad Singamsetty 	if (!safe_parse_maxint(&arg, &min_mem64))
2895342440ecSPrasad Singamsetty 		return (1);
2896342440ecSPrasad Singamsetty }
2897342440ecSPrasad Singamsetty 
2898342440ecSPrasad Singamsetty static struct builtin builtin_min_mem64 =
2899342440ecSPrasad Singamsetty {
2900342440ecSPrasad Singamsetty 	"min_mem64",
2901342440ecSPrasad Singamsetty 	min_mem64_func,
2902342440ecSPrasad Singamsetty 	BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
2903342440ecSPrasad Singamsetty 	"min_mem64 <memory in MB>",
2904342440ecSPrasad Singamsetty 	"Sets minimum memory (in MB) required for $ISADIR to expand to amd64, "
2905342440ecSPrasad Singamsetty 	"even on 64-bit capable hardware."
2906342440ecSPrasad Singamsetty };
2907342440ecSPrasad Singamsetty 
2908ae115bc7Smrj static int
kernel_dollar_func(char * arg,int flags)2909ae115bc7Smrj kernel_dollar_func (char *arg, int flags)
2910ae115bc7Smrj {
2911a5602e1bSKeith M Wesolowski   int err;
2912a5602e1bSKeith M Wesolowski   char newarg[MAX_CMDLINE];
2913b1b8ab34Slling 
2914a5602e1bSKeith M Wesolowski   /*
2915a5602e1bSKeith M Wesolowski    * We're going to expand the arguments twice.  The first expansion, which
2916a5602e1bSKeith M Wesolowski    * occurs without the benefit of knowing the ZFS object ID of the filesystem
2917a5602e1bSKeith M Wesolowski    * we're booting from (if we're booting from ZFS, of course), must be
2918a5602e1bSKeith M Wesolowski    * sufficient to find and read the kernel.  The second expansion will
2919a5602e1bSKeith M Wesolowski    * then overwrite the command line actually set in the multiboot header with
2920a5602e1bSKeith M Wesolowski    * the newly-expanded one.  Since $ZFS-BOOTFS expands differently after
2921a5602e1bSKeith M Wesolowski    * zfs_open() has been called (kernel_func() -> load_image() -> grub_open() ->
2922a5602e1bSKeith M Wesolowski    * zfs_open()), we need to do the second expansion so that the kernel is
2923a5602e1bSKeith M Wesolowski    * given the right object ID argument.  Note that the pointer to the
2924a5602e1bSKeith M Wesolowski    * command line set in the multiboot header is always MB_CMDLINE_BUF.
2925a5602e1bSKeith M Wesolowski    */
2926b1b8ab34Slling   grub_printf("loading '%s' ...\n", arg);
2927a5602e1bSKeith M Wesolowski   if ((err = expand_string(arg, newarg, MAX_CMDLINE)) != 0) {
2928a5602e1bSKeith M Wesolowski     errnum = err;
2929a5602e1bSKeith M Wesolowski     return (1);
2930a5602e1bSKeith M Wesolowski   }
2931b1b8ab34Slling 
2932a5602e1bSKeith M Wesolowski   if ((err = kernel_func(newarg, flags)) != 0)
2933a5602e1bSKeith M Wesolowski     return (err);
2934b1b8ab34Slling 
2935b1b8ab34Slling   mb_cmdline = (char *)MB_CMDLINE_BUF;
2936a5602e1bSKeith M Wesolowski   if ((err = expand_string(arg, mb_cmdline, MAX_CMDLINE)) != 0) {
2937a5602e1bSKeith M Wesolowski     errnum = err;
2938a5602e1bSKeith M Wesolowski     return (1);
2939ffb5616eSLin Ling   }
2940b1b8ab34Slling 
2941a5602e1bSKeith M Wesolowski   grub_printf("loading '%s' ...\n", mb_cmdline);
2942b1b8ab34Slling   mb_cmdline += grub_strlen(mb_cmdline) + 1;
2943b1b8ab34Slling   return (0);
2944ae115bc7Smrj }
2945ae115bc7Smrj 
2946ae115bc7Smrj static struct builtin builtin_kernel_dollar =
2947ae115bc7Smrj {
2948ae115bc7Smrj   "kernel$",
2949ae115bc7Smrj   kernel_dollar_func,
2950ae115bc7Smrj   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
2951ae115bc7Smrj   "kernel$ [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
2952a5602e1bSKeith M Wesolowski   " Just like kernel, but with variable expansion, including the legacy"
2953a5602e1bSKeith M Wesolowski   " (and nonconforming) variables $ISADIR and $ZFS-BOOTFS."
2954ae115bc7Smrj };
2955ae115bc7Smrj 
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate /* lock */
29587c478bd9Sstevel@tonic-gate static int
lock_func(char * arg,int flags)29597c478bd9Sstevel@tonic-gate lock_func (char *arg, int flags)
29607c478bd9Sstevel@tonic-gate {
29617c478bd9Sstevel@tonic-gate   if (! auth && password)
29627c478bd9Sstevel@tonic-gate     {
29637c478bd9Sstevel@tonic-gate       errnum = ERR_PRIVILEGED;
29647c478bd9Sstevel@tonic-gate       return 1;
29657c478bd9Sstevel@tonic-gate     }
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate   return 0;
29687c478bd9Sstevel@tonic-gate }
29697c478bd9Sstevel@tonic-gate 
29707c478bd9Sstevel@tonic-gate static struct builtin builtin_lock =
29717c478bd9Sstevel@tonic-gate {
29727c478bd9Sstevel@tonic-gate   "lock",
29737c478bd9Sstevel@tonic-gate   lock_func,
29747c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
29757c478bd9Sstevel@tonic-gate   "lock",
29767c478bd9Sstevel@tonic-gate   "Break a command execution unless the user is authenticated."
29777c478bd9Sstevel@tonic-gate };
29787c478bd9Sstevel@tonic-gate 
29797c478bd9Sstevel@tonic-gate 
29807c478bd9Sstevel@tonic-gate /* makeactive */
29817c478bd9Sstevel@tonic-gate static int
makeactive_func(char * arg,int flags)29827c478bd9Sstevel@tonic-gate makeactive_func (char *arg, int flags)
29837c478bd9Sstevel@tonic-gate {
29847c478bd9Sstevel@tonic-gate   if (! make_saved_active ())
29857c478bd9Sstevel@tonic-gate     return 1;
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate   return 0;
29887c478bd9Sstevel@tonic-gate }
29897c478bd9Sstevel@tonic-gate 
29907c478bd9Sstevel@tonic-gate static struct builtin builtin_makeactive =
29917c478bd9Sstevel@tonic-gate {
29927c478bd9Sstevel@tonic-gate   "makeactive",
29937c478bd9Sstevel@tonic-gate   makeactive_func,
29947c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
29957c478bd9Sstevel@tonic-gate   "makeactive",
29967c478bd9Sstevel@tonic-gate   "Set the active partition on the root disk to GRUB's root device."
29977c478bd9Sstevel@tonic-gate   " This command is limited to _primary_ PC partitions on a hard disk."
29987c478bd9Sstevel@tonic-gate };
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 
30017c478bd9Sstevel@tonic-gate /* map */
30027c478bd9Sstevel@tonic-gate /* Map FROM_DRIVE to TO_DRIVE.  */
30037c478bd9Sstevel@tonic-gate static int
map_func(char * arg,int flags)30047c478bd9Sstevel@tonic-gate map_func (char *arg, int flags)
30057c478bd9Sstevel@tonic-gate {
30067c478bd9Sstevel@tonic-gate   char *to_drive;
30077c478bd9Sstevel@tonic-gate   char *from_drive;
30087c478bd9Sstevel@tonic-gate   unsigned long to, from;
30097c478bd9Sstevel@tonic-gate   int i;
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate   to_drive = arg;
30127c478bd9Sstevel@tonic-gate   from_drive = skip_to (0, arg);
30137c478bd9Sstevel@tonic-gate 
30147c478bd9Sstevel@tonic-gate   /* Get the drive number for TO_DRIVE.  */
30157c478bd9Sstevel@tonic-gate   set_device (to_drive);
30167c478bd9Sstevel@tonic-gate   if (errnum)
30177c478bd9Sstevel@tonic-gate     return 1;
30187c478bd9Sstevel@tonic-gate   to = current_drive;
30197c478bd9Sstevel@tonic-gate 
30207c478bd9Sstevel@tonic-gate   /* Get the drive number for FROM_DRIVE.  */
30217c478bd9Sstevel@tonic-gate   set_device (from_drive);
30227c478bd9Sstevel@tonic-gate   if (errnum)
30237c478bd9Sstevel@tonic-gate     return 1;
30247c478bd9Sstevel@tonic-gate   from = current_drive;
30257c478bd9Sstevel@tonic-gate 
30267c478bd9Sstevel@tonic-gate   /* Search for an empty slot in BIOS_DRIVE_MAP.  */
30277c478bd9Sstevel@tonic-gate   for (i = 0; i < DRIVE_MAP_SIZE; i++)
30287c478bd9Sstevel@tonic-gate     {
30297c478bd9Sstevel@tonic-gate       /* Perhaps the user wants to override the map.  */
30307c478bd9Sstevel@tonic-gate       if ((bios_drive_map[i] & 0xff) == from)
30317c478bd9Sstevel@tonic-gate 	break;
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate       if (! bios_drive_map[i])
30347c478bd9Sstevel@tonic-gate 	break;
30357c478bd9Sstevel@tonic-gate     }
30367c478bd9Sstevel@tonic-gate 
30377c478bd9Sstevel@tonic-gate   if (i == DRIVE_MAP_SIZE)
30387c478bd9Sstevel@tonic-gate     {
30397c478bd9Sstevel@tonic-gate       errnum = ERR_WONT_FIT;
30407c478bd9Sstevel@tonic-gate       return 1;
30417c478bd9Sstevel@tonic-gate     }
30427c478bd9Sstevel@tonic-gate 
30437c478bd9Sstevel@tonic-gate   if (to == from)
30447c478bd9Sstevel@tonic-gate     /* If TO is equal to FROM, delete the entry.  */
30457c478bd9Sstevel@tonic-gate     grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i + 1],
30467c478bd9Sstevel@tonic-gate 		  sizeof (unsigned short) * (DRIVE_MAP_SIZE - i));
30477c478bd9Sstevel@tonic-gate   else
30487c478bd9Sstevel@tonic-gate     bios_drive_map[i] = from | (to << 8);
30497c478bd9Sstevel@tonic-gate 
30507c478bd9Sstevel@tonic-gate   return 0;
30517c478bd9Sstevel@tonic-gate }
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate static struct builtin builtin_map =
30547c478bd9Sstevel@tonic-gate {
30557c478bd9Sstevel@tonic-gate   "map",
30567c478bd9Sstevel@tonic-gate   map_func,
30577c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
30587c478bd9Sstevel@tonic-gate   "map TO_DRIVE FROM_DRIVE",
30597c478bd9Sstevel@tonic-gate   "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
30607c478bd9Sstevel@tonic-gate   " when you chain-load some operating systems, such as DOS, if such an"
30617c478bd9Sstevel@tonic-gate   " OS resides at a non-first drive."
30627c478bd9Sstevel@tonic-gate };
30637c478bd9Sstevel@tonic-gate 
30647c478bd9Sstevel@tonic-gate 
30657c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
30667c478bd9Sstevel@tonic-gate /* md5crypt */
30677c478bd9Sstevel@tonic-gate static int
md5crypt_func(char * arg,int flags)30687c478bd9Sstevel@tonic-gate md5crypt_func (char *arg, int flags)
30697c478bd9Sstevel@tonic-gate {
30707c478bd9Sstevel@tonic-gate   char crypted[36];
30717c478bd9Sstevel@tonic-gate   char key[32];
30727c478bd9Sstevel@tonic-gate   unsigned int seed;
30737c478bd9Sstevel@tonic-gate   int i;
30747c478bd9Sstevel@tonic-gate   const char *const seedchars =
30757c478bd9Sstevel@tonic-gate     "./0123456789ABCDEFGHIJKLMNOPQRST"
30767c478bd9Sstevel@tonic-gate     "UVWXYZabcdefghijklmnopqrstuvwxyz";
30777c478bd9Sstevel@tonic-gate 
30787c478bd9Sstevel@tonic-gate   /* First create a salt.  */
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate   /* The magical prefix.  */
30817c478bd9Sstevel@tonic-gate   grub_memset (crypted, 0, sizeof (crypted));
30827c478bd9Sstevel@tonic-gate   grub_memmove (crypted, "$1$", 3);
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate   /* Create the length of a salt.  */
30857c478bd9Sstevel@tonic-gate   seed = currticks ();
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate   /* Generate a salt.  */
30887c478bd9Sstevel@tonic-gate   for (i = 0; i < 8 && seed; i++)
30897c478bd9Sstevel@tonic-gate     {
30907c478bd9Sstevel@tonic-gate       /* FIXME: This should be more random.  */
30917c478bd9Sstevel@tonic-gate       crypted[3 + i] = seedchars[seed & 0x3f];
30927c478bd9Sstevel@tonic-gate       seed >>= 6;
30937c478bd9Sstevel@tonic-gate     }
30947c478bd9Sstevel@tonic-gate 
30957c478bd9Sstevel@tonic-gate   /* A salt must be terminated with `$', if it is less than 8 chars.  */
30967c478bd9Sstevel@tonic-gate   crypted[3 + i] = '$';
30977c478bd9Sstevel@tonic-gate 
30987c478bd9Sstevel@tonic-gate #ifdef DEBUG_MD5CRYPT
30997c478bd9Sstevel@tonic-gate   grub_printf ("salt = %s\n", crypted);
31007c478bd9Sstevel@tonic-gate #endif
31017c478bd9Sstevel@tonic-gate 
31027c478bd9Sstevel@tonic-gate   /* Get a password.  */
31037c478bd9Sstevel@tonic-gate   grub_memset (key, 0, sizeof (key));
31047c478bd9Sstevel@tonic-gate   get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
31057c478bd9Sstevel@tonic-gate 
31067c478bd9Sstevel@tonic-gate   /* Crypt the key.  */
31077c478bd9Sstevel@tonic-gate   make_md5_password (key, crypted);
31087c478bd9Sstevel@tonic-gate 
31097c478bd9Sstevel@tonic-gate   grub_printf ("Encrypted: %s\n", crypted);
31107c478bd9Sstevel@tonic-gate   return 0;
31117c478bd9Sstevel@tonic-gate }
31127c478bd9Sstevel@tonic-gate 
31137c478bd9Sstevel@tonic-gate static struct builtin builtin_md5crypt =
31147c478bd9Sstevel@tonic-gate {
31157c478bd9Sstevel@tonic-gate   "md5crypt",
31167c478bd9Sstevel@tonic-gate   md5crypt_func,
31177c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
31187c478bd9Sstevel@tonic-gate   "md5crypt",
31197c478bd9Sstevel@tonic-gate   "Generate a password in MD5 format."
31207c478bd9Sstevel@tonic-gate };
31217c478bd9Sstevel@tonic-gate #endif /* USE_MD5_PASSWORDS */
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 
31247c478bd9Sstevel@tonic-gate /* module */
31257c478bd9Sstevel@tonic-gate static int
module_func(char * arg,int flags)31267c478bd9Sstevel@tonic-gate module_func (char *arg, int flags)
31277c478bd9Sstevel@tonic-gate {
31287c478bd9Sstevel@tonic-gate   int len = grub_strlen (arg);
31297c478bd9Sstevel@tonic-gate 
31307c478bd9Sstevel@tonic-gate   switch (kernel_type)
31317c478bd9Sstevel@tonic-gate     {
31327c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_MULTIBOOT:
31337c478bd9Sstevel@tonic-gate       if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN)
31347c478bd9Sstevel@tonic-gate 	{
31357c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
31367c478bd9Sstevel@tonic-gate 	  return 1;
31377c478bd9Sstevel@tonic-gate 	}
31387c478bd9Sstevel@tonic-gate       grub_memmove (mb_cmdline, arg, len + 1);
31397c478bd9Sstevel@tonic-gate       if (! load_module (arg, mb_cmdline))
31407c478bd9Sstevel@tonic-gate 	return 1;
3141b1b8ab34Slling 
3142b1b8ab34Slling       mb_cmdline += grub_strlen(mb_cmdline) + 1;
31437c478bd9Sstevel@tonic-gate       break;
31447c478bd9Sstevel@tonic-gate 
31457c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_LINUX:
31467c478bd9Sstevel@tonic-gate     case KERNEL_TYPE_BIG_LINUX:
31477c478bd9Sstevel@tonic-gate       if (! load_initrd (arg))
31487c478bd9Sstevel@tonic-gate 	return 1;
31497c478bd9Sstevel@tonic-gate       break;
31507c478bd9Sstevel@tonic-gate 
31517c478bd9Sstevel@tonic-gate     default:
31527c478bd9Sstevel@tonic-gate       errnum = ERR_NEED_MB_KERNEL;
31537c478bd9Sstevel@tonic-gate       return 1;
31547c478bd9Sstevel@tonic-gate     }
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate   return 0;
31577c478bd9Sstevel@tonic-gate }
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate static struct builtin builtin_module =
31607c478bd9Sstevel@tonic-gate {
31617c478bd9Sstevel@tonic-gate   "module",
31627c478bd9Sstevel@tonic-gate   module_func,
31637c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
31647c478bd9Sstevel@tonic-gate   "module FILE [ARG ...]",
31657c478bd9Sstevel@tonic-gate   "Load a boot module FILE for a Multiboot format boot image (no"
31667c478bd9Sstevel@tonic-gate   " interpretation of the file contents is made, so users of this"
31677c478bd9Sstevel@tonic-gate   " command must know what the kernel in question expects). The"
31687c478bd9Sstevel@tonic-gate   " rest of the line is passed as the \"module command line\", like"
31697c478bd9Sstevel@tonic-gate   " the `kernel' command."
31707c478bd9Sstevel@tonic-gate };
31717c478bd9Sstevel@tonic-gate 
3172ae115bc7Smrj /* module$ */
3173ae115bc7Smrj static int
module_dollar_func(char * arg,int flags)3174ae115bc7Smrj module_dollar_func (char *arg, int flags)
3175ae115bc7Smrj {
3176a5602e1bSKeith M Wesolowski   char newarg[MAX_CMDLINE];
3177a5602e1bSKeith M Wesolowski   char *cmdline_sav = mb_cmdline;
3178a5602e1bSKeith M Wesolowski   int err;
3179b1b8ab34Slling 
3180b1b8ab34Slling   grub_printf("loading '%s' ...\n", arg);
3181a5602e1bSKeith M Wesolowski   if ((err = expand_string(arg, newarg, MAX_CMDLINE)) != 0) {
3182a5602e1bSKeith M Wesolowski     errnum = err;
3183a5602e1bSKeith M Wesolowski     return (1);
3184a5602e1bSKeith M Wesolowski   }
3185b1b8ab34Slling 
3186a5602e1bSKeith M Wesolowski   if ((err = module_func(newarg, flags)) != 0)
3187a5602e1bSKeith M Wesolowski     return (err);
3188b1b8ab34Slling 
3189a5602e1bSKeith M Wesolowski   if ((err = expand_string(arg, cmdline_sav, MAX_CMDLINE)) != 0) {
3190a5602e1bSKeith M Wesolowski     errnum = err;
3191a5602e1bSKeith M Wesolowski     return (1);
3192ffb5616eSLin Ling   }
3193b1b8ab34Slling 
3194a5602e1bSKeith M Wesolowski   grub_printf("loading '%s' ...\n", cmdline_sav);
3195b1b8ab34Slling   mb_cmdline += grub_strlen(cmdline_sav) + 1;
3196b1b8ab34Slling   return (0);
3197ae115bc7Smrj }
3198ae115bc7Smrj 
3199ae115bc7Smrj static struct builtin builtin_module_dollar =
3200ae115bc7Smrj {
3201ae115bc7Smrj   "module$",
3202ae115bc7Smrj   module_dollar_func,
3203ae115bc7Smrj   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3204ae115bc7Smrj   "module FILE [ARG ...]",
3205ae115bc7Smrj   " Just like module, but with $ISADIR expansion."
3206ae115bc7Smrj };
3207ae115bc7Smrj 
32087c478bd9Sstevel@tonic-gate 
32097c478bd9Sstevel@tonic-gate /* modulenounzip */
32107c478bd9Sstevel@tonic-gate static int
modulenounzip_func(char * arg,int flags)32117c478bd9Sstevel@tonic-gate modulenounzip_func (char *arg, int flags)
32127c478bd9Sstevel@tonic-gate {
32137c478bd9Sstevel@tonic-gate   int ret;
32147c478bd9Sstevel@tonic-gate 
32157c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
32167c478bd9Sstevel@tonic-gate   no_decompression = 1;
32177c478bd9Sstevel@tonic-gate #endif
32187c478bd9Sstevel@tonic-gate 
32197c478bd9Sstevel@tonic-gate   ret = module_func (arg, flags);
32207c478bd9Sstevel@tonic-gate 
32217c478bd9Sstevel@tonic-gate #ifndef NO_DECOMPRESSION
32227c478bd9Sstevel@tonic-gate   no_decompression = 0;
32237c478bd9Sstevel@tonic-gate #endif
32247c478bd9Sstevel@tonic-gate 
32257c478bd9Sstevel@tonic-gate   return ret;
32267c478bd9Sstevel@tonic-gate }
32277c478bd9Sstevel@tonic-gate 
32287c478bd9Sstevel@tonic-gate static struct builtin builtin_modulenounzip =
32297c478bd9Sstevel@tonic-gate {
32307c478bd9Sstevel@tonic-gate   "modulenounzip",
32317c478bd9Sstevel@tonic-gate   modulenounzip_func,
32327c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
32337c478bd9Sstevel@tonic-gate   "modulenounzip FILE [ARG ...]",
32347c478bd9Sstevel@tonic-gate   "The same as `module', except that automatic decompression is"
32357c478bd9Sstevel@tonic-gate   " disabled."
32367c478bd9Sstevel@tonic-gate };
32377c478bd9Sstevel@tonic-gate 
32387c478bd9Sstevel@tonic-gate 
32397c478bd9Sstevel@tonic-gate /* pager [on|off] */
32407c478bd9Sstevel@tonic-gate static int
pager_func(char * arg,int flags)32417c478bd9Sstevel@tonic-gate pager_func (char *arg, int flags)
32427c478bd9Sstevel@tonic-gate {
32437c478bd9Sstevel@tonic-gate   /* If ARG is empty, toggle the flag.  */
32447c478bd9Sstevel@tonic-gate   if (! *arg)
32457c478bd9Sstevel@tonic-gate     use_pager = ! use_pager;
32467c478bd9Sstevel@tonic-gate   else if (grub_memcmp (arg, "on", 2) == 0)
32477c478bd9Sstevel@tonic-gate     use_pager = 1;
32487c478bd9Sstevel@tonic-gate   else if (grub_memcmp (arg, "off", 3) == 0)
32497c478bd9Sstevel@tonic-gate     use_pager = 0;
32507c478bd9Sstevel@tonic-gate   else
32517c478bd9Sstevel@tonic-gate     {
32527c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
32537c478bd9Sstevel@tonic-gate       return 1;
32547c478bd9Sstevel@tonic-gate     }
32557c478bd9Sstevel@tonic-gate 
32567c478bd9Sstevel@tonic-gate   grub_printf (" Internal pager is now %s\n", use_pager ? "on" : "off");
32577c478bd9Sstevel@tonic-gate   return 0;
32587c478bd9Sstevel@tonic-gate }
32597c478bd9Sstevel@tonic-gate 
32607c478bd9Sstevel@tonic-gate static struct builtin builtin_pager =
32617c478bd9Sstevel@tonic-gate {
32627c478bd9Sstevel@tonic-gate   "pager",
32637c478bd9Sstevel@tonic-gate   pager_func,
32647c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
32657c478bd9Sstevel@tonic-gate   "pager [FLAG]",
32667c478bd9Sstevel@tonic-gate   "Toggle pager mode with no argument. If FLAG is given and its value"
32677c478bd9Sstevel@tonic-gate   " is `on', turn on the mode. If FLAG is `off', turn off the mode."
32687c478bd9Sstevel@tonic-gate };
32697c478bd9Sstevel@tonic-gate 
32707c478bd9Sstevel@tonic-gate 
32717c478bd9Sstevel@tonic-gate /* partnew PART TYPE START LEN */
32727c478bd9Sstevel@tonic-gate static int
partnew_func(char * arg,int flags)32737c478bd9Sstevel@tonic-gate partnew_func (char *arg, int flags)
32747c478bd9Sstevel@tonic-gate {
32757c478bd9Sstevel@tonic-gate   int new_type, new_start, new_len;
32767c478bd9Sstevel@tonic-gate   int start_cl, start_ch, start_dh;
32777c478bd9Sstevel@tonic-gate   int end_cl, end_ch, end_dh;
32787c478bd9Sstevel@tonic-gate   int entry;
32797c478bd9Sstevel@tonic-gate   char mbr[512];
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate   /* Convert a LBA address to a CHS address in the INT 13 format.  */
32827c478bd9Sstevel@tonic-gate   auto void lba_to_chs (int lba, int *cl, int *ch, int *dh);
32837c478bd9Sstevel@tonic-gate   void lba_to_chs (int lba, int *cl, int *ch, int *dh)
32847c478bd9Sstevel@tonic-gate     {
32857c478bd9Sstevel@tonic-gate       int cylinder, head, sector;
32867c478bd9Sstevel@tonic-gate 
32877c478bd9Sstevel@tonic-gate       sector = lba % buf_geom.sectors + 1;
32887c478bd9Sstevel@tonic-gate       head = (lba / buf_geom.sectors) % buf_geom.heads;
32897c478bd9Sstevel@tonic-gate       cylinder = lba / (buf_geom.sectors * buf_geom.heads);
32907c478bd9Sstevel@tonic-gate 
32917c478bd9Sstevel@tonic-gate       if (cylinder >= buf_geom.cylinders)
32927c478bd9Sstevel@tonic-gate 	cylinder = buf_geom.cylinders - 1;
32937c478bd9Sstevel@tonic-gate 
32947c478bd9Sstevel@tonic-gate       *cl = sector | ((cylinder & 0x300) >> 2);
32957c478bd9Sstevel@tonic-gate       *ch = cylinder & 0xFF;
32967c478bd9Sstevel@tonic-gate       *dh = head;
32977c478bd9Sstevel@tonic-gate     }
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate   /* Get the drive and the partition.  */
33007c478bd9Sstevel@tonic-gate   if (! set_device (arg))
33017c478bd9Sstevel@tonic-gate     return 1;
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate   /* The drive must be a hard disk.  */
33047c478bd9Sstevel@tonic-gate   if (! (current_drive & 0x80))
33057c478bd9Sstevel@tonic-gate     {
33067c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
33077c478bd9Sstevel@tonic-gate       return 1;
33087c478bd9Sstevel@tonic-gate     }
33097c478bd9Sstevel@tonic-gate 
33107c478bd9Sstevel@tonic-gate   /* The partition must a primary partition.  */
33117c478bd9Sstevel@tonic-gate   if ((current_partition >> 16) > 3
33127c478bd9Sstevel@tonic-gate       || (current_partition & 0xFFFF) != 0xFFFF)
33137c478bd9Sstevel@tonic-gate     {
33147c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
33157c478bd9Sstevel@tonic-gate       return 1;
33167c478bd9Sstevel@tonic-gate     }
33177c478bd9Sstevel@tonic-gate 
33187c478bd9Sstevel@tonic-gate   entry = current_partition >> 16;
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate   /* Get the new partition type.  */
33217c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
33227c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_type))
33237c478bd9Sstevel@tonic-gate     return 1;
33247c478bd9Sstevel@tonic-gate 
33257c478bd9Sstevel@tonic-gate   /* The partition type is unsigned char.  */
33267c478bd9Sstevel@tonic-gate   if (new_type > 0xFF)
33277c478bd9Sstevel@tonic-gate     {
33287c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
33297c478bd9Sstevel@tonic-gate       return 1;
33307c478bd9Sstevel@tonic-gate     }
33317c478bd9Sstevel@tonic-gate 
33327c478bd9Sstevel@tonic-gate   /* Get the new partition start.  */
33337c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
33347c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_start))
33357c478bd9Sstevel@tonic-gate     return 1;
33367c478bd9Sstevel@tonic-gate 
33377c478bd9Sstevel@tonic-gate   /* Get the new partition length.  */
33387c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
33397c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_len))
33407c478bd9Sstevel@tonic-gate     return 1;
33417c478bd9Sstevel@tonic-gate 
33427c478bd9Sstevel@tonic-gate   /* Read the MBR.  */
33437c478bd9Sstevel@tonic-gate   if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr))
33447c478bd9Sstevel@tonic-gate     return 1;
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate   /* Store the partition information in the MBR.  */
33477c478bd9Sstevel@tonic-gate   lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
33487c478bd9Sstevel@tonic-gate   lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
33497c478bd9Sstevel@tonic-gate 
33507c478bd9Sstevel@tonic-gate   PC_SLICE_FLAG (mbr, entry) = 0;
33517c478bd9Sstevel@tonic-gate   PC_SLICE_HEAD (mbr, entry) = start_dh;
33527c478bd9Sstevel@tonic-gate   PC_SLICE_SEC (mbr, entry) = start_cl;
33537c478bd9Sstevel@tonic-gate   PC_SLICE_CYL (mbr, entry) = start_ch;
33547c478bd9Sstevel@tonic-gate   PC_SLICE_TYPE (mbr, entry) = new_type;
33557c478bd9Sstevel@tonic-gate   PC_SLICE_EHEAD (mbr, entry) = end_dh;
33567c478bd9Sstevel@tonic-gate   PC_SLICE_ESEC (mbr, entry) = end_cl;
33577c478bd9Sstevel@tonic-gate   PC_SLICE_ECYL (mbr, entry) = end_ch;
33587c478bd9Sstevel@tonic-gate   PC_SLICE_START (mbr, entry) = new_start;
33597c478bd9Sstevel@tonic-gate   PC_SLICE_LENGTH (mbr, entry) = new_len;
33607c478bd9Sstevel@tonic-gate 
33617c478bd9Sstevel@tonic-gate   /* Make sure that the MBR has a valid signature.  */
33627c478bd9Sstevel@tonic-gate   PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
33637c478bd9Sstevel@tonic-gate 
33647c478bd9Sstevel@tonic-gate   /* Write back the MBR to the disk.  */
3365342440ecSPrasad Singamsetty   buf_track = BUF_CACHE_INVALID;
33667c478bd9Sstevel@tonic-gate   if (! rawwrite (current_drive, 0, mbr))
33677c478bd9Sstevel@tonic-gate     return 1;
33687c478bd9Sstevel@tonic-gate 
33697c478bd9Sstevel@tonic-gate   return 0;
33707c478bd9Sstevel@tonic-gate }
33717c478bd9Sstevel@tonic-gate 
33727c478bd9Sstevel@tonic-gate static struct builtin builtin_partnew =
33737c478bd9Sstevel@tonic-gate {
33747c478bd9Sstevel@tonic-gate   "partnew",
33757c478bd9Sstevel@tonic-gate   partnew_func,
33767c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
33777c478bd9Sstevel@tonic-gate   "partnew PART TYPE START LEN",
33787c478bd9Sstevel@tonic-gate   "Create a primary partition at the starting address START with the"
33797c478bd9Sstevel@tonic-gate   " length LEN, with the type TYPE. START and LEN are in sector units."
33807c478bd9Sstevel@tonic-gate };
33817c478bd9Sstevel@tonic-gate 
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate /* parttype PART TYPE */
33847c478bd9Sstevel@tonic-gate static int
parttype_func(char * arg,int flags)33857c478bd9Sstevel@tonic-gate parttype_func (char *arg, int flags)
33867c478bd9Sstevel@tonic-gate {
33877c478bd9Sstevel@tonic-gate   int new_type;
33887c478bd9Sstevel@tonic-gate   unsigned long part = 0xFFFFFF;
33899890706eSHans Rosenfeld   unsigned long long start, len, offset, ext_offset, gpt_offset;
339044bc9120SRichard Yao   int entry, type, gpt_count, gpt_size;
33917c478bd9Sstevel@tonic-gate   char mbr[512];
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate   /* Get the drive and the partition.  */
33947c478bd9Sstevel@tonic-gate   if (! set_device (arg))
33957c478bd9Sstevel@tonic-gate     return 1;
33967c478bd9Sstevel@tonic-gate 
33977c478bd9Sstevel@tonic-gate   /* The drive must be a hard disk.  */
33987c478bd9Sstevel@tonic-gate   if (! (current_drive & 0x80))
33997c478bd9Sstevel@tonic-gate     {
34007c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
34017c478bd9Sstevel@tonic-gate       return 1;
34027c478bd9Sstevel@tonic-gate     }
34037c478bd9Sstevel@tonic-gate 
34047c478bd9Sstevel@tonic-gate   /* The partition must be a PC slice.  */
34057c478bd9Sstevel@tonic-gate   if ((current_partition >> 16) == 0xFF
34067c478bd9Sstevel@tonic-gate       || (current_partition & 0xFFFF) != 0xFFFF)
34077c478bd9Sstevel@tonic-gate     {
34087c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
34097c478bd9Sstevel@tonic-gate       return 1;
34107c478bd9Sstevel@tonic-gate     }
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate   /* Get the new partition type.  */
34137c478bd9Sstevel@tonic-gate   arg = skip_to (0, arg);
34147c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &new_type))
34157c478bd9Sstevel@tonic-gate     return 1;
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate   /* The partition type is unsigned char.  */
34187c478bd9Sstevel@tonic-gate   if (new_type > 0xFF)
34197c478bd9Sstevel@tonic-gate     {
34207c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
34217c478bd9Sstevel@tonic-gate       return 1;
34227c478bd9Sstevel@tonic-gate     }
34237c478bd9Sstevel@tonic-gate 
34247c478bd9Sstevel@tonic-gate   /* Look for the partition.  */
34257c478bd9Sstevel@tonic-gate   while (next_partition (current_drive, 0xFFFFFF, &part, &type,
34267c478bd9Sstevel@tonic-gate 			 &start, &len, &offset, &entry,
342744bc9120SRichard Yao 			 &ext_offset, &gpt_offset, &gpt_count, &gpt_size, mbr))
34287c478bd9Sstevel@tonic-gate     {
342944bc9120SRichard Yao 	  /* The partition may not be a GPT partition.  */
343044bc9120SRichard Yao 	  if (gpt_offset != 0)
343144bc9120SRichard Yao 	    {
343244bc9120SRichard Yao 		errnum = ERR_BAD_ARGUMENT;
343344bc9120SRichard Yao 		return 1;
343444bc9120SRichard Yao 	    }
343544bc9120SRichard Yao 
34367c478bd9Sstevel@tonic-gate       if (part == current_partition)
34377c478bd9Sstevel@tonic-gate 	{
34387c478bd9Sstevel@tonic-gate 	  /* Found.  */
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate 	  /* Set the type to NEW_TYPE.  */
34417c478bd9Sstevel@tonic-gate 	  PC_SLICE_TYPE (mbr, entry) = new_type;
34427c478bd9Sstevel@tonic-gate 
34437c478bd9Sstevel@tonic-gate 	  /* Write back the MBR to the disk.  */
3444342440ecSPrasad Singamsetty 	  buf_track = BUF_CACHE_INVALID;
34457c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, offset, mbr))
34467c478bd9Sstevel@tonic-gate 	    return 1;
34477c478bd9Sstevel@tonic-gate 
34487c478bd9Sstevel@tonic-gate 	  /* Succeed.  */
34497c478bd9Sstevel@tonic-gate 	  return 0;
34507c478bd9Sstevel@tonic-gate 	}
34517c478bd9Sstevel@tonic-gate     }
34527c478bd9Sstevel@tonic-gate 
34537c478bd9Sstevel@tonic-gate   /* The partition was not found.  ERRNUM was set by next_partition.  */
34547c478bd9Sstevel@tonic-gate   return 1;
34557c478bd9Sstevel@tonic-gate }
34567c478bd9Sstevel@tonic-gate 
34577c478bd9Sstevel@tonic-gate static struct builtin builtin_parttype =
34587c478bd9Sstevel@tonic-gate {
34597c478bd9Sstevel@tonic-gate   "parttype",
34607c478bd9Sstevel@tonic-gate   parttype_func,
34617c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
34627c478bd9Sstevel@tonic-gate   "parttype PART TYPE",
34637c478bd9Sstevel@tonic-gate   "Change the type of the partition PART to TYPE."
34647c478bd9Sstevel@tonic-gate };
34657c478bd9Sstevel@tonic-gate 
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate /* password */
34687c478bd9Sstevel@tonic-gate static int
password_func(char * arg,int flags)34697c478bd9Sstevel@tonic-gate password_func (char *arg, int flags)
34707c478bd9Sstevel@tonic-gate {
34717c478bd9Sstevel@tonic-gate   int len;
34727c478bd9Sstevel@tonic-gate   password_t type = PASSWORD_PLAIN;
34737c478bd9Sstevel@tonic-gate 
34747c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
34757c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--md5", 5) == 0)
34767c478bd9Sstevel@tonic-gate     {
34777c478bd9Sstevel@tonic-gate       type = PASSWORD_MD5;
34787c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
34797c478bd9Sstevel@tonic-gate     }
34807c478bd9Sstevel@tonic-gate #endif
34817c478bd9Sstevel@tonic-gate   if (grub_memcmp (arg, "--", 2) == 0)
34827c478bd9Sstevel@tonic-gate     {
34837c478bd9Sstevel@tonic-gate       type = PASSWORD_UNSUPPORTED;
34847c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
34857c478bd9Sstevel@tonic-gate     }
34867c478bd9Sstevel@tonic-gate 
34877c478bd9Sstevel@tonic-gate   if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
34887c478bd9Sstevel@tonic-gate     {
34897c478bd9Sstevel@tonic-gate       /* Do password check! */
34907c478bd9Sstevel@tonic-gate       char entered[32];
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate       /* Wipe out any previously entered password */
34937c478bd9Sstevel@tonic-gate       entered[0] = 0;
34947c478bd9Sstevel@tonic-gate       get_cmdline ("Password: ", entered, 31, '*', 0);
34957c478bd9Sstevel@tonic-gate 
34967c478bd9Sstevel@tonic-gate       nul_terminate (arg);
34977c478bd9Sstevel@tonic-gate       if (check_password (entered, arg, type) != 0)
34987c478bd9Sstevel@tonic-gate 	{
34997c478bd9Sstevel@tonic-gate 	  errnum = ERR_PRIVILEGED;
35007c478bd9Sstevel@tonic-gate 	  return 1;
35017c478bd9Sstevel@tonic-gate 	}
35027c478bd9Sstevel@tonic-gate     }
35037c478bd9Sstevel@tonic-gate   else
35047c478bd9Sstevel@tonic-gate     {
35057c478bd9Sstevel@tonic-gate       len = grub_strlen (arg);
35067c478bd9Sstevel@tonic-gate 
35077c478bd9Sstevel@tonic-gate       /* PASSWORD NUL NUL ... */
35087c478bd9Sstevel@tonic-gate       if (len + 2 > PASSWORD_BUFLEN)
35097c478bd9Sstevel@tonic-gate 	{
35107c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
35117c478bd9Sstevel@tonic-gate 	  return 1;
35127c478bd9Sstevel@tonic-gate 	}
35137c478bd9Sstevel@tonic-gate 
35147c478bd9Sstevel@tonic-gate       /* Copy the password and clear the rest of the buffer.  */
35157c478bd9Sstevel@tonic-gate       password = (char *) PASSWORD_BUF;
35167c478bd9Sstevel@tonic-gate       grub_memmove (password, arg, len);
35177c478bd9Sstevel@tonic-gate       grub_memset (password + len, 0, PASSWORD_BUFLEN - len);
35187c478bd9Sstevel@tonic-gate       password_type = type;
35197c478bd9Sstevel@tonic-gate     }
35207c478bd9Sstevel@tonic-gate   return 0;
35217c478bd9Sstevel@tonic-gate }
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate static struct builtin builtin_password =
35247c478bd9Sstevel@tonic-gate {
35257c478bd9Sstevel@tonic-gate   "password",
35267c478bd9Sstevel@tonic-gate   password_func,
35277c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
35287c478bd9Sstevel@tonic-gate   "password [--md5] PASSWD [FILE]",
35297c478bd9Sstevel@tonic-gate   "If used in the first section of a menu file, disable all"
35307c478bd9Sstevel@tonic-gate   " interactive editing control (menu entry editor and"
35317c478bd9Sstevel@tonic-gate   " command line). If the password PASSWD is entered, it loads the"
35327c478bd9Sstevel@tonic-gate   " FILE as a new config file and restarts the GRUB Stage 2. If you"
35337c478bd9Sstevel@tonic-gate   " omit the argument FILE, then GRUB just unlocks privileged"
35347c478bd9Sstevel@tonic-gate   " instructions.  You can also use it in the script section, in"
35357c478bd9Sstevel@tonic-gate   " which case it will ask for the password, before continueing."
35367c478bd9Sstevel@tonic-gate   " The option --md5 tells GRUB that PASSWD is encrypted with"
35377c478bd9Sstevel@tonic-gate   " md5crypt."
35387c478bd9Sstevel@tonic-gate };
35397c478bd9Sstevel@tonic-gate 
35407c478bd9Sstevel@tonic-gate 
35417c478bd9Sstevel@tonic-gate /* pause */
35427c478bd9Sstevel@tonic-gate static int
pause_func(char * arg,int flags)35437c478bd9Sstevel@tonic-gate pause_func (char *arg, int flags)
35447c478bd9Sstevel@tonic-gate {
35457c478bd9Sstevel@tonic-gate   printf("%s\n", arg);
35467c478bd9Sstevel@tonic-gate 
35477c478bd9Sstevel@tonic-gate   /* If ESC is returned, then abort this entry.  */
35487c478bd9Sstevel@tonic-gate   if (ASCII_CHAR (getkey ()) == 27)
35497c478bd9Sstevel@tonic-gate     return 1;
35507c478bd9Sstevel@tonic-gate 
35517c478bd9Sstevel@tonic-gate   return 0;
35527c478bd9Sstevel@tonic-gate }
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate static struct builtin builtin_pause =
35557c478bd9Sstevel@tonic-gate {
35567c478bd9Sstevel@tonic-gate   "pause",
35577c478bd9Sstevel@tonic-gate   pause_func,
35587c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
35597c478bd9Sstevel@tonic-gate   "pause [MESSAGE ...]",
35607c478bd9Sstevel@tonic-gate   "Print MESSAGE, then wait until a key is pressed."
35617c478bd9Sstevel@tonic-gate };
35627c478bd9Sstevel@tonic-gate 
35637c478bd9Sstevel@tonic-gate 
35647c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
35657c478bd9Sstevel@tonic-gate /* quit */
35667c478bd9Sstevel@tonic-gate static int
quit_func(char * arg,int flags)35677c478bd9Sstevel@tonic-gate quit_func (char *arg, int flags)
35687c478bd9Sstevel@tonic-gate {
35697c478bd9Sstevel@tonic-gate   stop ();
35707c478bd9Sstevel@tonic-gate 
35717c478bd9Sstevel@tonic-gate   /* Never reach here.  */
35727c478bd9Sstevel@tonic-gate   return 0;
35737c478bd9Sstevel@tonic-gate }
35747c478bd9Sstevel@tonic-gate 
35757c478bd9Sstevel@tonic-gate static struct builtin builtin_quit =
35767c478bd9Sstevel@tonic-gate {
35777c478bd9Sstevel@tonic-gate   "quit",
35787c478bd9Sstevel@tonic-gate   quit_func,
35797c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
35807c478bd9Sstevel@tonic-gate   "quit",
35817c478bd9Sstevel@tonic-gate   "Exit from the GRUB shell."
35827c478bd9Sstevel@tonic-gate };
35837c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
35847c478bd9Sstevel@tonic-gate 
35857c478bd9Sstevel@tonic-gate 
35867c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
35877c478bd9Sstevel@tonic-gate /* rarp */
35887c478bd9Sstevel@tonic-gate static int
rarp_func(char * arg,int flags)35897c478bd9Sstevel@tonic-gate rarp_func (char *arg, int flags)
35907c478bd9Sstevel@tonic-gate {
35917c478bd9Sstevel@tonic-gate   if (! rarp ())
35927c478bd9Sstevel@tonic-gate     {
35937c478bd9Sstevel@tonic-gate       if (errnum == ERR_NONE)
35947c478bd9Sstevel@tonic-gate 	errnum = ERR_DEV_VALUES;
35957c478bd9Sstevel@tonic-gate 
35967c478bd9Sstevel@tonic-gate       return 1;
35977c478bd9Sstevel@tonic-gate     }
35987c478bd9Sstevel@tonic-gate 
35997c478bd9Sstevel@tonic-gate   /* Notify the configuration.  */
36007c478bd9Sstevel@tonic-gate   print_network_configuration ();
36017c478bd9Sstevel@tonic-gate   return 0;
36027c478bd9Sstevel@tonic-gate }
36037c478bd9Sstevel@tonic-gate 
36047c478bd9Sstevel@tonic-gate static struct builtin builtin_rarp =
36057c478bd9Sstevel@tonic-gate {
36067c478bd9Sstevel@tonic-gate   "rarp",
36077c478bd9Sstevel@tonic-gate   rarp_func,
36087c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
36097c478bd9Sstevel@tonic-gate   "rarp",
36107c478bd9Sstevel@tonic-gate   "Initialize a network device via RARP."
36117c478bd9Sstevel@tonic-gate };
36127c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
36137c478bd9Sstevel@tonic-gate 
36147c478bd9Sstevel@tonic-gate 
36157c478bd9Sstevel@tonic-gate static int
read_func(char * arg,int flags)36167c478bd9Sstevel@tonic-gate read_func (char *arg, int flags)
36177c478bd9Sstevel@tonic-gate {
36187c478bd9Sstevel@tonic-gate   int addr;
36197c478bd9Sstevel@tonic-gate 
36207c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &addr))
36217c478bd9Sstevel@tonic-gate     return 1;
36227c478bd9Sstevel@tonic-gate 
36237c478bd9Sstevel@tonic-gate   grub_printf ("Address 0x%x: Value 0x%x\n",
36247c478bd9Sstevel@tonic-gate 	       addr, *((unsigned *) RAW_ADDR (addr)));
36257c478bd9Sstevel@tonic-gate   return 0;
36267c478bd9Sstevel@tonic-gate }
36277c478bd9Sstevel@tonic-gate 
36287c478bd9Sstevel@tonic-gate static struct builtin builtin_read =
36297c478bd9Sstevel@tonic-gate {
36307c478bd9Sstevel@tonic-gate   "read",
36317c478bd9Sstevel@tonic-gate   read_func,
36327c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
36337c478bd9Sstevel@tonic-gate   "read ADDR",
36347c478bd9Sstevel@tonic-gate   "Read a 32-bit value from memory at address ADDR and"
36357c478bd9Sstevel@tonic-gate   " display it in hex format."
36367c478bd9Sstevel@tonic-gate };
36377c478bd9Sstevel@tonic-gate 
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate /* reboot */
36407c478bd9Sstevel@tonic-gate static int
reboot_func(char * arg,int flags)36417c478bd9Sstevel@tonic-gate reboot_func (char *arg, int flags)
36427c478bd9Sstevel@tonic-gate {
36437c478bd9Sstevel@tonic-gate   grub_reboot ();
36447c478bd9Sstevel@tonic-gate 
36457c478bd9Sstevel@tonic-gate   /* Never reach here.  */
36467c478bd9Sstevel@tonic-gate   return 1;
36477c478bd9Sstevel@tonic-gate }
36487c478bd9Sstevel@tonic-gate 
36497c478bd9Sstevel@tonic-gate static struct builtin builtin_reboot =
36507c478bd9Sstevel@tonic-gate {
36517c478bd9Sstevel@tonic-gate   "reboot",
36527c478bd9Sstevel@tonic-gate   reboot_func,
36537c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
36547c478bd9Sstevel@tonic-gate   "reboot",
36557c478bd9Sstevel@tonic-gate   "Reboot your system."
36567c478bd9Sstevel@tonic-gate };
36577c478bd9Sstevel@tonic-gate 
36587c478bd9Sstevel@tonic-gate 
36597c478bd9Sstevel@tonic-gate /* Print the root device information.  */
36607c478bd9Sstevel@tonic-gate static void
print_root_device(void)36617c478bd9Sstevel@tonic-gate print_root_device (void)
36627c478bd9Sstevel@tonic-gate {
36637c478bd9Sstevel@tonic-gate   if (saved_drive == NETWORK_DRIVE)
36647c478bd9Sstevel@tonic-gate     {
36657c478bd9Sstevel@tonic-gate       /* Network drive.  */
36667c478bd9Sstevel@tonic-gate       grub_printf (" (nd):");
36677c478bd9Sstevel@tonic-gate     }
36687c478bd9Sstevel@tonic-gate   else if (saved_drive & 0x80)
36697c478bd9Sstevel@tonic-gate     {
36707c478bd9Sstevel@tonic-gate       /* Hard disk drive.  */
36717c478bd9Sstevel@tonic-gate       grub_printf (" (hd%d", saved_drive - 0x80);
36727c478bd9Sstevel@tonic-gate 
36737c478bd9Sstevel@tonic-gate       if ((saved_partition & 0xFF0000) != 0xFF0000)
36747c478bd9Sstevel@tonic-gate 	grub_printf (",%d", saved_partition >> 16);
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate       if ((saved_partition & 0x00FF00) != 0x00FF00)
36777c478bd9Sstevel@tonic-gate 	grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a');
36787c478bd9Sstevel@tonic-gate 
36797c478bd9Sstevel@tonic-gate       grub_printf ("):");
36807c478bd9Sstevel@tonic-gate     }
36817c478bd9Sstevel@tonic-gate   else
36827c478bd9Sstevel@tonic-gate     {
36837c478bd9Sstevel@tonic-gate       /* Floppy disk drive.  */
36847c478bd9Sstevel@tonic-gate       grub_printf (" (fd%d):", saved_drive);
36857c478bd9Sstevel@tonic-gate     }
36867c478bd9Sstevel@tonic-gate 
36877c478bd9Sstevel@tonic-gate   /* Print the filesystem information.  */
36887c478bd9Sstevel@tonic-gate   current_partition = saved_partition;
36897c478bd9Sstevel@tonic-gate   current_drive = saved_drive;
36907c478bd9Sstevel@tonic-gate   print_fsys_type ();
36917c478bd9Sstevel@tonic-gate }
36927c478bd9Sstevel@tonic-gate 
36937c478bd9Sstevel@tonic-gate static int
real_root_func(char * arg,int attempt_mount)36947c478bd9Sstevel@tonic-gate real_root_func (char *arg, int attempt_mount)
36957c478bd9Sstevel@tonic-gate {
36967c478bd9Sstevel@tonic-gate   int hdbias = 0;
36977c478bd9Sstevel@tonic-gate   char *biasptr;
36987c478bd9Sstevel@tonic-gate   char *next;
36997c478bd9Sstevel@tonic-gate 
37007c478bd9Sstevel@tonic-gate   /* If ARG is empty, just print the current root device.  */
37017c478bd9Sstevel@tonic-gate   if (! *arg)
37027c478bd9Sstevel@tonic-gate     {
37037c478bd9Sstevel@tonic-gate       print_root_device ();
37047c478bd9Sstevel@tonic-gate       return 0;
37057c478bd9Sstevel@tonic-gate     }
37067c478bd9Sstevel@tonic-gate 
37077c478bd9Sstevel@tonic-gate   /* Call set_device to get the drive and the partition in ARG.  */
37087c478bd9Sstevel@tonic-gate   next = set_device (arg);
37097c478bd9Sstevel@tonic-gate   if (! next)
37107c478bd9Sstevel@tonic-gate     return 1;
37117c478bd9Sstevel@tonic-gate 
37127c478bd9Sstevel@tonic-gate   /* Ignore ERR_FSYS_MOUNT.  */
37137c478bd9Sstevel@tonic-gate   if (attempt_mount)
37147c478bd9Sstevel@tonic-gate     {
37157c478bd9Sstevel@tonic-gate       if (! open_device () && errnum != ERR_FSYS_MOUNT)
37167c478bd9Sstevel@tonic-gate 	return 1;
37177c478bd9Sstevel@tonic-gate     }
37187c478bd9Sstevel@tonic-gate   else
37197c478bd9Sstevel@tonic-gate     {
37207c478bd9Sstevel@tonic-gate       /* This is necessary, because the location of a partition table
37217c478bd9Sstevel@tonic-gate 	 must be set appropriately.  */
37227c478bd9Sstevel@tonic-gate       if (open_partition ())
37237c478bd9Sstevel@tonic-gate 	{
37247c478bd9Sstevel@tonic-gate 	  set_bootdev (0);
37257c478bd9Sstevel@tonic-gate 	  if (errnum)
37267c478bd9Sstevel@tonic-gate 	    return 1;
37277c478bd9Sstevel@tonic-gate 	}
37287c478bd9Sstevel@tonic-gate     }
37297c478bd9Sstevel@tonic-gate 
37307c478bd9Sstevel@tonic-gate   /* Clear ERRNUM.  */
37317c478bd9Sstevel@tonic-gate   errnum = 0;
37327c478bd9Sstevel@tonic-gate   saved_partition = current_partition;
37337c478bd9Sstevel@tonic-gate   saved_drive = current_drive;
37347c478bd9Sstevel@tonic-gate 
37357c478bd9Sstevel@tonic-gate   if (attempt_mount)
37367c478bd9Sstevel@tonic-gate     {
37377c478bd9Sstevel@tonic-gate       /* BSD and chainloading evil hacks !!  */
37387c478bd9Sstevel@tonic-gate       biasptr = skip_to (0, next);
37397c478bd9Sstevel@tonic-gate       safe_parse_maxint (&biasptr, &hdbias);
37407c478bd9Sstevel@tonic-gate       errnum = 0;
37417c478bd9Sstevel@tonic-gate       bootdev = set_bootdev (hdbias);
37427c478bd9Sstevel@tonic-gate       if (errnum)
37437c478bd9Sstevel@tonic-gate 	return 1;
37447c478bd9Sstevel@tonic-gate 
37457c478bd9Sstevel@tonic-gate       /* Print the type of the filesystem.  */
37467c478bd9Sstevel@tonic-gate       print_fsys_type ();
37477c478bd9Sstevel@tonic-gate     }
37487c478bd9Sstevel@tonic-gate 
37497c478bd9Sstevel@tonic-gate   return 0;
37507c478bd9Sstevel@tonic-gate }
37517c478bd9Sstevel@tonic-gate 
37527c478bd9Sstevel@tonic-gate static int
root_func(char * arg,int flags)37537c478bd9Sstevel@tonic-gate root_func (char *arg, int flags)
37547c478bd9Sstevel@tonic-gate {
3755b1b8ab34Slling   is_zfs_mount = 0;
37567c478bd9Sstevel@tonic-gate   return real_root_func (arg, 1);
37577c478bd9Sstevel@tonic-gate }
37587c478bd9Sstevel@tonic-gate 
37597c478bd9Sstevel@tonic-gate static struct builtin builtin_root =
37607c478bd9Sstevel@tonic-gate {
37617c478bd9Sstevel@tonic-gate   "root",
37627c478bd9Sstevel@tonic-gate   root_func,
37637c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
37647c478bd9Sstevel@tonic-gate   "root [DEVICE [HDBIAS]]",
37657c478bd9Sstevel@tonic-gate   "Set the current \"root device\" to the device DEVICE, then"
37667c478bd9Sstevel@tonic-gate   " attempt to mount it to get the partition size (for passing the"
37677c478bd9Sstevel@tonic-gate   " partition descriptor in `ES:ESI', used by some chain-loaded"
37687c478bd9Sstevel@tonic-gate   " bootloaders), the BSD drive-type (for booting BSD kernels using"
37697c478bd9Sstevel@tonic-gate   " their native boot format), and correctly determine "
37707c478bd9Sstevel@tonic-gate   " the PC partition where a BSD sub-partition is located. The"
37717c478bd9Sstevel@tonic-gate   " optional HDBIAS parameter is a number to tell a BSD kernel"
37727c478bd9Sstevel@tonic-gate   " how many BIOS drive numbers are on controllers before the current"
37737c478bd9Sstevel@tonic-gate   " one. For example, if there is an IDE disk and a SCSI disk, and your"
37747c478bd9Sstevel@tonic-gate   " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."
37757c478bd9Sstevel@tonic-gate };
37767c478bd9Sstevel@tonic-gate 
3777eb2bd662Svikram 
3778eb2bd662Svikram /* findroot */
377917f1e64aSEric Taylor int
findroot_func(char * arg,int flags)3780eb2bd662Svikram findroot_func (char *arg, int flags)
3781eb2bd662Svikram {
3782eb2bd662Svikram   int ret;
3783eb2bd662Svikram   char root[32];
3784eb2bd662Svikram 
3785eb2bd662Svikram   if (grub_strlen(arg) >= BOOTSIGN_ARGLEN) {
3786eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
3787eb2bd662Svikram 	return 1;
3788eb2bd662Svikram   }
3789eb2bd662Svikram 
3790eb2bd662Svikram   if (arg[0] == '\0') {
3791eb2bd662Svikram   	errnum = ERR_BAD_ARGUMENT;
3792eb2bd662Svikram 	return 1;
3793eb2bd662Svikram   }
3794eb2bd662Svikram 
3795051aabe6Staylor   find_best_root = 1;
3796051aabe6Staylor   best_drive = 0;
3797051aabe6Staylor   best_part = 0;
3798eb2bd662Svikram   ret = find_common(arg, root, 1, flags);
3799eb2bd662Svikram   if (ret != 0)
3800eb2bd662Svikram 	return (ret);
3801051aabe6Staylor   find_best_root = 0;
3802eb2bd662Svikram 
3803eb2bd662Svikram   return real_root_func (root, 1);
3804eb2bd662Svikram }
3805eb2bd662Svikram 
3806eb2bd662Svikram static struct builtin builtin_findroot =
3807eb2bd662Svikram {
3808eb2bd662Svikram   "findroot",
3809eb2bd662Svikram   findroot_func,
3810eb2bd662Svikram   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3811963390b4Svikram   "findroot  <SIGNATURE | (SIGNATURE,partition[,slice])>",
3812963390b4Svikram   "Searches across all partitions for the file name SIGNATURE."
3813963390b4Svikram   " GRUB looks only in the directory /boot/grub/bootsign for the"
3814963390b4Svikram   " filename and it stops as soon as it finds the first instance of"
3815963390b4Svikram   " the file - so to be useful the name of the signature file must be"
3816963390b4Svikram   " unique across all partitions. Once the signature file is found,"
3817963390b4Svikram   " GRUB invokes the \"root\" command on that partition."
3818eb2bd662Svikram   " An optional partition and slice may be specified to optimize the search."
3819eb2bd662Svikram };
3820eb2bd662Svikram 
3821b1b8ab34Slling 
3822b1b8ab34Slling /*
3823b1b8ab34Slling  * COMMAND to override the default root filesystem for ZFS
3824b1b8ab34Slling  *	bootfs pool/fs
3825b1b8ab34Slling  */
3826b1b8ab34Slling static int
bootfs_func(char * arg,int flags)3827b1b8ab34Slling bootfs_func (char *arg, int flags)
3828b1b8ab34Slling {
3829b1b8ab34Slling 	int hdbias = 0;
3830b1b8ab34Slling 	char *biasptr;
3831b1b8ab34Slling 	char *next;
3832b1b8ab34Slling 
3833b1b8ab34Slling 	if (! *arg) {
3834b1b8ab34Slling 	    if (current_bootfs[0] != '\0')
3835b1b8ab34Slling 		grub_printf ("The zfs boot filesystem is set to '%s'.\n",
3836b1b8ab34Slling 				current_bootfs);
3837b1b8ab34Slling 	    else if (current_rootpool[0] != 0 && current_bootfs_obj != 0)
3838b1b8ab34Slling 		grub_printf("The zfs boot filesystem is <default: %s/%u>.",
3839b1b8ab34Slling 				current_rootpool, current_bootfs_obj);
3840b1b8ab34Slling 	    else
384111a41203Slling 		grub_printf ("The zfs boot filesystem will be derived from "
384211a41203Slling 			"the default bootfs pool property.\n");
3843b1b8ab34Slling 
3844b1b8ab34Slling 	    return (1);
3845b1b8ab34Slling 	}
3846b1b8ab34Slling 
3847b1b8ab34Slling 	/* Verify the zfs filesystem name */
3848b1b8ab34Slling 	if (arg[0] == '/' || arg[0] == '\0') {
3849b1b8ab34Slling 		errnum = ERR_BAD_ARGUMENT;
3850b1b8ab34Slling 		return 0;
3851b1b8ab34Slling 	}
3852b35c6776Staylor 	if (current_rootpool[0] != 0 && grub_strncmp(arg,
3853b35c6776Staylor 	    current_rootpool, strlen(current_rootpool))) {
3854b35c6776Staylor 		errnum = ERR_BAD_ARGUMENT;
3855b35c6776Staylor 		return 0;
3856b35c6776Staylor 	}
3857b1b8ab34Slling 
3858e23347b1SEric Taylor 	grub_memmove(current_bootfs, arg, MAXNAMELEN);
3859b1b8ab34Slling 
3860b1b8ab34Slling 	return (1);
3861b1b8ab34Slling }
3862b1b8ab34Slling 
3863b1b8ab34Slling static struct builtin builtin_bootfs =
3864b1b8ab34Slling {
3865b1b8ab34Slling   "bootfs",
3866b1b8ab34Slling   bootfs_func,
3867b1b8ab34Slling   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
3868b1b8ab34Slling   "bootfs [ZFSBOOTFS]",
3869b1b8ab34Slling   "Set the current zfs boot filesystem to ZFSBOOTFS (rootpool/rootfs)."
3870b1b8ab34Slling };
3871b1b8ab34Slling 
38727c478bd9Sstevel@tonic-gate 
38737c478bd9Sstevel@tonic-gate /* rootnoverify */
38747c478bd9Sstevel@tonic-gate static int
rootnoverify_func(char * arg,int flags)38757c478bd9Sstevel@tonic-gate rootnoverify_func (char *arg, int flags)
38767c478bd9Sstevel@tonic-gate {
38777c478bd9Sstevel@tonic-gate   return real_root_func (arg, 0);
38787c478bd9Sstevel@tonic-gate }
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate static struct builtin builtin_rootnoverify =
38817c478bd9Sstevel@tonic-gate {
38827c478bd9Sstevel@tonic-gate   "rootnoverify",
38837c478bd9Sstevel@tonic-gate   rootnoverify_func,
38847c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
38857c478bd9Sstevel@tonic-gate   "rootnoverify [DEVICE [HDBIAS]]",
38867c478bd9Sstevel@tonic-gate   "Similar to `root', but don't attempt to mount the partition. This"
38877c478bd9Sstevel@tonic-gate   " is useful for when an OS is outside of the area of the disk that"
38887c478bd9Sstevel@tonic-gate   " GRUB can read, but setting the correct root device is still"
38897c478bd9Sstevel@tonic-gate   " desired. Note that the items mentioned in `root' which"
38907c478bd9Sstevel@tonic-gate   " derived from attempting the mount will NOT work correctly."
38917c478bd9Sstevel@tonic-gate };
38927c478bd9Sstevel@tonic-gate 
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate /* savedefault */
38957c478bd9Sstevel@tonic-gate static int
savedefault_func(char * arg,int flags)38967c478bd9Sstevel@tonic-gate savedefault_func (char *arg, int flags)
38977c478bd9Sstevel@tonic-gate {
38987c478bd9Sstevel@tonic-gate #if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
38997c478bd9Sstevel@tonic-gate   unsigned long tmp_drive = saved_drive;
39007c478bd9Sstevel@tonic-gate   unsigned long tmp_partition = saved_partition;
39017c478bd9Sstevel@tonic-gate   char *default_file = (char *) DEFAULT_FILE_BUF;
39027c478bd9Sstevel@tonic-gate   char buf[10];
39037c478bd9Sstevel@tonic-gate   char sect[SECTOR_SIZE];
39047c478bd9Sstevel@tonic-gate   int entryno;
39057c478bd9Sstevel@tonic-gate   int sector_count = 0;
39069890706eSHans Rosenfeld   unsigned long long saved_sectors[2];
39077c478bd9Sstevel@tonic-gate   int saved_offsets[2];
39087c478bd9Sstevel@tonic-gate   int saved_lengths[2];
39097c478bd9Sstevel@tonic-gate 
3910b1b8ab34Slling   /* not supported for zfs root */
3911b1b8ab34Slling   if (is_zfs_mount == 1) {
3912b1b8ab34Slling 	return (0); /* no-op */
3913b1b8ab34Slling   }
3914b1b8ab34Slling 
39157c478bd9Sstevel@tonic-gate   /* Save sector information about at most two sectors.  */
39169890706eSHans Rosenfeld   auto void disk_read_savesect_func (unsigned long long sector, int offset,
39171b8adde7SWilliam Kucharski       int length);
39189890706eSHans Rosenfeld   void disk_read_savesect_func (unsigned long long sector, int offset, int length)
39197c478bd9Sstevel@tonic-gate     {
39207c478bd9Sstevel@tonic-gate       if (sector_count < 2)
39217c478bd9Sstevel@tonic-gate 	{
39227c478bd9Sstevel@tonic-gate 	  saved_sectors[sector_count] = sector;
39237c478bd9Sstevel@tonic-gate 	  saved_offsets[sector_count] = offset;
39247c478bd9Sstevel@tonic-gate 	  saved_lengths[sector_count] = length;
39257c478bd9Sstevel@tonic-gate 	}
39267c478bd9Sstevel@tonic-gate       sector_count++;
39277c478bd9Sstevel@tonic-gate     }
39287c478bd9Sstevel@tonic-gate 
39297c478bd9Sstevel@tonic-gate   /* This command is only useful when you boot an entry from the menu
39307c478bd9Sstevel@tonic-gate      interface.  */
39317c478bd9Sstevel@tonic-gate   if (! (flags & BUILTIN_SCRIPT))
39327c478bd9Sstevel@tonic-gate     {
39337c478bd9Sstevel@tonic-gate       errnum = ERR_UNRECOGNIZED;
39347c478bd9Sstevel@tonic-gate       return 1;
39357c478bd9Sstevel@tonic-gate     }
39367c478bd9Sstevel@tonic-gate 
39377c478bd9Sstevel@tonic-gate   /* Determine a saved entry number.  */
39387c478bd9Sstevel@tonic-gate   if (*arg)
39397c478bd9Sstevel@tonic-gate     {
39407c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0)
39417c478bd9Sstevel@tonic-gate 	{
39427c478bd9Sstevel@tonic-gate 	  int i;
39437c478bd9Sstevel@tonic-gate 	  int index = 0;
39447c478bd9Sstevel@tonic-gate 
39457c478bd9Sstevel@tonic-gate 	  for (i = 0; i < MAX_FALLBACK_ENTRIES; i++)
39467c478bd9Sstevel@tonic-gate 	    {
39477c478bd9Sstevel@tonic-gate 	      if (fallback_entries[i] < 0)
39487c478bd9Sstevel@tonic-gate 		break;
39497c478bd9Sstevel@tonic-gate 	      if (fallback_entries[i] == current_entryno)
39507c478bd9Sstevel@tonic-gate 		{
39517c478bd9Sstevel@tonic-gate 		  index = i + 1;
39527c478bd9Sstevel@tonic-gate 		  break;
39537c478bd9Sstevel@tonic-gate 		}
39547c478bd9Sstevel@tonic-gate 	    }
39557c478bd9Sstevel@tonic-gate 
39567c478bd9Sstevel@tonic-gate 	  if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0)
39577c478bd9Sstevel@tonic-gate 	    {
39587c478bd9Sstevel@tonic-gate 	      /* This is the last.  */
39597c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
39607c478bd9Sstevel@tonic-gate 	      return 1;
39617c478bd9Sstevel@tonic-gate 	    }
39627c478bd9Sstevel@tonic-gate 
39637c478bd9Sstevel@tonic-gate 	  entryno = fallback_entries[index];
39647c478bd9Sstevel@tonic-gate 	}
39657c478bd9Sstevel@tonic-gate       else if (! safe_parse_maxint (&arg, &entryno))
39667c478bd9Sstevel@tonic-gate 	return 1;
39677c478bd9Sstevel@tonic-gate     }
39687c478bd9Sstevel@tonic-gate   else
39697c478bd9Sstevel@tonic-gate     entryno = current_entryno;
39707c478bd9Sstevel@tonic-gate 
39717c478bd9Sstevel@tonic-gate   /* Open the default file.  */
39727c478bd9Sstevel@tonic-gate   saved_drive = boot_drive;
39737c478bd9Sstevel@tonic-gate   saved_partition = install_partition;
39747c478bd9Sstevel@tonic-gate   if (grub_open (default_file))
39757c478bd9Sstevel@tonic-gate     {
39767c478bd9Sstevel@tonic-gate       int len;
39777c478bd9Sstevel@tonic-gate 
39787c478bd9Sstevel@tonic-gate       disk_read_hook = disk_read_savesect_func;
39797c478bd9Sstevel@tonic-gate       len = grub_read (buf, sizeof (buf));
39807c478bd9Sstevel@tonic-gate       disk_read_hook = 0;
39817c478bd9Sstevel@tonic-gate       grub_close ();
39827c478bd9Sstevel@tonic-gate 
39837c478bd9Sstevel@tonic-gate       if (len != sizeof (buf))
39847c478bd9Sstevel@tonic-gate 	{
39857c478bd9Sstevel@tonic-gate 	  /* This is too small. Do not modify the file manually, please!  */
39867c478bd9Sstevel@tonic-gate 	  errnum = ERR_READ;
39877c478bd9Sstevel@tonic-gate 	  goto fail;
39887c478bd9Sstevel@tonic-gate 	}
39897c478bd9Sstevel@tonic-gate 
39907c478bd9Sstevel@tonic-gate       if (sector_count > 2)
39917c478bd9Sstevel@tonic-gate 	{
39927c478bd9Sstevel@tonic-gate 	  /* Is this possible?! Too fragmented!  */
39937c478bd9Sstevel@tonic-gate 	  errnum = ERR_FSYS_CORRUPT;
39947c478bd9Sstevel@tonic-gate 	  goto fail;
39957c478bd9Sstevel@tonic-gate 	}
39967c478bd9Sstevel@tonic-gate 
39977c478bd9Sstevel@tonic-gate       /* Set up a string to be written.  */
39987c478bd9Sstevel@tonic-gate       grub_memset (buf, '\n', sizeof (buf));
39997c478bd9Sstevel@tonic-gate       grub_sprintf (buf, "%d", entryno);
40007c478bd9Sstevel@tonic-gate 
40017c478bd9Sstevel@tonic-gate       if (saved_lengths[0] < sizeof (buf))
40027c478bd9Sstevel@tonic-gate 	{
40037c478bd9Sstevel@tonic-gate 	  /* The file is anchored to another file and the first few bytes
40047c478bd9Sstevel@tonic-gate 	     are spanned in two sectors. Uggh...  */
40057c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
40067c478bd9Sstevel@tonic-gate 			 sect))
40077c478bd9Sstevel@tonic-gate 	    goto fail;
40087c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]);
40097c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
40107c478bd9Sstevel@tonic-gate 	    goto fail;
40117c478bd9Sstevel@tonic-gate 
40127c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE,
40137c478bd9Sstevel@tonic-gate 			 sect))
40147c478bd9Sstevel@tonic-gate 	    goto fail;
40157c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[1],
40167c478bd9Sstevel@tonic-gate 			buf + saved_lengths[0],
40177c478bd9Sstevel@tonic-gate 			sizeof (buf) - saved_lengths[0]);
40187c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[1], sect))
40197c478bd9Sstevel@tonic-gate 	    goto fail;
40207c478bd9Sstevel@tonic-gate 	}
40217c478bd9Sstevel@tonic-gate       else
40227c478bd9Sstevel@tonic-gate 	{
40237c478bd9Sstevel@tonic-gate 	  /* This is a simple case. It fits into a single sector.  */
40247c478bd9Sstevel@tonic-gate 	  if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE,
40257c478bd9Sstevel@tonic-gate 			 sect))
40267c478bd9Sstevel@tonic-gate 	    goto fail;
40277c478bd9Sstevel@tonic-gate 	  grub_memmove (sect + saved_offsets[0], buf, sizeof (buf));
40287c478bd9Sstevel@tonic-gate 	  if (! rawwrite (current_drive, saved_sectors[0], sect))
40297c478bd9Sstevel@tonic-gate 	    goto fail;
40307c478bd9Sstevel@tonic-gate 	}
40317c478bd9Sstevel@tonic-gate 
40327c478bd9Sstevel@tonic-gate       /* Clear the cache.  */
4033342440ecSPrasad Singamsetty       buf_track = BUF_CACHE_INVALID;
40347c478bd9Sstevel@tonic-gate     }
40357c478bd9Sstevel@tonic-gate 
40367c478bd9Sstevel@tonic-gate  fail:
40377c478bd9Sstevel@tonic-gate   saved_drive = tmp_drive;
40387c478bd9Sstevel@tonic-gate   saved_partition = tmp_partition;
40397c478bd9Sstevel@tonic-gate   return errnum;
40407c478bd9Sstevel@tonic-gate #else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
40417c478bd9Sstevel@tonic-gate   errnum = ERR_UNRECOGNIZED;
40427c478bd9Sstevel@tonic-gate   return 1;
40437c478bd9Sstevel@tonic-gate #endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
40447c478bd9Sstevel@tonic-gate }
40457c478bd9Sstevel@tonic-gate 
40467c478bd9Sstevel@tonic-gate static struct builtin builtin_savedefault =
40477c478bd9Sstevel@tonic-gate {
40487c478bd9Sstevel@tonic-gate   "savedefault",
40497c478bd9Sstevel@tonic-gate   savedefault_func,
40507c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
40517c478bd9Sstevel@tonic-gate   "savedefault [NUM | `fallback']",
40527c478bd9Sstevel@tonic-gate   "Save the current entry as the default boot entry if no argument is"
40537c478bd9Sstevel@tonic-gate   " specified. If a number is specified, this number is saved. If"
40547c478bd9Sstevel@tonic-gate   " `fallback' is used, next fallback entry is saved."
40557c478bd9Sstevel@tonic-gate };
40567c478bd9Sstevel@tonic-gate 
40577c478bd9Sstevel@tonic-gate 
40587c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
40597c478bd9Sstevel@tonic-gate /* serial */
40607c478bd9Sstevel@tonic-gate static int
serial_func(char * arg,int flags)40617c478bd9Sstevel@tonic-gate serial_func (char *arg, int flags)
40627c478bd9Sstevel@tonic-gate {
40635626beecSKeith M Wesolowski   int i;
40645626beecSKeith M Wesolowski   int units[SERIAL_MAX_PORTS];
40655626beecSKeith M Wesolowski   unsigned short ports[SERIAL_MAX_PORTS];
40667c478bd9Sstevel@tonic-gate   unsigned int speed = 9600;
40677c478bd9Sstevel@tonic-gate   int word_len = UART_8BITS_WORD;
40687c478bd9Sstevel@tonic-gate   int parity = UART_NO_PARITY;
40697c478bd9Sstevel@tonic-gate   int stop_bit_len = UART_1_STOP_BIT;
40707c478bd9Sstevel@tonic-gate 
40715626beecSKeith M Wesolowski   for (i = 0; i < SERIAL_MAX_PORTS; ++i)
40725626beecSKeith M Wesolowski     {
40735626beecSKeith M Wesolowski       units[i] = -1;
40745626beecSKeith M Wesolowski       ports[i] = 0;
40755626beecSKeith M Wesolowski     }
40765626beecSKeith M Wesolowski 
40777c478bd9Sstevel@tonic-gate   /* Process GNU-style long options.
40787c478bd9Sstevel@tonic-gate      FIXME: We should implement a getopt-like function, to avoid
40797c478bd9Sstevel@tonic-gate      duplications.  */
40807c478bd9Sstevel@tonic-gate   while (1)
40817c478bd9Sstevel@tonic-gate     {
40827c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
40837c478bd9Sstevel@tonic-gate 	{
40847c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--unit=") - 1;
40857c478bd9Sstevel@tonic-gate 	  int unit;
40865626beecSKeith M Wesolowski 
40875626beecSKeith M Wesolowski 	  i = 0;
40885626beecSKeith M Wesolowski 	  do
40897c478bd9Sstevel@tonic-gate 	    {
40905626beecSKeith M Wesolowski 	      if (i >= SERIAL_MAX_PORTS)
40915626beecSKeith M Wesolowski 		{
40925626beecSKeith M Wesolowski 		  errnum = ERR_DEV_FORMAT;
40935626beecSKeith M Wesolowski 		  return 1;
40945626beecSKeith M Wesolowski 		}
40955626beecSKeith M Wesolowski 
40965626beecSKeith M Wesolowski 	      if (! safe_parse_maxint (&p, &unit))
40975626beecSKeith M Wesolowski 	        return 1;
40985626beecSKeith M Wesolowski 
40995626beecSKeith M Wesolowski 	      if (unit < 0 || unit > 3)
41005626beecSKeith M Wesolowski 	        {
41015626beecSKeith M Wesolowski 	          errnum = ERR_DEV_VALUES;
41025626beecSKeith M Wesolowski 	          return 1;
41035626beecSKeith M Wesolowski 	        }
41047c478bd9Sstevel@tonic-gate 
41055626beecSKeith M Wesolowski 	      units[i++] = unit;
41065626beecSKeith M Wesolowski 	    }
41075626beecSKeith M Wesolowski 	  while (*p++ == ',');
41087c478bd9Sstevel@tonic-gate 	}
41097c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0)
41107c478bd9Sstevel@tonic-gate 	{
41117c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--speed=") - 1;
41127c478bd9Sstevel@tonic-gate 	  int num;
41137c478bd9Sstevel@tonic-gate 
41147c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &num))
41157c478bd9Sstevel@tonic-gate 	    return 1;
41167c478bd9Sstevel@tonic-gate 
41177c478bd9Sstevel@tonic-gate 	  speed = (unsigned int) num;
41187c478bd9Sstevel@tonic-gate 	}
41197c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
41207c478bd9Sstevel@tonic-gate 	{
41217c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--port=") - 1;
41227c478bd9Sstevel@tonic-gate 	  int num;
41237c478bd9Sstevel@tonic-gate 
41245626beecSKeith M Wesolowski 	  i = 0;
41255626beecSKeith M Wesolowski 	  do
41265626beecSKeith M Wesolowski 	    {
41275626beecSKeith M Wesolowski 	      if (i >= SERIAL_MAX_PORTS)
41285626beecSKeith M Wesolowski 		{
41295626beecSKeith M Wesolowski 		  errnum = ERR_DEV_FORMAT;
41305626beecSKeith M Wesolowski 		  return 1;
41315626beecSKeith M Wesolowski 		}
41325626beecSKeith M Wesolowski 
41335626beecSKeith M Wesolowski 	      if (! safe_parse_maxint (&p, &num))
41345626beecSKeith M Wesolowski 	        return 1;
41355626beecSKeith M Wesolowski 
41365626beecSKeith M Wesolowski 	      if (num > 0xffff || num <= 0)
41375626beecSKeith M Wesolowski 		{
41385626beecSKeith M Wesolowski 		  errnum = ERR_DEV_VALUES;
41395626beecSKeith M Wesolowski 		  return 1;
41405626beecSKeith M Wesolowski 		}
41415626beecSKeith M Wesolowski 
41425626beecSKeith M Wesolowski 	      ports[i++] = (unsigned short) num;
41435626beecSKeith M Wesolowski 	    }
41445626beecSKeith M Wesolowski 	  while (*p++ == ',');
41457c478bd9Sstevel@tonic-gate 	}
41467c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
41477c478bd9Sstevel@tonic-gate 	{
41487c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--word=") - 1;
41497c478bd9Sstevel@tonic-gate 	  int len;
41507c478bd9Sstevel@tonic-gate 
41517c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &len))
41527c478bd9Sstevel@tonic-gate 	    return 1;
41537c478bd9Sstevel@tonic-gate 
41547c478bd9Sstevel@tonic-gate 	  switch (len)
41557c478bd9Sstevel@tonic-gate 	    {
41567c478bd9Sstevel@tonic-gate 	    case 5: word_len = UART_5BITS_WORD; break;
41577c478bd9Sstevel@tonic-gate 	    case 6: word_len = UART_6BITS_WORD; break;
41587c478bd9Sstevel@tonic-gate 	    case 7: word_len = UART_7BITS_WORD; break;
41597c478bd9Sstevel@tonic-gate 	    case 8: word_len = UART_8BITS_WORD; break;
41607c478bd9Sstevel@tonic-gate 	    default:
41617c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
41627c478bd9Sstevel@tonic-gate 	      return 1;
41637c478bd9Sstevel@tonic-gate 	    }
41647c478bd9Sstevel@tonic-gate 	}
41657c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
41667c478bd9Sstevel@tonic-gate 	{
41677c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--stop=") - 1;
41687c478bd9Sstevel@tonic-gate 	  int len;
41697c478bd9Sstevel@tonic-gate 
41707c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&p, &len))
41717c478bd9Sstevel@tonic-gate 	    return 1;
41727c478bd9Sstevel@tonic-gate 
41737c478bd9Sstevel@tonic-gate 	  switch (len)
41747c478bd9Sstevel@tonic-gate 	    {
41757c478bd9Sstevel@tonic-gate 	    case 1: stop_bit_len = UART_1_STOP_BIT; break;
41767c478bd9Sstevel@tonic-gate 	    case 2: stop_bit_len = UART_2_STOP_BITS; break;
41777c478bd9Sstevel@tonic-gate 	    default:
41787c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
41797c478bd9Sstevel@tonic-gate 	      return 1;
41807c478bd9Sstevel@tonic-gate 	    }
41817c478bd9Sstevel@tonic-gate 	}
41827c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
41837c478bd9Sstevel@tonic-gate 	{
41847c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--parity=") - 1;
41857c478bd9Sstevel@tonic-gate 
41867c478bd9Sstevel@tonic-gate 	  if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
41877c478bd9Sstevel@tonic-gate 	    parity = UART_NO_PARITY;
41887c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
41897c478bd9Sstevel@tonic-gate 	    parity = UART_ODD_PARITY;
41907c478bd9Sstevel@tonic-gate 	  else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
41917c478bd9Sstevel@tonic-gate 	    parity = UART_EVEN_PARITY;
41927c478bd9Sstevel@tonic-gate 	  else
41937c478bd9Sstevel@tonic-gate 	    {
41947c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
41957c478bd9Sstevel@tonic-gate 	      return 1;
41967c478bd9Sstevel@tonic-gate 	    }
41977c478bd9Sstevel@tonic-gate 	}
41987c478bd9Sstevel@tonic-gate # ifdef GRUB_UTIL
41997c478bd9Sstevel@tonic-gate       /* In the grub shell, don't use any port number but open a tty
42007c478bd9Sstevel@tonic-gate 	 device instead.  */
42017c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
42027c478bd9Sstevel@tonic-gate 	{
42037c478bd9Sstevel@tonic-gate 	  char *p = arg + sizeof ("--device=") - 1;
42047c478bd9Sstevel@tonic-gate 	  char dev[256];	/* XXX */
42057c478bd9Sstevel@tonic-gate 	  char *q = dev;
42067c478bd9Sstevel@tonic-gate 
42077c478bd9Sstevel@tonic-gate 	  while (*p && ! grub_isspace (*p))
42087c478bd9Sstevel@tonic-gate 	    *q++ = *p++;
42097c478bd9Sstevel@tonic-gate 
42107c478bd9Sstevel@tonic-gate 	  *q = 0;
42117c478bd9Sstevel@tonic-gate 	  serial_set_device (dev);
42127c478bd9Sstevel@tonic-gate 	}
42137c478bd9Sstevel@tonic-gate # endif /* GRUB_UTIL */
42147c478bd9Sstevel@tonic-gate       else
42157c478bd9Sstevel@tonic-gate 	break;
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
42187c478bd9Sstevel@tonic-gate     }
42197c478bd9Sstevel@tonic-gate 
42205626beecSKeith M Wesolowski   if (units[0] == -1 && ports[0] == 0)
42215626beecSKeith M Wesolowski     units[0] = 0;
42225626beecSKeith M Wesolowski 
42235626beecSKeith M Wesolowski   for (i = 0; i < SERIAL_MAX_PORTS; ++i)
42245626beecSKeith M Wesolowski     {
42255626beecSKeith M Wesolowski       if (units[i] != -1)
42265626beecSKeith M Wesolowski 	ports[i] = serial_hw_get_port (units[i]);
42275626beecSKeith M Wesolowski       if (ports[i] == 0)
42285626beecSKeith M Wesolowski 	continue;
42295626beecSKeith M Wesolowski 
42305626beecSKeith M Wesolowski       if (serial_hw_init (ports[i], speed, word_len, parity, stop_bit_len))
42315626beecSKeith M Wesolowski 	break;
42325626beecSKeith M Wesolowski     }
42335626beecSKeith M Wesolowski 
42345626beecSKeith M Wesolowski   if (i >= SERIAL_MAX_PORTS)
42357c478bd9Sstevel@tonic-gate     {
42367c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
42377c478bd9Sstevel@tonic-gate       return 1;
42387c478bd9Sstevel@tonic-gate     }
42397c478bd9Sstevel@tonic-gate 
42407c478bd9Sstevel@tonic-gate   return 0;
42417c478bd9Sstevel@tonic-gate }
42427c478bd9Sstevel@tonic-gate 
42437c478bd9Sstevel@tonic-gate static struct builtin builtin_serial =
42447c478bd9Sstevel@tonic-gate {
42457c478bd9Sstevel@tonic-gate   "serial",
42467c478bd9Sstevel@tonic-gate   serial_func,
42477c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
42485626beecSKeith M Wesolowski   "serial [[--unit=UNIT[,UNIT...]] | [--port=PORT[,PORT...]]] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
42497c478bd9Sstevel@tonic-gate   "Initialize a serial device. UNIT is a digit that specifies which serial"
42505626beecSKeith M Wesolowski   " device is used (e.g. 0 == ttya (aka COM1)). If you need to specify the port"
42515626beecSKeith M Wesolowski   " number, set it by --port. Either but not both of --unit and --port is"
42525626beecSKeith M Wesolowski   " permitted; --unit takes precedence. Multiple devices may be specified,"
42535626beecSKeith M Wesolowski   " separated by commas; the first working device in the list will be used"
42545626beecSKeith M Wesolowski   " and the rest ignored. SPEED is the DTE-DTE speed. WORD is the word length,"
42557c478bd9Sstevel@tonic-gate   " PARITY is the type of parity, which is one of `no', `odd' and `even'."
42567c478bd9Sstevel@tonic-gate   " STOP is the length of stop bit(s). The option --device can be used only"
42577c478bd9Sstevel@tonic-gate   " in the grub shell, which specifies the file name of a tty device. The"
42585626beecSKeith M Wesolowski   " default values are ttya, 9600, 8N1."
42597c478bd9Sstevel@tonic-gate };
42607c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
42617c478bd9Sstevel@tonic-gate 
42627c478bd9Sstevel@tonic-gate 
42637c478bd9Sstevel@tonic-gate /* setkey */
42647c478bd9Sstevel@tonic-gate struct keysym
42657c478bd9Sstevel@tonic-gate {
42667c478bd9Sstevel@tonic-gate   char *unshifted_name;			/* the name in unshifted state */
42677c478bd9Sstevel@tonic-gate   char *shifted_name;			/* the name in shifted state */
42687c478bd9Sstevel@tonic-gate   unsigned char unshifted_ascii;	/* the ascii code in unshifted state */
42697c478bd9Sstevel@tonic-gate   unsigned char shifted_ascii;		/* the ascii code in shifted state */
42707c478bd9Sstevel@tonic-gate   unsigned char keycode;		/* keyboard scancode */
42717c478bd9Sstevel@tonic-gate };
42727c478bd9Sstevel@tonic-gate 
42737c478bd9Sstevel@tonic-gate /* The table for key symbols. If the "shifted" member of an entry is
42747c478bd9Sstevel@tonic-gate    NULL, the entry does not have shifted state.  */
42757c478bd9Sstevel@tonic-gate static struct keysym keysym_table[] =
42767c478bd9Sstevel@tonic-gate {
42777c478bd9Sstevel@tonic-gate   {"escape",		0,		0x1b,	0,	0x01},
42787c478bd9Sstevel@tonic-gate   {"1",			"exclam",	'1',	'!',	0x02},
42797c478bd9Sstevel@tonic-gate   {"2",			"at",		'2',	'@',	0x03},
42807c478bd9Sstevel@tonic-gate   {"3",			"numbersign",	'3',	'#',	0x04},
42817c478bd9Sstevel@tonic-gate   {"4",			"dollar",	'4',	'$',	0x05},
42827c478bd9Sstevel@tonic-gate   {"5",			"percent",	'5',	'%',	0x06},
42837c478bd9Sstevel@tonic-gate   {"6",			"caret",	'6',	'^',	0x07},
42847c478bd9Sstevel@tonic-gate   {"7",			"ampersand",	'7',	'&',	0x08},
42857c478bd9Sstevel@tonic-gate   {"8",			"asterisk",	'8',	'*',	0x09},
42867c478bd9Sstevel@tonic-gate   {"9",			"parenleft",	'9',	'(',	0x0a},
42877c478bd9Sstevel@tonic-gate   {"0",			"parenright",	'0',	')',	0x0b},
42887c478bd9Sstevel@tonic-gate   {"minus",		"underscore",	'-',	'_',	0x0c},
42897c478bd9Sstevel@tonic-gate   {"equal",		"plus",		'=',	'+',	0x0d},
42907c478bd9Sstevel@tonic-gate   {"backspace",		0,		'\b',	0,	0x0e},
42917c478bd9Sstevel@tonic-gate   {"tab",		0,		'\t',	0,	0x0f},
42927c478bd9Sstevel@tonic-gate   {"q",			"Q",		'q',	'Q',	0x10},
42937c478bd9Sstevel@tonic-gate   {"w",			"W",		'w',	'W',	0x11},
42947c478bd9Sstevel@tonic-gate   {"e",			"E",		'e',	'E',	0x12},
42957c478bd9Sstevel@tonic-gate   {"r",			"R",		'r',	'R',	0x13},
42967c478bd9Sstevel@tonic-gate   {"t",			"T",		't',	'T',	0x14},
42977c478bd9Sstevel@tonic-gate   {"y",			"Y",		'y',	'Y',	0x15},
42987c478bd9Sstevel@tonic-gate   {"u",			"U",		'u',	'U',	0x16},
42997c478bd9Sstevel@tonic-gate   {"i",			"I",		'i',	'I',	0x17},
43007c478bd9Sstevel@tonic-gate   {"o",			"O",		'o',	'O',	0x18},
43017c478bd9Sstevel@tonic-gate   {"p",			"P",		'p',	'P',	0x19},
43027c478bd9Sstevel@tonic-gate   {"bracketleft",	"braceleft",	'[',	'{',	0x1a},
43037c478bd9Sstevel@tonic-gate   {"bracketright",	"braceright",	']',	'}',	0x1b},
43047c478bd9Sstevel@tonic-gate   {"enter",		0,		'\n',	0,	0x1c},
43057c478bd9Sstevel@tonic-gate   {"control",		0,		0,	0,	0x1d},
43067c478bd9Sstevel@tonic-gate   {"a",			"A",		'a',	'A',	0x1e},
43077c478bd9Sstevel@tonic-gate   {"s",			"S",		's',	'S',	0x1f},
43087c478bd9Sstevel@tonic-gate   {"d",			"D",		'd',	'D',	0x20},
43097c478bd9Sstevel@tonic-gate   {"f",			"F",		'f',	'F',	0x21},
43107c478bd9Sstevel@tonic-gate   {"g",			"G",		'g',	'G',	0x22},
43117c478bd9Sstevel@tonic-gate   {"h",			"H",		'h',	'H',	0x23},
43127c478bd9Sstevel@tonic-gate   {"j",			"J",		'j',	'J',	0x24},
43137c478bd9Sstevel@tonic-gate   {"k",			"K",		'k',	'K',	0x25},
43147c478bd9Sstevel@tonic-gate   {"l",			"L",		'l',	'L',	0x26},
43157c478bd9Sstevel@tonic-gate   {"semicolon",		"colon",	';',	':',	0x27},
43167c478bd9Sstevel@tonic-gate   {"quote",		"doublequote",	'\'',	'"',	0x28},
43177c478bd9Sstevel@tonic-gate   {"backquote",		"tilde",	'`',	'~',	0x29},
43187c478bd9Sstevel@tonic-gate   {"shift",		0,		0,	0,	0x2a},
43197c478bd9Sstevel@tonic-gate   {"backslash",		"bar",		'\\',	'|',	0x2b},
43207c478bd9Sstevel@tonic-gate   {"z",			"Z",		'z',	'Z',	0x2c},
43217c478bd9Sstevel@tonic-gate   {"x",			"X",		'x',	'X',	0x2d},
43227c478bd9Sstevel@tonic-gate   {"c",			"C",		'c',	'C',	0x2e},
43237c478bd9Sstevel@tonic-gate   {"v",			"V",		'v',	'V',	0x2f},
43247c478bd9Sstevel@tonic-gate   {"b",			"B",		'b',	'B',	0x30},
43257c478bd9Sstevel@tonic-gate   {"n",			"N",		'n',	'N',	0x31},
43267c478bd9Sstevel@tonic-gate   {"m",			"M",		'm',	'M',	0x32},
43277c478bd9Sstevel@tonic-gate   {"comma",		"less",		',',	'<',	0x33},
43287c478bd9Sstevel@tonic-gate   {"period",		"greater",	'.',	'>',	0x34},
43297c478bd9Sstevel@tonic-gate   {"slash",		"question",	'/',	'?',	0x35},
43307c478bd9Sstevel@tonic-gate   {"alt",		0,		0,	0,	0x38},
43317c478bd9Sstevel@tonic-gate   {"space",		0,		' ',	0,	0x39},
43327c478bd9Sstevel@tonic-gate   {"capslock",		0,		0,	0,	0x3a},
43337c478bd9Sstevel@tonic-gate   {"F1",		0,		0,	0,	0x3b},
43347c478bd9Sstevel@tonic-gate   {"F2",		0,		0,	0,	0x3c},
43357c478bd9Sstevel@tonic-gate   {"F3",		0,		0,	0,	0x3d},
43367c478bd9Sstevel@tonic-gate   {"F4",		0,		0,	0,	0x3e},
43377c478bd9Sstevel@tonic-gate   {"F5",		0,		0,	0,	0x3f},
43387c478bd9Sstevel@tonic-gate   {"F6",		0,		0,	0,	0x40},
43397c478bd9Sstevel@tonic-gate   {"F7",		0,		0,	0,	0x41},
43407c478bd9Sstevel@tonic-gate   {"F8",		0,		0,	0,	0x42},
43417c478bd9Sstevel@tonic-gate   {"F9",		0,		0,	0,	0x43},
43427c478bd9Sstevel@tonic-gate   {"F10",		0,		0,	0,	0x44},
43437c478bd9Sstevel@tonic-gate   /* Caution: do not add NumLock here! we cannot deal with it properly.  */
43447c478bd9Sstevel@tonic-gate   {"delete",		0,		0x7f,	0,	0x53}
43457c478bd9Sstevel@tonic-gate };
43467c478bd9Sstevel@tonic-gate 
43477c478bd9Sstevel@tonic-gate static int
setkey_func(char * arg,int flags)43487c478bd9Sstevel@tonic-gate setkey_func (char *arg, int flags)
43497c478bd9Sstevel@tonic-gate {
43507c478bd9Sstevel@tonic-gate   char *to_key, *from_key;
43517c478bd9Sstevel@tonic-gate   int to_code, from_code;
43527c478bd9Sstevel@tonic-gate   int map_in_interrupt = 0;
43537c478bd9Sstevel@tonic-gate 
43541b8adde7SWilliam Kucharski   auto int find_key_code (char *key);
43551b8adde7SWilliam Kucharski   auto int find_ascii_code (char *key);
43561b8adde7SWilliam Kucharski 
43571b8adde7SWilliam Kucharski   auto int find_key_code (char *key)
43587c478bd9Sstevel@tonic-gate     {
43597c478bd9Sstevel@tonic-gate       int i;
43607c478bd9Sstevel@tonic-gate 
43617c478bd9Sstevel@tonic-gate       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
43627c478bd9Sstevel@tonic-gate 	{
43637c478bd9Sstevel@tonic-gate 	  if (keysym_table[i].unshifted_name &&
43647c478bd9Sstevel@tonic-gate 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
43657c478bd9Sstevel@tonic-gate 	    return keysym_table[i].keycode;
43667c478bd9Sstevel@tonic-gate 	  else if (keysym_table[i].shifted_name &&
43677c478bd9Sstevel@tonic-gate 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
43687c478bd9Sstevel@tonic-gate 	    return keysym_table[i].keycode;
43697c478bd9Sstevel@tonic-gate 	}
43707c478bd9Sstevel@tonic-gate 
43717c478bd9Sstevel@tonic-gate       return 0;
43727c478bd9Sstevel@tonic-gate     }
43737c478bd9Sstevel@tonic-gate 
43741b8adde7SWilliam Kucharski   auto int find_ascii_code (char *key)
43757c478bd9Sstevel@tonic-gate     {
43767c478bd9Sstevel@tonic-gate       int i;
43777c478bd9Sstevel@tonic-gate 
43787c478bd9Sstevel@tonic-gate       for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
43797c478bd9Sstevel@tonic-gate 	{
43807c478bd9Sstevel@tonic-gate 	  if (keysym_table[i].unshifted_name &&
43817c478bd9Sstevel@tonic-gate 	      grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
43827c478bd9Sstevel@tonic-gate 	    return keysym_table[i].unshifted_ascii;
43837c478bd9Sstevel@tonic-gate 	  else if (keysym_table[i].shifted_name &&
43847c478bd9Sstevel@tonic-gate 		   grub_strcmp (key, keysym_table[i].shifted_name) == 0)
43857c478bd9Sstevel@tonic-gate 	    return keysym_table[i].shifted_ascii;
43867c478bd9Sstevel@tonic-gate 	}
43877c478bd9Sstevel@tonic-gate 
43887c478bd9Sstevel@tonic-gate       return 0;
43897c478bd9Sstevel@tonic-gate     }
43907c478bd9Sstevel@tonic-gate 
43917c478bd9Sstevel@tonic-gate   to_key = arg;
43927c478bd9Sstevel@tonic-gate   from_key = skip_to (0, to_key);
43937c478bd9Sstevel@tonic-gate 
43947c478bd9Sstevel@tonic-gate   if (! *to_key)
43957c478bd9Sstevel@tonic-gate     {
43967c478bd9Sstevel@tonic-gate       /* If the user specifies no argument, reset the key mappings.  */
43977c478bd9Sstevel@tonic-gate       grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
43987c478bd9Sstevel@tonic-gate       grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
43997c478bd9Sstevel@tonic-gate 
44007c478bd9Sstevel@tonic-gate       return 0;
44017c478bd9Sstevel@tonic-gate     }
44027c478bd9Sstevel@tonic-gate   else if (! *from_key)
44037c478bd9Sstevel@tonic-gate     {
44047c478bd9Sstevel@tonic-gate       /* The user must specify two arguments or zero argument.  */
44057c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
44067c478bd9Sstevel@tonic-gate       return 1;
44077c478bd9Sstevel@tonic-gate     }
44087c478bd9Sstevel@tonic-gate 
44097c478bd9Sstevel@tonic-gate   nul_terminate (to_key);
44107c478bd9Sstevel@tonic-gate   nul_terminate (from_key);
44117c478bd9Sstevel@tonic-gate 
44127c478bd9Sstevel@tonic-gate   to_code = find_ascii_code (to_key);
44137c478bd9Sstevel@tonic-gate   from_code = find_ascii_code (from_key);
44147c478bd9Sstevel@tonic-gate   if (! to_code || ! from_code)
44157c478bd9Sstevel@tonic-gate     {
44167c478bd9Sstevel@tonic-gate       map_in_interrupt = 1;
44177c478bd9Sstevel@tonic-gate       to_code = find_key_code (to_key);
44187c478bd9Sstevel@tonic-gate       from_code = find_key_code (from_key);
44197c478bd9Sstevel@tonic-gate       if (! to_code || ! from_code)
44207c478bd9Sstevel@tonic-gate 	{
44217c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
44227c478bd9Sstevel@tonic-gate 	  return 1;
44237c478bd9Sstevel@tonic-gate 	}
44247c478bd9Sstevel@tonic-gate     }
44257c478bd9Sstevel@tonic-gate 
44267c478bd9Sstevel@tonic-gate   if (map_in_interrupt)
44277c478bd9Sstevel@tonic-gate     {
44287c478bd9Sstevel@tonic-gate       int i;
44297c478bd9Sstevel@tonic-gate 
44307c478bd9Sstevel@tonic-gate       /* Find an empty slot.  */
44317c478bd9Sstevel@tonic-gate       for (i = 0; i < KEY_MAP_SIZE; i++)
44327c478bd9Sstevel@tonic-gate 	{
44337c478bd9Sstevel@tonic-gate 	  if ((bios_key_map[i] & 0xff) == from_code)
44347c478bd9Sstevel@tonic-gate 	    /* Perhaps the user wants to overwrite the map.  */
44357c478bd9Sstevel@tonic-gate 	    break;
44367c478bd9Sstevel@tonic-gate 
44377c478bd9Sstevel@tonic-gate 	  if (! bios_key_map[i])
44387c478bd9Sstevel@tonic-gate 	    break;
44397c478bd9Sstevel@tonic-gate 	}
44407c478bd9Sstevel@tonic-gate 
44417c478bd9Sstevel@tonic-gate       if (i == KEY_MAP_SIZE)
44427c478bd9Sstevel@tonic-gate 	{
44437c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
44447c478bd9Sstevel@tonic-gate 	  return 1;
44457c478bd9Sstevel@tonic-gate 	}
44467c478bd9Sstevel@tonic-gate 
44477c478bd9Sstevel@tonic-gate       if (to_code == from_code)
44487c478bd9Sstevel@tonic-gate 	/* If TO is equal to FROM, delete the entry.  */
44497c478bd9Sstevel@tonic-gate 	grub_memmove ((char *) &bios_key_map[i],
44507c478bd9Sstevel@tonic-gate 		      (char *) &bios_key_map[i + 1],
44517c478bd9Sstevel@tonic-gate 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
44527c478bd9Sstevel@tonic-gate       else
44537c478bd9Sstevel@tonic-gate 	bios_key_map[i] = (to_code << 8) | from_code;
44547c478bd9Sstevel@tonic-gate 
44557c478bd9Sstevel@tonic-gate       /* Ugly but should work.  */
44567c478bd9Sstevel@tonic-gate       unset_int15_handler ();
44577c478bd9Sstevel@tonic-gate       set_int15_handler ();
44587c478bd9Sstevel@tonic-gate     }
44597c478bd9Sstevel@tonic-gate   else
44607c478bd9Sstevel@tonic-gate     {
44617c478bd9Sstevel@tonic-gate       int i;
44627c478bd9Sstevel@tonic-gate 
44637c478bd9Sstevel@tonic-gate       /* Find an empty slot.  */
44647c478bd9Sstevel@tonic-gate       for (i = 0; i < KEY_MAP_SIZE; i++)
44657c478bd9Sstevel@tonic-gate 	{
44667c478bd9Sstevel@tonic-gate 	  if ((ascii_key_map[i] & 0xff) == from_code)
44677c478bd9Sstevel@tonic-gate 	    /* Perhaps the user wants to overwrite the map.  */
44687c478bd9Sstevel@tonic-gate 	    break;
44697c478bd9Sstevel@tonic-gate 
44707c478bd9Sstevel@tonic-gate 	  if (! ascii_key_map[i])
44717c478bd9Sstevel@tonic-gate 	    break;
44727c478bd9Sstevel@tonic-gate 	}
44737c478bd9Sstevel@tonic-gate 
44747c478bd9Sstevel@tonic-gate       if (i == KEY_MAP_SIZE)
44757c478bd9Sstevel@tonic-gate 	{
44767c478bd9Sstevel@tonic-gate 	  errnum = ERR_WONT_FIT;
44777c478bd9Sstevel@tonic-gate 	  return 1;
44787c478bd9Sstevel@tonic-gate 	}
44797c478bd9Sstevel@tonic-gate 
44807c478bd9Sstevel@tonic-gate       if (to_code == from_code)
44817c478bd9Sstevel@tonic-gate 	/* If TO is equal to FROM, delete the entry.  */
44827c478bd9Sstevel@tonic-gate 	grub_memmove ((char *) &ascii_key_map[i],
44837c478bd9Sstevel@tonic-gate 		      (char *) &ascii_key_map[i + 1],
44847c478bd9Sstevel@tonic-gate 		      sizeof (unsigned short) * (KEY_MAP_SIZE - i));
44857c478bd9Sstevel@tonic-gate       else
44867c478bd9Sstevel@tonic-gate 	ascii_key_map[i] = (to_code << 8) | from_code;
44877c478bd9Sstevel@tonic-gate     }
44887c478bd9Sstevel@tonic-gate 
44897c478bd9Sstevel@tonic-gate   return 0;
44907c478bd9Sstevel@tonic-gate }
44917c478bd9Sstevel@tonic-gate 
44927c478bd9Sstevel@tonic-gate static struct builtin builtin_setkey =
44937c478bd9Sstevel@tonic-gate {
44947c478bd9Sstevel@tonic-gate   "setkey",
44957c478bd9Sstevel@tonic-gate   setkey_func,
44967c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
44977c478bd9Sstevel@tonic-gate   "setkey [TO_KEY FROM_KEY]",
44987c478bd9Sstevel@tonic-gate   "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
44997c478bd9Sstevel@tonic-gate   " A key must be an alphabet, a digit, or one of these: escape, exclam,"
45007c478bd9Sstevel@tonic-gate   " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft,"
45017c478bd9Sstevel@tonic-gate   " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft,"
45027c478bd9Sstevel@tonic-gate   " braceleft, bracketright, braceright, enter, control, semicolon, colon,"
45037c478bd9Sstevel@tonic-gate   " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
45047c478bd9Sstevel@tonic-gate   " less, period, greater, slash, question, alt, space, capslock, FX (X"
45057c478bd9Sstevel@tonic-gate   " is a digit), and delete. If no argument is specified, reset key"
45067c478bd9Sstevel@tonic-gate   " mappings."
45077c478bd9Sstevel@tonic-gate };
45087c478bd9Sstevel@tonic-gate 
45097c478bd9Sstevel@tonic-gate 
45107c478bd9Sstevel@tonic-gate /* setup */
45117c478bd9Sstevel@tonic-gate static int
setup_func(char * arg,int flags)45127c478bd9Sstevel@tonic-gate setup_func (char *arg, int flags)
45137c478bd9Sstevel@tonic-gate {
45147c478bd9Sstevel@tonic-gate   /* Point to the string of the installed drive/partition.  */
45157c478bd9Sstevel@tonic-gate   char *install_ptr;
45167c478bd9Sstevel@tonic-gate   /* Point to the string of the drive/parition where the GRUB images
45177c478bd9Sstevel@tonic-gate      reside.  */
45187c478bd9Sstevel@tonic-gate   char *image_ptr;
45197c478bd9Sstevel@tonic-gate   unsigned long installed_drive, installed_partition;
45207c478bd9Sstevel@tonic-gate   unsigned long image_drive, image_partition;
45217c478bd9Sstevel@tonic-gate   unsigned long tmp_drive, tmp_partition;
45227c478bd9Sstevel@tonic-gate   char stage1[64];
45237c478bd9Sstevel@tonic-gate   char stage2[64];
45247c478bd9Sstevel@tonic-gate   char config_filename[64];
45257c478bd9Sstevel@tonic-gate   char real_config_filename[64];
45267c478bd9Sstevel@tonic-gate   char cmd_arg[256];
45277c478bd9Sstevel@tonic-gate   char device[16];
45287c478bd9Sstevel@tonic-gate   char *buffer = (char *) RAW_ADDR (0x100000);
45297c478bd9Sstevel@tonic-gate   int is_force_lba = 0;
45307c478bd9Sstevel@tonic-gate   char *stage2_arg = 0;
45317c478bd9Sstevel@tonic-gate   char *prefix = 0;
45327c478bd9Sstevel@tonic-gate 
45337c478bd9Sstevel@tonic-gate   auto int check_file (char *file);
45347c478bd9Sstevel@tonic-gate   auto void sprint_device (int drive, int partition);
45357c478bd9Sstevel@tonic-gate   auto int embed_stage1_5 (char * stage1_5, int drive, int partition);
45367c478bd9Sstevel@tonic-gate 
45377c478bd9Sstevel@tonic-gate   /* Check if the file FILE exists like Autoconf.  */
45387c478bd9Sstevel@tonic-gate   int check_file (char *file)
45397c478bd9Sstevel@tonic-gate     {
45407c478bd9Sstevel@tonic-gate       int ret;
45417c478bd9Sstevel@tonic-gate 
45427c478bd9Sstevel@tonic-gate       grub_printf (" Checking if \"%s\" exists... ", file);
45437c478bd9Sstevel@tonic-gate       ret = grub_open (file);
45447c478bd9Sstevel@tonic-gate       if (ret)
45457c478bd9Sstevel@tonic-gate 	{
45467c478bd9Sstevel@tonic-gate 	  grub_close ();
45477c478bd9Sstevel@tonic-gate 	  grub_printf ("yes\n");
45487c478bd9Sstevel@tonic-gate 	}
45497c478bd9Sstevel@tonic-gate       else
45507c478bd9Sstevel@tonic-gate 	grub_printf ("no\n");
45517c478bd9Sstevel@tonic-gate 
45527c478bd9Sstevel@tonic-gate       return ret;
45537c478bd9Sstevel@tonic-gate     }
45547c478bd9Sstevel@tonic-gate 
45557c478bd9Sstevel@tonic-gate   /* Construct a device name in DEVICE.  */
45567c478bd9Sstevel@tonic-gate   void sprint_device (int drive, int partition)
45577c478bd9Sstevel@tonic-gate     {
45587c478bd9Sstevel@tonic-gate       grub_sprintf (device, "(%cd%d",
45597c478bd9Sstevel@tonic-gate 		    (drive & 0x80) ? 'h' : 'f',
45607c478bd9Sstevel@tonic-gate 		    drive & ~0x80);
45617c478bd9Sstevel@tonic-gate       if ((partition & 0xFF0000) != 0xFF0000)
45627c478bd9Sstevel@tonic-gate 	{
45637c478bd9Sstevel@tonic-gate 	  char tmp[16];
45647c478bd9Sstevel@tonic-gate 	  grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
456509fadd94SJerry Jelinek 	  grub_strncat (device, tmp, sizeof (device));
45667c478bd9Sstevel@tonic-gate 	}
45677c478bd9Sstevel@tonic-gate       if ((partition & 0x00FF00) != 0x00FF00)
45687c478bd9Sstevel@tonic-gate 	{
45697c478bd9Sstevel@tonic-gate 	  char tmp[16];
45707c478bd9Sstevel@tonic-gate 	  grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
457109fadd94SJerry Jelinek 	  grub_strncat (device, tmp, sizeof (device));
45727c478bd9Sstevel@tonic-gate 	}
457309fadd94SJerry Jelinek       grub_strncat (device, ")", sizeof (device));
45747c478bd9Sstevel@tonic-gate     }
45757c478bd9Sstevel@tonic-gate 
45767c478bd9Sstevel@tonic-gate   int embed_stage1_5 (char *stage1_5, int drive, int partition)
45777c478bd9Sstevel@tonic-gate     {
45787c478bd9Sstevel@tonic-gate       /* We install GRUB into the MBR, so try to embed the
45797c478bd9Sstevel@tonic-gate 	 Stage 1.5 in the sectors right after the MBR.  */
45807c478bd9Sstevel@tonic-gate       sprint_device (drive, partition);
45817c478bd9Sstevel@tonic-gate       grub_sprintf (cmd_arg, "%s %s", stage1_5, device);
45827c478bd9Sstevel@tonic-gate 
45837c478bd9Sstevel@tonic-gate       /* Notify what will be run.  */
45847c478bd9Sstevel@tonic-gate       grub_printf (" Running \"embed %s\"... ", cmd_arg);
45857c478bd9Sstevel@tonic-gate 
45867c478bd9Sstevel@tonic-gate       embed_func (cmd_arg, flags);
45877c478bd9Sstevel@tonic-gate       if (! errnum)
45887c478bd9Sstevel@tonic-gate 	{
45897c478bd9Sstevel@tonic-gate 	  /* Construct the blocklist representation.  */
45907c478bd9Sstevel@tonic-gate 	  grub_sprintf (buffer, "%s%s", device, embed_info);
45917c478bd9Sstevel@tonic-gate 	  grub_printf ("succeeded\n");
45927c478bd9Sstevel@tonic-gate 	  return 1;
45937c478bd9Sstevel@tonic-gate 	}
45947c478bd9Sstevel@tonic-gate       else
45957c478bd9Sstevel@tonic-gate 	{
45967c478bd9Sstevel@tonic-gate 	  grub_printf ("failed (this is not fatal)\n");
45977c478bd9Sstevel@tonic-gate 	  return 0;
45987c478bd9Sstevel@tonic-gate 	}
45997c478bd9Sstevel@tonic-gate     }
46007c478bd9Sstevel@tonic-gate 
46017c478bd9Sstevel@tonic-gate   struct stage1_5_map {
46027c478bd9Sstevel@tonic-gate     char *fsys;
46037c478bd9Sstevel@tonic-gate     char *name;
46047c478bd9Sstevel@tonic-gate   };
46057c478bd9Sstevel@tonic-gate   struct stage1_5_map stage1_5_map[] =
46067c478bd9Sstevel@tonic-gate   {
46077c478bd9Sstevel@tonic-gate     {"ext2fs",   "/e2fs_stage1_5"},
46087c478bd9Sstevel@tonic-gate     {"fat",      "/fat_stage1_5"},
46097c478bd9Sstevel@tonic-gate     {"ufs2",     "/ufs2_stage1_5"},
46107c478bd9Sstevel@tonic-gate     {"ffs",      "/ffs_stage1_5"},
46117c478bd9Sstevel@tonic-gate     {"iso9660",  "/iso9660_stage1_5"},
46127c478bd9Sstevel@tonic-gate     {"jfs",      "/jfs_stage1_5"},
46137c478bd9Sstevel@tonic-gate     {"minix",    "/minix_stage1_5"},
46147c478bd9Sstevel@tonic-gate     {"reiserfs", "/reiserfs_stage1_5"},
46157c478bd9Sstevel@tonic-gate     {"vstafs",   "/vstafs_stage1_5"},
46167c478bd9Sstevel@tonic-gate     {"xfs",      "/xfs_stage1_5"},
46177c478bd9Sstevel@tonic-gate     {"ufs",      "/ufs_stage1_5"}
46187c478bd9Sstevel@tonic-gate   };
46197c478bd9Sstevel@tonic-gate 
46207c478bd9Sstevel@tonic-gate   tmp_drive = saved_drive;
46217c478bd9Sstevel@tonic-gate   tmp_partition = saved_partition;
46227c478bd9Sstevel@tonic-gate 
46237c478bd9Sstevel@tonic-gate   /* Check if the user specifies --force-lba.  */
46247c478bd9Sstevel@tonic-gate   while (1)
46257c478bd9Sstevel@tonic-gate     {
46267c478bd9Sstevel@tonic-gate       if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
46277c478bd9Sstevel@tonic-gate 	{
46287c478bd9Sstevel@tonic-gate 	  is_force_lba = 1;
46297c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
46307c478bd9Sstevel@tonic-gate 	}
46317c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) == 0)
46327c478bd9Sstevel@tonic-gate 	{
46337c478bd9Sstevel@tonic-gate 	  prefix = arg + sizeof ("--prefix=") - 1;
46347c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
46357c478bd9Sstevel@tonic-gate 	  nul_terminate (prefix);
46367c478bd9Sstevel@tonic-gate 	}
46377c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
46387c478bd9Sstevel@tonic-gate       else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
46397c478bd9Sstevel@tonic-gate 	{
46407c478bd9Sstevel@tonic-gate 	  stage2_arg = arg;
46417c478bd9Sstevel@tonic-gate 	  arg = skip_to (0, arg);
46427c478bd9Sstevel@tonic-gate 	  nul_terminate (stage2_arg);
46437c478bd9Sstevel@tonic-gate 	}
46447c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
46457c478bd9Sstevel@tonic-gate       else
46467c478bd9Sstevel@tonic-gate 	break;
46477c478bd9Sstevel@tonic-gate     }
46487c478bd9Sstevel@tonic-gate 
46497c478bd9Sstevel@tonic-gate   install_ptr = arg;
46507c478bd9Sstevel@tonic-gate   image_ptr = skip_to (0, install_ptr);
46517c478bd9Sstevel@tonic-gate 
46527c478bd9Sstevel@tonic-gate   /* Make sure that INSTALL_PTR is valid.  */
46537c478bd9Sstevel@tonic-gate   set_device (install_ptr);
46547c478bd9Sstevel@tonic-gate   if (errnum)
46557c478bd9Sstevel@tonic-gate     return 1;
46567c478bd9Sstevel@tonic-gate 
46577c478bd9Sstevel@tonic-gate   installed_drive = current_drive;
46587c478bd9Sstevel@tonic-gate   installed_partition = current_partition;
46597c478bd9Sstevel@tonic-gate 
46607c478bd9Sstevel@tonic-gate   /* Mount the drive pointed by IMAGE_PTR.  */
46617c478bd9Sstevel@tonic-gate   if (*image_ptr)
46627c478bd9Sstevel@tonic-gate     {
46637c478bd9Sstevel@tonic-gate       /* If the drive/partition where the images reside is specified,
46647c478bd9Sstevel@tonic-gate 	 get the drive and the partition.  */
46657c478bd9Sstevel@tonic-gate       set_device (image_ptr);
46667c478bd9Sstevel@tonic-gate       if (errnum)
46677c478bd9Sstevel@tonic-gate 	return 1;
46687c478bd9Sstevel@tonic-gate     }
46697c478bd9Sstevel@tonic-gate   else
46707c478bd9Sstevel@tonic-gate     {
46717c478bd9Sstevel@tonic-gate       /* If omitted, use SAVED_PARTITION and SAVED_DRIVE.  */
46727c478bd9Sstevel@tonic-gate       current_drive = saved_drive;
46737c478bd9Sstevel@tonic-gate       current_partition = saved_partition;
46747c478bd9Sstevel@tonic-gate     }
46757c478bd9Sstevel@tonic-gate 
46767c478bd9Sstevel@tonic-gate   image_drive = saved_drive = current_drive;
46777c478bd9Sstevel@tonic-gate   image_partition = saved_partition = current_partition;
46787c478bd9Sstevel@tonic-gate 
46797c478bd9Sstevel@tonic-gate   /* Open it.  */
46807c478bd9Sstevel@tonic-gate   if (! open_device ())
46817c478bd9Sstevel@tonic-gate     goto fail;
46827c478bd9Sstevel@tonic-gate 
46837c478bd9Sstevel@tonic-gate   /* Check if stage1 exists. If the user doesn't specify the option
46847c478bd9Sstevel@tonic-gate      `--prefix', attempt /boot/grub and /grub.  */
46857c478bd9Sstevel@tonic-gate   /* NOTE: It is dangerous to run this command without `--prefix' in the
46867c478bd9Sstevel@tonic-gate      grub shell, since that affects `--stage2'.  */
46877c478bd9Sstevel@tonic-gate   if (! prefix)
46887c478bd9Sstevel@tonic-gate     {
46897c478bd9Sstevel@tonic-gate       prefix = "/boot/grub";
46907c478bd9Sstevel@tonic-gate       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
46917c478bd9Sstevel@tonic-gate       if (! check_file (stage1))
46927c478bd9Sstevel@tonic-gate 	{
46937c478bd9Sstevel@tonic-gate 	  errnum = ERR_NONE;
46947c478bd9Sstevel@tonic-gate 	  prefix = "/grub";
46957c478bd9Sstevel@tonic-gate 	  grub_sprintf (stage1, "%s%s", prefix, "/stage1");
46967c478bd9Sstevel@tonic-gate 	  if (! check_file (stage1))
46977c478bd9Sstevel@tonic-gate 	    goto fail;
46987c478bd9Sstevel@tonic-gate 	}
46997c478bd9Sstevel@tonic-gate     }
47007c478bd9Sstevel@tonic-gate   else
47017c478bd9Sstevel@tonic-gate     {
47027c478bd9Sstevel@tonic-gate       grub_sprintf (stage1, "%s%s", prefix, "/stage1");
47037c478bd9Sstevel@tonic-gate       if (! check_file (stage1))
47047c478bd9Sstevel@tonic-gate 	goto fail;
47057c478bd9Sstevel@tonic-gate     }
47067c478bd9Sstevel@tonic-gate 
47077c478bd9Sstevel@tonic-gate   /* The prefix was determined.  */
47087c478bd9Sstevel@tonic-gate   grub_sprintf (stage2, "%s%s", prefix, "/stage2");
47097c478bd9Sstevel@tonic-gate   grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst");
47107c478bd9Sstevel@tonic-gate   *real_config_filename = 0;
47117c478bd9Sstevel@tonic-gate 
47127c478bd9Sstevel@tonic-gate   /* Check if stage2 exists.  */
47137c478bd9Sstevel@tonic-gate   if (! check_file (stage2))
47147c478bd9Sstevel@tonic-gate     goto fail;
47157c478bd9Sstevel@tonic-gate 
47167c478bd9Sstevel@tonic-gate   {
47177c478bd9Sstevel@tonic-gate     char *fsys = fsys_table[fsys_type].name;
47187c478bd9Sstevel@tonic-gate     int i;
47197c478bd9Sstevel@tonic-gate     int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]);
47207c478bd9Sstevel@tonic-gate 
47217c478bd9Sstevel@tonic-gate     /* Iterate finding the same filesystem name as FSYS.  */
47227c478bd9Sstevel@tonic-gate     for (i = 0; i < size; i++)
47237c478bd9Sstevel@tonic-gate       if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0)
47247c478bd9Sstevel@tonic-gate 	{
47257c478bd9Sstevel@tonic-gate 	  /* OK, check if the Stage 1.5 exists.  */
47267c478bd9Sstevel@tonic-gate 	  char stage1_5[64];
47277c478bd9Sstevel@tonic-gate 
47287c478bd9Sstevel@tonic-gate 	  grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name);
47297c478bd9Sstevel@tonic-gate 	  if (check_file (stage1_5))
47307c478bd9Sstevel@tonic-gate 	    {
47317c478bd9Sstevel@tonic-gate 	      if (embed_stage1_5 (stage1_5,
47327c478bd9Sstevel@tonic-gate 				    installed_drive, installed_partition)
47337c478bd9Sstevel@tonic-gate 		  || embed_stage1_5 (stage1_5,
47347c478bd9Sstevel@tonic-gate 				     image_drive, image_partition))
47357c478bd9Sstevel@tonic-gate 		{
47367c478bd9Sstevel@tonic-gate 		  grub_strcpy (real_config_filename, config_filename);
47377c478bd9Sstevel@tonic-gate 		  sprint_device (image_drive, image_partition);
47387c478bd9Sstevel@tonic-gate 		  grub_sprintf (config_filename, "%s%s", device, stage2);
47397c478bd9Sstevel@tonic-gate 		  grub_strcpy (stage2, buffer);
47407c478bd9Sstevel@tonic-gate 		}
47417c478bd9Sstevel@tonic-gate 	    }
47427c478bd9Sstevel@tonic-gate 	  errnum = 0;
47437c478bd9Sstevel@tonic-gate 	  break;
47447c478bd9Sstevel@tonic-gate 	}
47457c478bd9Sstevel@tonic-gate   }
47467c478bd9Sstevel@tonic-gate 
47477c478bd9Sstevel@tonic-gate   /* Construct a string that is used by the command "install" as its
47487c478bd9Sstevel@tonic-gate      arguments.  */
47497c478bd9Sstevel@tonic-gate   sprint_device (installed_drive, installed_partition);
47507c478bd9Sstevel@tonic-gate 
47517c478bd9Sstevel@tonic-gate #if 1
47527c478bd9Sstevel@tonic-gate   /* Don't embed a drive number unnecessarily.  */
47537c478bd9Sstevel@tonic-gate   grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s",
47547c478bd9Sstevel@tonic-gate 		is_force_lba? "--force-lba " : "",
47557c478bd9Sstevel@tonic-gate 		stage2_arg? stage2_arg : "",
47567c478bd9Sstevel@tonic-gate 		stage2_arg? " " : "",
47577c478bd9Sstevel@tonic-gate 		stage1,
47587c478bd9Sstevel@tonic-gate 		(installed_drive != image_drive) ? "d " : "",
47597c478bd9Sstevel@tonic-gate 		device,
47607c478bd9Sstevel@tonic-gate 		stage2,
47617c478bd9Sstevel@tonic-gate 		config_filename,
47627c478bd9Sstevel@tonic-gate 		real_config_filename);
47637c478bd9Sstevel@tonic-gate #else /* NOT USED */
47647c478bd9Sstevel@tonic-gate   /* This code was used, because we belived some BIOSes had a problem
47657c478bd9Sstevel@tonic-gate      that they didn't pass a booting drive correctly. It turned out,
47667c478bd9Sstevel@tonic-gate      however, stage1 could trash a booting drive when checking LBA support,
47677c478bd9Sstevel@tonic-gate      because some BIOSes modified the register %dx in INT 13H, AH=48H.
47687c478bd9Sstevel@tonic-gate      So it becamed unclear whether GRUB should use a pre-defined booting
47697c478bd9Sstevel@tonic-gate      drive or not. If the problem still exists, it would be necessary to
47707c478bd9Sstevel@tonic-gate      switch back to this code.  */
47717c478bd9Sstevel@tonic-gate   grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s",
47727c478bd9Sstevel@tonic-gate 		is_force_lba? "--force-lba " : "",
47737c478bd9Sstevel@tonic-gate 		stage2_arg? stage2_arg : "",
47747c478bd9Sstevel@tonic-gate 		stage2_arg? " " : "",
47757c478bd9Sstevel@tonic-gate 		stage1,
47767c478bd9Sstevel@tonic-gate 		device,
47777c478bd9Sstevel@tonic-gate 		stage2,
47787c478bd9Sstevel@tonic-gate 		config_filename,
47797c478bd9Sstevel@tonic-gate 		real_config_filename);
47807c478bd9Sstevel@tonic-gate #endif /* NOT USED */
47817c478bd9Sstevel@tonic-gate 
47827c478bd9Sstevel@tonic-gate   /* Notify what will be run.  */
47837c478bd9Sstevel@tonic-gate   grub_printf (" Running \"install %s\"... ", cmd_arg);
47847c478bd9Sstevel@tonic-gate 
47857c478bd9Sstevel@tonic-gate   /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical
47867c478bd9Sstevel@tonic-gate      with IMAGE_DRIVE and IMAGE_PARTITION, respectively.  */
47877c478bd9Sstevel@tonic-gate   saved_drive = image_drive;
47887c478bd9Sstevel@tonic-gate   saved_partition = image_partition;
47897c478bd9Sstevel@tonic-gate 
47907c478bd9Sstevel@tonic-gate   /* Run the command.  */
47917c478bd9Sstevel@tonic-gate   if (! install_func (cmd_arg, flags))
47927c478bd9Sstevel@tonic-gate     grub_printf ("succeeded\nDone.\n");
47937c478bd9Sstevel@tonic-gate   else
47947c478bd9Sstevel@tonic-gate     grub_printf ("failed\n");
47957c478bd9Sstevel@tonic-gate 
47967c478bd9Sstevel@tonic-gate  fail:
47977c478bd9Sstevel@tonic-gate   saved_drive = tmp_drive;
47987c478bd9Sstevel@tonic-gate   saved_partition = tmp_partition;
47997c478bd9Sstevel@tonic-gate   return errnum;
48007c478bd9Sstevel@tonic-gate }
48017c478bd9Sstevel@tonic-gate 
48027c478bd9Sstevel@tonic-gate static struct builtin builtin_setup =
48037c478bd9Sstevel@tonic-gate {
48047c478bd9Sstevel@tonic-gate   "setup",
48057c478bd9Sstevel@tonic-gate   setup_func,
48067c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
48077c478bd9Sstevel@tonic-gate   "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
48087c478bd9Sstevel@tonic-gate   "Set up the installation of GRUB automatically. This command uses"
48097c478bd9Sstevel@tonic-gate   " the more flexible command \"install\" in the backend and installs"
48107c478bd9Sstevel@tonic-gate   " GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified,"
48117c478bd9Sstevel@tonic-gate   " then find the GRUB images in the device IMAGE_DEVICE, otherwise"
48127c478bd9Sstevel@tonic-gate   " use the current \"root device\", which can be set by the command"
48137c478bd9Sstevel@tonic-gate   " \"root\". If you know that your BIOS should support LBA but GRUB"
48147c478bd9Sstevel@tonic-gate   " doesn't work in LBA mode, specify the option `--force-lba'."
48157c478bd9Sstevel@tonic-gate   " If you install GRUB under the grub shell and you cannot unmount the"
48167c478bd9Sstevel@tonic-gate   " partition where GRUB images reside, specify the option `--stage2'"
48177c478bd9Sstevel@tonic-gate   " to tell GRUB the file name under your OS."
48187c478bd9Sstevel@tonic-gate };
48197c478bd9Sstevel@tonic-gate 
48207c478bd9Sstevel@tonic-gate 
48217c478bd9Sstevel@tonic-gate #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
48227c478bd9Sstevel@tonic-gate /* terminal */
48237c478bd9Sstevel@tonic-gate static int
terminal_func(char * arg,int flags)48247c478bd9Sstevel@tonic-gate terminal_func (char *arg, int flags)
48257c478bd9Sstevel@tonic-gate {
48267c478bd9Sstevel@tonic-gate   /* The index of the default terminal in TERM_TABLE.  */
48277c478bd9Sstevel@tonic-gate   int default_term = -1;
48287c478bd9Sstevel@tonic-gate   struct term_entry *prev_term = current_term;
48297c478bd9Sstevel@tonic-gate   int to = -1;
48307c478bd9Sstevel@tonic-gate   int lines = 0;
48317c478bd9Sstevel@tonic-gate   int no_message = 0;
48327c478bd9Sstevel@tonic-gate   unsigned long term_flags = 0;
48337c478bd9Sstevel@tonic-gate   /* XXX: Assume less than 32 terminals.  */
48347c478bd9Sstevel@tonic-gate   unsigned long term_bitmap = 0;
48357c478bd9Sstevel@tonic-gate 
48367c478bd9Sstevel@tonic-gate   /* Get GNU-style long options.  */
48377c478bd9Sstevel@tonic-gate   while (1)
48387c478bd9Sstevel@tonic-gate     {
48397c478bd9Sstevel@tonic-gate       if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0)
48407c478bd9Sstevel@tonic-gate 	term_flags |= TERM_DUMB;
48417c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0)
48427c478bd9Sstevel@tonic-gate 	/* ``--no-echo'' implies ``--no-edit''.  */
48437c478bd9Sstevel@tonic-gate 	term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT);
48447c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0)
48457c478bd9Sstevel@tonic-gate 	term_flags |= TERM_NO_EDIT;
48467c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0)
48477c478bd9Sstevel@tonic-gate 	{
48487c478bd9Sstevel@tonic-gate 	  char *val = arg + sizeof ("--timeout=") - 1;
48497c478bd9Sstevel@tonic-gate 
48507c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&val, &to))
48517c478bd9Sstevel@tonic-gate 	    return 1;
48527c478bd9Sstevel@tonic-gate 	}
48537c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0)
48547c478bd9Sstevel@tonic-gate 	{
48557c478bd9Sstevel@tonic-gate 	  char *val = arg + sizeof ("--lines=") - 1;
48567c478bd9Sstevel@tonic-gate 
48577c478bd9Sstevel@tonic-gate 	  if (! safe_parse_maxint (&val, &lines))
48587c478bd9Sstevel@tonic-gate 	    return 1;
48597c478bd9Sstevel@tonic-gate 
48607c478bd9Sstevel@tonic-gate 	  /* Probably less than four is meaningless....  */
48617c478bd9Sstevel@tonic-gate 	  if (lines < 4)
48627c478bd9Sstevel@tonic-gate 	    {
48637c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
48647c478bd9Sstevel@tonic-gate 	      return 1;
48657c478bd9Sstevel@tonic-gate 	    }
48667c478bd9Sstevel@tonic-gate 	}
48677c478bd9Sstevel@tonic-gate       else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0)
48687c478bd9Sstevel@tonic-gate 	no_message = 1;
48697c478bd9Sstevel@tonic-gate       else
48707c478bd9Sstevel@tonic-gate 	break;
48717c478bd9Sstevel@tonic-gate 
48727c478bd9Sstevel@tonic-gate       arg = skip_to (0, arg);
48737c478bd9Sstevel@tonic-gate     }
48747c478bd9Sstevel@tonic-gate 
48757c478bd9Sstevel@tonic-gate   /* If no argument is specified, show current setting.  */
48767c478bd9Sstevel@tonic-gate   if (! *arg)
48777c478bd9Sstevel@tonic-gate     {
48787c478bd9Sstevel@tonic-gate       grub_printf ("%s%s%s%s\n",
48797c478bd9Sstevel@tonic-gate 		   current_term->name,
48807c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_DUMB ? " (dumb)" : "",
48817c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_NO_EDIT ? " (no edit)" : "",
48827c478bd9Sstevel@tonic-gate 		   current_term->flags & TERM_NO_ECHO ? " (no echo)" : "");
48837c478bd9Sstevel@tonic-gate       return 0;
48847c478bd9Sstevel@tonic-gate     }
48857c478bd9Sstevel@tonic-gate 
48867c478bd9Sstevel@tonic-gate   while (*arg)
48877c478bd9Sstevel@tonic-gate     {
48887c478bd9Sstevel@tonic-gate       int i;
48897c478bd9Sstevel@tonic-gate       char *next = skip_to (0, arg);
48907c478bd9Sstevel@tonic-gate 
48917c478bd9Sstevel@tonic-gate       nul_terminate (arg);
48927c478bd9Sstevel@tonic-gate 
48937c478bd9Sstevel@tonic-gate       for (i = 0; term_table[i].name; i++)
48947c478bd9Sstevel@tonic-gate 	{
48957c478bd9Sstevel@tonic-gate 	  if (grub_strcmp (arg, term_table[i].name) == 0)
48967c478bd9Sstevel@tonic-gate 	    {
48977c478bd9Sstevel@tonic-gate 	      if (term_table[i].flags & TERM_NEED_INIT)
48987c478bd9Sstevel@tonic-gate 		{
48997c478bd9Sstevel@tonic-gate 		  errnum = ERR_DEV_NEED_INIT;
49007c478bd9Sstevel@tonic-gate 		  return 1;
49017c478bd9Sstevel@tonic-gate 		}
49027c478bd9Sstevel@tonic-gate 
49037c478bd9Sstevel@tonic-gate 	      if (default_term < 0)
49047c478bd9Sstevel@tonic-gate 		default_term = i;
49057c478bd9Sstevel@tonic-gate 
49067c478bd9Sstevel@tonic-gate 	      term_bitmap |= (1 << i);
49077c478bd9Sstevel@tonic-gate 	      break;
49087c478bd9Sstevel@tonic-gate 	    }
49097c478bd9Sstevel@tonic-gate 	}
49107c478bd9Sstevel@tonic-gate 
49117c478bd9Sstevel@tonic-gate       if (! term_table[i].name)
49127c478bd9Sstevel@tonic-gate 	{
49137c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
49147c478bd9Sstevel@tonic-gate 	  return 1;
49157c478bd9Sstevel@tonic-gate 	}
49167c478bd9Sstevel@tonic-gate 
49177c478bd9Sstevel@tonic-gate       arg = next;
49187c478bd9Sstevel@tonic-gate     }
49197c478bd9Sstevel@tonic-gate 
49207c478bd9Sstevel@tonic-gate   /* If multiple terminals are specified, wait until the user pushes any
49217c478bd9Sstevel@tonic-gate      key on one of the terminals.  */
49227c478bd9Sstevel@tonic-gate   if (term_bitmap & ~(1 << default_term))
49237c478bd9Sstevel@tonic-gate     {
49247c478bd9Sstevel@tonic-gate       int time1, time2 = -1;
49257c478bd9Sstevel@tonic-gate 
49267c478bd9Sstevel@tonic-gate       /* XXX: Disable the pager.  */
49277c478bd9Sstevel@tonic-gate       count_lines = -1;
49287c478bd9Sstevel@tonic-gate 
49297c478bd9Sstevel@tonic-gate       /* Get current time.  */
49307c478bd9Sstevel@tonic-gate       while ((time1 = getrtsecs ()) == 0xFF)
49317c478bd9Sstevel@tonic-gate 	;
49327c478bd9Sstevel@tonic-gate 
49337c478bd9Sstevel@tonic-gate       /* Wait for a key input.  */
49347c478bd9Sstevel@tonic-gate       while (to)
49357c478bd9Sstevel@tonic-gate 	{
49367c478bd9Sstevel@tonic-gate 	  int i;
49377c478bd9Sstevel@tonic-gate 
49387c478bd9Sstevel@tonic-gate 	  for (i = 0; term_table[i].name; i++)
49397c478bd9Sstevel@tonic-gate 	    {
49407c478bd9Sstevel@tonic-gate 	      if (term_bitmap & (1 << i))
49417c478bd9Sstevel@tonic-gate 		{
49427c478bd9Sstevel@tonic-gate 		  if (term_table[i].checkkey () >= 0)
49437c478bd9Sstevel@tonic-gate 		    {
49447c478bd9Sstevel@tonic-gate 		      (void) term_table[i].getkey ();
49457c478bd9Sstevel@tonic-gate 		      default_term = i;
49467c478bd9Sstevel@tonic-gate 
49477c478bd9Sstevel@tonic-gate 		      goto end;
49487c478bd9Sstevel@tonic-gate 		    }
49497c478bd9Sstevel@tonic-gate 		}
49507c478bd9Sstevel@tonic-gate 	    }
49517c478bd9Sstevel@tonic-gate 
49527c478bd9Sstevel@tonic-gate 	  /* Prompt the user, once per sec.  */
49537c478bd9Sstevel@tonic-gate 	  if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
49547c478bd9Sstevel@tonic-gate 	    {
49557c478bd9Sstevel@tonic-gate 	      if (! no_message)
49567c478bd9Sstevel@tonic-gate 		{
49577c478bd9Sstevel@tonic-gate 		  /* Need to set CURRENT_TERM to each of selected
49587c478bd9Sstevel@tonic-gate 		     terminals.  */
49597c478bd9Sstevel@tonic-gate 		  for (i = 0; term_table[i].name; i++)
49607c478bd9Sstevel@tonic-gate 		    if (term_bitmap & (1 << i))
49617c478bd9Sstevel@tonic-gate 		      {
49627c478bd9Sstevel@tonic-gate 			current_term = term_table + i;
49637c478bd9Sstevel@tonic-gate 			grub_printf ("\rPress any key to continue.\n");
49647c478bd9Sstevel@tonic-gate 		      }
49657c478bd9Sstevel@tonic-gate 
49667c478bd9Sstevel@tonic-gate 		  /* Restore CURRENT_TERM.  */
49677c478bd9Sstevel@tonic-gate 		  current_term = prev_term;
49687c478bd9Sstevel@tonic-gate 		}
49697c478bd9Sstevel@tonic-gate 
49707c478bd9Sstevel@tonic-gate 	      time2 = time1;
49717c478bd9Sstevel@tonic-gate 	      if (to > 0)
49727c478bd9Sstevel@tonic-gate 		to--;
49737c478bd9Sstevel@tonic-gate 	    }
49747c478bd9Sstevel@tonic-gate 	}
49757c478bd9Sstevel@tonic-gate     }
49767c478bd9Sstevel@tonic-gate 
49777c478bd9Sstevel@tonic-gate  end:
49787c478bd9Sstevel@tonic-gate   current_term = term_table + default_term;
49797c478bd9Sstevel@tonic-gate   current_term->flags = term_flags;
49809b4e3ac2SWilliam Kucharski 
49817c478bd9Sstevel@tonic-gate   if (lines)
49827c478bd9Sstevel@tonic-gate     max_lines = lines;
49837c478bd9Sstevel@tonic-gate   else
49847c478bd9Sstevel@tonic-gate     max_lines = current_term->max_lines;
49857c478bd9Sstevel@tonic-gate 
49867c478bd9Sstevel@tonic-gate   /* If the interface is currently the command-line,
49877c478bd9Sstevel@tonic-gate      restart it to repaint the screen.  */
49887c478bd9Sstevel@tonic-gate   if ((current_term != prev_term) && (flags & BUILTIN_CMDLINE)){
49897c478bd9Sstevel@tonic-gate     if (prev_term->shutdown)
49907c478bd9Sstevel@tonic-gate       prev_term->shutdown();
49917c478bd9Sstevel@tonic-gate     if (current_term->startup)
49927c478bd9Sstevel@tonic-gate       current_term->startup();
49937c478bd9Sstevel@tonic-gate     grub_longjmp (restart_cmdline_env, 0);
49947c478bd9Sstevel@tonic-gate   }
49957c478bd9Sstevel@tonic-gate 
49967c478bd9Sstevel@tonic-gate   return 0;
49977c478bd9Sstevel@tonic-gate }
49987c478bd9Sstevel@tonic-gate 
49997c478bd9Sstevel@tonic-gate static struct builtin builtin_terminal =
50007c478bd9Sstevel@tonic-gate {
50017c478bd9Sstevel@tonic-gate   "terminal",
50027c478bd9Sstevel@tonic-gate   terminal_func,
50037c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
5004a5602e1bSKeith M Wesolowski   "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules] [graphics] [composite]",
50057c478bd9Sstevel@tonic-gate   "Select a terminal. When multiple terminals are specified, wait until"
50067c478bd9Sstevel@tonic-gate   " you push any key to continue. If both console and serial are specified,"
50077c478bd9Sstevel@tonic-gate   " the terminal to which you input a key first will be selected. If no"
5008a5602e1bSKeith M Wesolowski   " argument is specified, print current setting. To accomodate systems"
5009a5602e1bSKeith M Wesolowski   " where console redirection may or may not be present, the composite"
5010a5602e1bSKeith M Wesolowski   " console will direct output to the serial and BIOS consoles, and accept"
5011a5602e1bSKeith M Wesolowski   " input from either one, without requiring selection. The option --dumb"
50127c478bd9Sstevel@tonic-gate   " specifies that your terminal is dumb, otherwise, vt100-compatibility"
50137c478bd9Sstevel@tonic-gate   " is assumed. If you specify --no-echo, input characters won't be echoed."
50147c478bd9Sstevel@tonic-gate   " If you specify --no-edit, the BASH-like editing feature will be disabled."
50157c478bd9Sstevel@tonic-gate   " If --timeout is present, this command will wait at most for SECS"
50167c478bd9Sstevel@tonic-gate   " seconds. The option --lines specifies the maximum number of lines."
50177c478bd9Sstevel@tonic-gate   " The option --silent is used to suppress messages."
50187c478bd9Sstevel@tonic-gate };
50197c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
50207c478bd9Sstevel@tonic-gate 
50217c478bd9Sstevel@tonic-gate 
50227c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
50237c478bd9Sstevel@tonic-gate static int
terminfo_func(char * arg,int flags)50247c478bd9Sstevel@tonic-gate terminfo_func (char *arg, int flags)
50257c478bd9Sstevel@tonic-gate {
50267c478bd9Sstevel@tonic-gate   struct terminfo term;
50277c478bd9Sstevel@tonic-gate 
50287c478bd9Sstevel@tonic-gate   if (*arg)
50297c478bd9Sstevel@tonic-gate     {
50307c478bd9Sstevel@tonic-gate       struct
50317c478bd9Sstevel@tonic-gate       {
50327c478bd9Sstevel@tonic-gate 	const char *name;
50337c478bd9Sstevel@tonic-gate 	char *var;
50347c478bd9Sstevel@tonic-gate       }
50357c478bd9Sstevel@tonic-gate       options[] =
50367c478bd9Sstevel@tonic-gate 	{
50377c478bd9Sstevel@tonic-gate 	  {"--name=", term.name},
50387c478bd9Sstevel@tonic-gate 	  {"--cursor-address=", term.cursor_address},
50397c478bd9Sstevel@tonic-gate 	  {"--clear-screen=", term.clear_screen},
50407c478bd9Sstevel@tonic-gate 	  {"--enter-standout-mode=", term.enter_standout_mode},
50417c478bd9Sstevel@tonic-gate 	  {"--exit-standout-mode=", term.exit_standout_mode}
50427c478bd9Sstevel@tonic-gate 	};
50437c478bd9Sstevel@tonic-gate 
50447c478bd9Sstevel@tonic-gate       grub_memset (&term, 0, sizeof (term));
50457c478bd9Sstevel@tonic-gate 
50467c478bd9Sstevel@tonic-gate       while (*arg)
50477c478bd9Sstevel@tonic-gate 	{
50487c478bd9Sstevel@tonic-gate 	  int i;
50497c478bd9Sstevel@tonic-gate 	  char *next = skip_to (0, arg);
50507c478bd9Sstevel@tonic-gate 
50517c478bd9Sstevel@tonic-gate 	  nul_terminate (arg);
50527c478bd9Sstevel@tonic-gate 
50537c478bd9Sstevel@tonic-gate 	  for (i = 0; i < sizeof (options) / sizeof (options[0]); i++)
50547c478bd9Sstevel@tonic-gate 	    {
50557c478bd9Sstevel@tonic-gate 	      const char *name = options[i].name;
50567c478bd9Sstevel@tonic-gate 	      int len = grub_strlen (name);
50577c478bd9Sstevel@tonic-gate 
50587c478bd9Sstevel@tonic-gate 	      if (! grub_memcmp (arg, name, len))
50597c478bd9Sstevel@tonic-gate 		{
50607c478bd9Sstevel@tonic-gate 		  grub_strcpy (options[i].var, ti_unescape_string (arg + len));
50617c478bd9Sstevel@tonic-gate 		  break;
50627c478bd9Sstevel@tonic-gate 		}
50637c478bd9Sstevel@tonic-gate 	    }
50647c478bd9Sstevel@tonic-gate 
50657c478bd9Sstevel@tonic-gate 	  if (i == sizeof (options) / sizeof (options[0]))
50667c478bd9Sstevel@tonic-gate 	    {
50677c478bd9Sstevel@tonic-gate 	      errnum = ERR_BAD_ARGUMENT;
50687c478bd9Sstevel@tonic-gate 	      return errnum;
50697c478bd9Sstevel@tonic-gate 	    }
50707c478bd9Sstevel@tonic-gate 
50717c478bd9Sstevel@tonic-gate 	  arg = next;
50727c478bd9Sstevel@tonic-gate 	}
50737c478bd9Sstevel@tonic-gate 
50747c478bd9Sstevel@tonic-gate       if (term.name[0] == 0 || term.cursor_address[0] == 0)
50757c478bd9Sstevel@tonic-gate 	{
50767c478bd9Sstevel@tonic-gate 	  errnum = ERR_BAD_ARGUMENT;
50777c478bd9Sstevel@tonic-gate 	  return errnum;
50787c478bd9Sstevel@tonic-gate 	}
50797c478bd9Sstevel@tonic-gate 
50807c478bd9Sstevel@tonic-gate       ti_set_term (&term);
50817c478bd9Sstevel@tonic-gate     }
50827c478bd9Sstevel@tonic-gate   else
50837c478bd9Sstevel@tonic-gate     {
50847c478bd9Sstevel@tonic-gate       /* No option specifies printing out current settings.  */
50857c478bd9Sstevel@tonic-gate       ti_get_term (&term);
50867c478bd9Sstevel@tonic-gate 
50877c478bd9Sstevel@tonic-gate       grub_printf ("name=%s\n",
50887c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.name));
50897c478bd9Sstevel@tonic-gate       grub_printf ("cursor_address=%s\n",
50907c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.cursor_address));
50917c478bd9Sstevel@tonic-gate       grub_printf ("clear_screen=%s\n",
50927c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.clear_screen));
50937c478bd9Sstevel@tonic-gate       grub_printf ("enter_standout_mode=%s\n",
50947c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.enter_standout_mode));
50957c478bd9Sstevel@tonic-gate       grub_printf ("exit_standout_mode=%s\n",
50967c478bd9Sstevel@tonic-gate 		   ti_escape_string (term.exit_standout_mode));
50977c478bd9Sstevel@tonic-gate     }
50987c478bd9Sstevel@tonic-gate 
50997c478bd9Sstevel@tonic-gate   return 0;
51007c478bd9Sstevel@tonic-gate }
51017c478bd9Sstevel@tonic-gate 
51027c478bd9Sstevel@tonic-gate static struct builtin builtin_terminfo =
51037c478bd9Sstevel@tonic-gate {
51047c478bd9Sstevel@tonic-gate   "terminfo",
51057c478bd9Sstevel@tonic-gate   terminfo_func,
51067c478bd9Sstevel@tonic-gate   BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
51077c478bd9Sstevel@tonic-gate   "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]"
51087c478bd9Sstevel@tonic-gate   " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]",
51097c478bd9Sstevel@tonic-gate 
51107c478bd9Sstevel@tonic-gate   "Define the capabilities of your terminal. Use this command to"
51117c478bd9Sstevel@tonic-gate   " define escape sequences, if it is not vt100-compatible."
51127c478bd9Sstevel@tonic-gate   " You may use \\e for ESC and ^X for a control character."
51137c478bd9Sstevel@tonic-gate   " If no option is specified, the current settings are printed."
51147c478bd9Sstevel@tonic-gate };
51157c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
51167c478bd9Sstevel@tonic-gate 
51177c478bd9Sstevel@tonic-gate 
51187c478bd9Sstevel@tonic-gate /* testload */
51197c478bd9Sstevel@tonic-gate static int
testload_func(char * arg,int flags)51207c478bd9Sstevel@tonic-gate testload_func (char *arg, int flags)
51217c478bd9Sstevel@tonic-gate {
51227c478bd9Sstevel@tonic-gate   int i;
51237c478bd9Sstevel@tonic-gate 
51247c478bd9Sstevel@tonic-gate   kernel_type = KERNEL_TYPE_NONE;
51257c478bd9Sstevel@tonic-gate 
51267c478bd9Sstevel@tonic-gate   if (! grub_open (arg))
51277c478bd9Sstevel@tonic-gate     return 1;
51287c478bd9Sstevel@tonic-gate 
51297c478bd9Sstevel@tonic-gate   disk_read_hook = disk_read_print_func;
51307c478bd9Sstevel@tonic-gate 
51317c478bd9Sstevel@tonic-gate   /* Perform filesystem test on the specified file.  */
51327c478bd9Sstevel@tonic-gate   /* Read whole file first. */
51337c478bd9Sstevel@tonic-gate   grub_printf ("Whole file: ");
51347c478bd9Sstevel@tonic-gate 
51357c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x100000), -1);
51367c478bd9Sstevel@tonic-gate 
51377c478bd9Sstevel@tonic-gate   /* Now compare two sections of the file read differently.  */
51387c478bd9Sstevel@tonic-gate 
51397c478bd9Sstevel@tonic-gate   for (i = 0; i < 0x10ac0; i++)
51407c478bd9Sstevel@tonic-gate     {
51417c478bd9Sstevel@tonic-gate       *((unsigned char *) RAW_ADDR (0x200000 + i)) = 0;
51427c478bd9Sstevel@tonic-gate       *((unsigned char *) RAW_ADDR (0x300000 + i)) = 1;
51437c478bd9Sstevel@tonic-gate     }
51447c478bd9Sstevel@tonic-gate 
51457c478bd9Sstevel@tonic-gate   /* First partial read.  */
51467c478bd9Sstevel@tonic-gate   grub_printf ("\nPartial read 1: ");
51477c478bd9Sstevel@tonic-gate 
51487c478bd9Sstevel@tonic-gate   grub_seek (0);
51497c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200000), 0x7);
51507c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200007), 0x100);
51517c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200107), 0x10);
51527c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200117), 0x999);
51537c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200ab0), 0x10);
51547c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000);
51557c478bd9Sstevel@tonic-gate 
51567c478bd9Sstevel@tonic-gate   /* Second partial read.  */
51577c478bd9Sstevel@tonic-gate   grub_printf ("\nPartial read 2: ");
51587c478bd9Sstevel@tonic-gate 
51597c478bd9Sstevel@tonic-gate   grub_seek (0);
51607c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x300000), 0x10000);
51617c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310000), 0x10);
51627c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310010), 0x7);
51637c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310017), 0x10);
51647c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x310027), 0x999);
51657c478bd9Sstevel@tonic-gate   grub_read ((char *) RAW_ADDR (0x3109c0), 0x100);
51667c478bd9Sstevel@tonic-gate 
51677c478bd9Sstevel@tonic-gate   grub_printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
51687c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200000)),
51697c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200004)),
51707c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x200008)),
51717c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x20000c)));
51727c478bd9Sstevel@tonic-gate 
51737c478bd9Sstevel@tonic-gate   grub_printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n",
51747c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300000)),
51757c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300004)),
51767c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x300008)),
51777c478bd9Sstevel@tonic-gate 	       *((int *) RAW_ADDR (0x30000c)));
51787c478bd9Sstevel@tonic-gate 
51797c478bd9Sstevel@tonic-gate   for (i = 0; i < 0x10ac0; i++)
51807c478bd9Sstevel@tonic-gate     if (*((unsigned char *) RAW_ADDR (0x200000 + i))
51817c478bd9Sstevel@tonic-gate 	!= *((unsigned char *) RAW_ADDR (0x300000 + i)))
51827c478bd9Sstevel@tonic-gate       break;
51837c478bd9Sstevel@tonic-gate 
51847c478bd9Sstevel@tonic-gate   grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos);
51857c478bd9Sstevel@tonic-gate   disk_read_hook = 0;
51867c478bd9Sstevel@tonic-gate   grub_close ();
51877c478bd9Sstevel@tonic-gate   return 0;
51887c478bd9Sstevel@tonic-gate }
51897c478bd9Sstevel@tonic-gate 
51907c478bd9Sstevel@tonic-gate static struct builtin builtin_testload =
51917c478bd9Sstevel@tonic-gate {
51927c478bd9Sstevel@tonic-gate   "testload",
51937c478bd9Sstevel@tonic-gate   testload_func,
51947c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE,
51957c478bd9Sstevel@tonic-gate   "testload FILE",
51967c478bd9Sstevel@tonic-gate   "Read the entire contents of FILE in several different ways and"
51977c478bd9Sstevel@tonic-gate   " compares them, to test the filesystem code. The output is somewhat"
51987c478bd9Sstevel@tonic-gate   " cryptic, but if no errors are reported and the final `i=X,"
51997c478bd9Sstevel@tonic-gate   " filepos=Y' reading has X and Y equal, then it is definitely"
52007c478bd9Sstevel@tonic-gate   " consistent, and very likely works correctly subject to a"
52017c478bd9Sstevel@tonic-gate   " consistent offset error. If this test succeeds, then a good next"
52027c478bd9Sstevel@tonic-gate   " step is to try loading a kernel."
52037c478bd9Sstevel@tonic-gate };
52047c478bd9Sstevel@tonic-gate 
52057c478bd9Sstevel@tonic-gate 
52067c478bd9Sstevel@tonic-gate /* testvbe MODE */
52077c478bd9Sstevel@tonic-gate static int
testvbe_func(char * arg,int flags)52087c478bd9Sstevel@tonic-gate testvbe_func (char *arg, int flags)
52097c478bd9Sstevel@tonic-gate {
52107c478bd9Sstevel@tonic-gate   int mode_number;
52117c478bd9Sstevel@tonic-gate   struct vbe_controller controller;
52127c478bd9Sstevel@tonic-gate   struct vbe_mode mode;
52137c478bd9Sstevel@tonic-gate 
52147c478bd9Sstevel@tonic-gate   if (! *arg)
52157c478bd9Sstevel@tonic-gate     {
52167c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
52177c478bd9Sstevel@tonic-gate       return 1;
52187c478bd9Sstevel@tonic-gate     }
52197c478bd9Sstevel@tonic-gate 
52207c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &mode_number))
52217c478bd9Sstevel@tonic-gate     return 1;
52227c478bd9Sstevel@tonic-gate 
52237c478bd9Sstevel@tonic-gate   /* Preset `VBE2'.  */
52247c478bd9Sstevel@tonic-gate   grub_memmove (controller.signature, "VBE2", 4);
52257c478bd9Sstevel@tonic-gate 
52267c478bd9Sstevel@tonic-gate   /* Detect VBE BIOS.  */
52277c478bd9Sstevel@tonic-gate   if (get_vbe_controller_info (&controller) != 0x004F)
52287c478bd9Sstevel@tonic-gate     {
52297c478bd9Sstevel@tonic-gate       grub_printf (" VBE BIOS is not present.\n");
52307c478bd9Sstevel@tonic-gate       return 0;
52317c478bd9Sstevel@tonic-gate     }
52327c478bd9Sstevel@tonic-gate 
52337c478bd9Sstevel@tonic-gate   if (controller.version < 0x0200)
52347c478bd9Sstevel@tonic-gate     {
52357c478bd9Sstevel@tonic-gate       grub_printf (" VBE version %d.%d is not supported.\n",
52367c478bd9Sstevel@tonic-gate 		   (int) (controller.version >> 8),
52377c478bd9Sstevel@tonic-gate 		   (int) (controller.version & 0xFF));
52387c478bd9Sstevel@tonic-gate       return 0;
52397c478bd9Sstevel@tonic-gate     }
52407c478bd9Sstevel@tonic-gate 
52417c478bd9Sstevel@tonic-gate   if (get_vbe_mode_info (mode_number, &mode) != 0x004F
52427c478bd9Sstevel@tonic-gate       || (mode.mode_attributes & 0x0091) != 0x0091)
52437c478bd9Sstevel@tonic-gate     {
52447c478bd9Sstevel@tonic-gate       grub_printf (" Mode 0x%x is not supported.\n", mode_number);
52457c478bd9Sstevel@tonic-gate       return 0;
52467c478bd9Sstevel@tonic-gate     }
52477c478bd9Sstevel@tonic-gate 
52487c478bd9Sstevel@tonic-gate   /* Now trip to the graphics mode.  */
52497c478bd9Sstevel@tonic-gate   if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
52507c478bd9Sstevel@tonic-gate     {
52517c478bd9Sstevel@tonic-gate       grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
52527c478bd9Sstevel@tonic-gate       return 0;
52537c478bd9Sstevel@tonic-gate     }
52547c478bd9Sstevel@tonic-gate 
52557c478bd9Sstevel@tonic-gate   /* Draw something on the screen...  */
52567c478bd9Sstevel@tonic-gate   {
52577c478bd9Sstevel@tonic-gate     unsigned char *base_buf = (unsigned char *) mode.phys_base;
52587c478bd9Sstevel@tonic-gate     int scanline = controller.version >= 0x0300
52597c478bd9Sstevel@tonic-gate       ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline;
52607c478bd9Sstevel@tonic-gate     /* FIXME: this assumes that any depth is a modulo of 8.  */
52617c478bd9Sstevel@tonic-gate     int bpp = mode.bits_per_pixel / 8;
52627c478bd9Sstevel@tonic-gate     int width = mode.x_resolution;
52637c478bd9Sstevel@tonic-gate     int height = mode.y_resolution;
52647c478bd9Sstevel@tonic-gate     int x, y;
52657c478bd9Sstevel@tonic-gate     unsigned color = 0;
52667c478bd9Sstevel@tonic-gate 
52677c478bd9Sstevel@tonic-gate     /* Iterate drawing on the screen, until the user hits any key.  */
52687c478bd9Sstevel@tonic-gate     while (checkkey () == -1)
52697c478bd9Sstevel@tonic-gate       {
52707c478bd9Sstevel@tonic-gate 	for (y = 0; y < height; y++)
52717c478bd9Sstevel@tonic-gate 	  {
52727c478bd9Sstevel@tonic-gate 	    unsigned char *line_buf = base_buf + scanline * y;
52737c478bd9Sstevel@tonic-gate 
52747c478bd9Sstevel@tonic-gate 	    for (x = 0; x < width; x++)
52757c478bd9Sstevel@tonic-gate 	      {
52767c478bd9Sstevel@tonic-gate 		unsigned char *buf = line_buf + bpp * x;
52777c478bd9Sstevel@tonic-gate 		int i;
52787c478bd9Sstevel@tonic-gate 
52797c478bd9Sstevel@tonic-gate 		for (i = 0; i < bpp; i++, buf++)
52807c478bd9Sstevel@tonic-gate 		  *buf = (color >> (i * 8)) & 0xff;
52817c478bd9Sstevel@tonic-gate 	      }
52827c478bd9Sstevel@tonic-gate 
52837c478bd9Sstevel@tonic-gate 	    color++;
52847c478bd9Sstevel@tonic-gate 	  }
52857c478bd9Sstevel@tonic-gate       }
52867c478bd9Sstevel@tonic-gate 
52877c478bd9Sstevel@tonic-gate     /* Discard the input.  */
52887c478bd9Sstevel@tonic-gate     getkey ();
52897c478bd9Sstevel@tonic-gate   }
52907c478bd9Sstevel@tonic-gate 
52917c478bd9Sstevel@tonic-gate   /* Back to the default text mode.  */
52927c478bd9Sstevel@tonic-gate   if (set_vbe_mode (0x03) != 0x004F)
52937c478bd9Sstevel@tonic-gate     {
52947c478bd9Sstevel@tonic-gate       /* Why?!  */
52957c478bd9Sstevel@tonic-gate       grub_reboot ();
52967c478bd9Sstevel@tonic-gate     }
52977c478bd9Sstevel@tonic-gate 
52987c478bd9Sstevel@tonic-gate   return 0;
52997c478bd9Sstevel@tonic-gate }
53007c478bd9Sstevel@tonic-gate 
53017c478bd9Sstevel@tonic-gate static struct builtin builtin_testvbe =
53027c478bd9Sstevel@tonic-gate {
53037c478bd9Sstevel@tonic-gate   "testvbe",
53047c478bd9Sstevel@tonic-gate   testvbe_func,
53057c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
53067c478bd9Sstevel@tonic-gate   "testvbe MODE",
53077c478bd9Sstevel@tonic-gate   "Test the VBE mode MODE. Hit any key to return."
53087c478bd9Sstevel@tonic-gate };
53097c478bd9Sstevel@tonic-gate 
53107c478bd9Sstevel@tonic-gate 
53117c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
53127c478bd9Sstevel@tonic-gate /* tftpserver */
53137c478bd9Sstevel@tonic-gate static int
tftpserver_func(char * arg,int flags)53147c478bd9Sstevel@tonic-gate tftpserver_func (char *arg, int flags)
53157c478bd9Sstevel@tonic-gate {
53167c478bd9Sstevel@tonic-gate   if (! *arg || ! ifconfig (0, 0, 0, arg))
53177c478bd9Sstevel@tonic-gate     {
53187c478bd9Sstevel@tonic-gate       errnum = ERR_BAD_ARGUMENT;
53197c478bd9Sstevel@tonic-gate       return 1;
53207c478bd9Sstevel@tonic-gate     }
53217c478bd9Sstevel@tonic-gate 
53227c478bd9Sstevel@tonic-gate   print_network_configuration ();
53237c478bd9Sstevel@tonic-gate   return 0;
53247c478bd9Sstevel@tonic-gate }
53257c478bd9Sstevel@tonic-gate 
53267c478bd9Sstevel@tonic-gate static struct builtin builtin_tftpserver =
53277c478bd9Sstevel@tonic-gate {
53287c478bd9Sstevel@tonic-gate   "tftpserver",
53297c478bd9Sstevel@tonic-gate   tftpserver_func,
53307c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
53317c478bd9Sstevel@tonic-gate   "tftpserver IPADDR",
53327c478bd9Sstevel@tonic-gate   "Override the TFTP server address."
53337c478bd9Sstevel@tonic-gate };
53347c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
53357c478bd9Sstevel@tonic-gate 
53367c478bd9Sstevel@tonic-gate 
53377c478bd9Sstevel@tonic-gate /* timeout */
53387c478bd9Sstevel@tonic-gate static int
timeout_func(char * arg,int flags)53397c478bd9Sstevel@tonic-gate timeout_func (char *arg, int flags)
53407c478bd9Sstevel@tonic-gate {
53417c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, &grub_timeout))
53427c478bd9Sstevel@tonic-gate     return 1;
53437c478bd9Sstevel@tonic-gate 
53447c478bd9Sstevel@tonic-gate   return 0;
53457c478bd9Sstevel@tonic-gate }
53467c478bd9Sstevel@tonic-gate 
53477c478bd9Sstevel@tonic-gate static struct builtin builtin_timeout =
53487c478bd9Sstevel@tonic-gate {
53497c478bd9Sstevel@tonic-gate   "timeout",
53507c478bd9Sstevel@tonic-gate   timeout_func,
53517c478bd9Sstevel@tonic-gate   BUILTIN_MENU,
53527c478bd9Sstevel@tonic-gate #if 0
53537c478bd9Sstevel@tonic-gate   "timeout SEC",
53547c478bd9Sstevel@tonic-gate   "Set a timeout, in SEC seconds, before automatically booting the"
53557c478bd9Sstevel@tonic-gate   " default entry (normally the first entry defined)."
53567c478bd9Sstevel@tonic-gate #endif
53577c478bd9Sstevel@tonic-gate };
53587c478bd9Sstevel@tonic-gate 
53597c478bd9Sstevel@tonic-gate 
53607c478bd9Sstevel@tonic-gate /* title */
53617c478bd9Sstevel@tonic-gate static int
title_func(char * arg,int flags)53627c478bd9Sstevel@tonic-gate title_func (char *arg, int flags)
53637c478bd9Sstevel@tonic-gate {
53647c478bd9Sstevel@tonic-gate   /* This function is not actually used at least currently.  */
53657c478bd9Sstevel@tonic-gate   return 0;
53667c478bd9Sstevel@tonic-gate }
53677c478bd9Sstevel@tonic-gate 
53687c478bd9Sstevel@tonic-gate static struct builtin builtin_title =
53697c478bd9Sstevel@tonic-gate {
53707c478bd9Sstevel@tonic-gate   "title",
53717c478bd9Sstevel@tonic-gate   title_func,
53727c478bd9Sstevel@tonic-gate   BUILTIN_TITLE,
53737c478bd9Sstevel@tonic-gate #if 0
53747c478bd9Sstevel@tonic-gate   "title [NAME ...]",
53757c478bd9Sstevel@tonic-gate   "Start a new boot entry, and set its name to the contents of the"
53767c478bd9Sstevel@tonic-gate   " rest of the line, starting with the first non-space character."
53777c478bd9Sstevel@tonic-gate #endif
53787c478bd9Sstevel@tonic-gate };
53797c478bd9Sstevel@tonic-gate 
53807c478bd9Sstevel@tonic-gate 
53817c478bd9Sstevel@tonic-gate /* unhide */
53827c478bd9Sstevel@tonic-gate static int
unhide_func(char * arg,int flags)53837c478bd9Sstevel@tonic-gate unhide_func (char *arg, int flags)
53847c478bd9Sstevel@tonic-gate {
53857c478bd9Sstevel@tonic-gate   if (! set_device (arg))
53867c478bd9Sstevel@tonic-gate     return 1;
53877c478bd9Sstevel@tonic-gate 
53887c478bd9Sstevel@tonic-gate   if (! set_partition_hidden_flag (0))
53897c478bd9Sstevel@tonic-gate     return 1;
53907c478bd9Sstevel@tonic-gate 
53917c478bd9Sstevel@tonic-gate   return 0;
53927c478bd9Sstevel@tonic-gate }
53937c478bd9Sstevel@tonic-gate 
53947c478bd9Sstevel@tonic-gate static struct builtin builtin_unhide =
53957c478bd9Sstevel@tonic-gate {
53967c478bd9Sstevel@tonic-gate   "unhide",
53977c478bd9Sstevel@tonic-gate   unhide_func,
53987c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
53997c478bd9Sstevel@tonic-gate   "unhide PARTITION",
54007c478bd9Sstevel@tonic-gate   "Unhide PARTITION by clearing the \"hidden\" bit in its"
54017c478bd9Sstevel@tonic-gate   " partition type code."
54027c478bd9Sstevel@tonic-gate };
54037c478bd9Sstevel@tonic-gate 
54047c478bd9Sstevel@tonic-gate 
54057c478bd9Sstevel@tonic-gate /* uppermem */
54067c478bd9Sstevel@tonic-gate static int
uppermem_func(char * arg,int flags)54077c478bd9Sstevel@tonic-gate uppermem_func (char *arg, int flags)
54087c478bd9Sstevel@tonic-gate {
54097c478bd9Sstevel@tonic-gate   if (! safe_parse_maxint (&arg, (int *) &mbi.mem_upper))
54107c478bd9Sstevel@tonic-gate     return 1;
54117c478bd9Sstevel@tonic-gate 
54127c478bd9Sstevel@tonic-gate   mbi.flags &= ~MB_INFO_MEM_MAP;
54137c478bd9Sstevel@tonic-gate   return 0;
54147c478bd9Sstevel@tonic-gate }
54157c478bd9Sstevel@tonic-gate 
54167c478bd9Sstevel@tonic-gate static struct builtin builtin_uppermem =
54177c478bd9Sstevel@tonic-gate {
54187c478bd9Sstevel@tonic-gate   "uppermem",
54197c478bd9Sstevel@tonic-gate   uppermem_func,
54207c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
54217c478bd9Sstevel@tonic-gate   "uppermem KBYTES",
54227c478bd9Sstevel@tonic-gate   "Force GRUB to assume that only KBYTES kilobytes of upper memory are"
54237c478bd9Sstevel@tonic-gate   " installed.  Any system address range maps are discarded."
54247c478bd9Sstevel@tonic-gate };
54257c478bd9Sstevel@tonic-gate 
54267c478bd9Sstevel@tonic-gate 
54277c478bd9Sstevel@tonic-gate /* vbeprobe */
54287c478bd9Sstevel@tonic-gate static int
vbeprobe_func(char * arg,int flags)54297c478bd9Sstevel@tonic-gate vbeprobe_func (char *arg, int flags)
54307c478bd9Sstevel@tonic-gate {
54317c478bd9Sstevel@tonic-gate   struct vbe_controller controller;
54327c478bd9Sstevel@tonic-gate   unsigned short *mode_list;
54337c478bd9Sstevel@tonic-gate   int mode_number = -1;
54347c478bd9Sstevel@tonic-gate 
54357c478bd9Sstevel@tonic-gate   auto unsigned long vbe_far_ptr_to_linear (unsigned long);
54367c478bd9Sstevel@tonic-gate 
54377c478bd9Sstevel@tonic-gate   unsigned long vbe_far_ptr_to_linear (unsigned long ptr)
54387c478bd9Sstevel@tonic-gate     {
54397c478bd9Sstevel@tonic-gate       unsigned short seg = (ptr >> 16);
54407c478bd9Sstevel@tonic-gate       unsigned short off = (ptr & 0xFFFF);
54417c478bd9Sstevel@tonic-gate 
54427c478bd9Sstevel@tonic-gate       return (seg << 4) + off;
54437c478bd9Sstevel@tonic-gate     }
54447c478bd9Sstevel@tonic-gate 
54457c478bd9Sstevel@tonic-gate   if (*arg)
54467c478bd9Sstevel@tonic-gate     {
54477c478bd9Sstevel@tonic-gate       if (! safe_parse_maxint (&arg, &mode_number))
54487c478bd9Sstevel@tonic-gate 	return 1;
54497c478bd9Sstevel@tonic-gate     }
54507c478bd9Sstevel@tonic-gate 
54517c478bd9Sstevel@tonic-gate   /* Set the signature to `VBE2', to obtain VBE 3.0 information.  */
54527c478bd9Sstevel@tonic-gate   grub_memmove (controller.signature, "VBE2", 4);
54537c478bd9Sstevel@tonic-gate 
54547c478bd9Sstevel@tonic-gate   if (get_vbe_controller_info (&controller) != 0x004F)
54557c478bd9Sstevel@tonic-gate     {
54567c478bd9Sstevel@tonic-gate       grub_printf (" VBE BIOS is not present.\n");
54577c478bd9Sstevel@tonic-gate       return 0;
54587c478bd9Sstevel@tonic-gate     }
54597c478bd9Sstevel@tonic-gate 
54607c478bd9Sstevel@tonic-gate   /* Check the version.  */
54617c478bd9Sstevel@tonic-gate   if (controller.version < 0x0200)
54627c478bd9Sstevel@tonic-gate     {
54637c478bd9Sstevel@tonic-gate       grub_printf (" VBE version %d.%d is not supported.\n",
54647c478bd9Sstevel@tonic-gate 		   (int) (controller.version >> 8),
54657c478bd9Sstevel@tonic-gate 		   (int) (controller.version & 0xFF));
54667c478bd9Sstevel@tonic-gate       return 0;
54677c478bd9Sstevel@tonic-gate     }
54687c478bd9Sstevel@tonic-gate 
54697c478bd9Sstevel@tonic-gate   /* Print some information.  */
54707c478bd9Sstevel@tonic-gate   grub_printf (" VBE version %d.%d\n",
54717c478bd9Sstevel@tonic-gate 	       (int) (controller.version >> 8),
54727c478bd9Sstevel@tonic-gate 	       (int) (controller.version & 0xFF));
54737c478bd9Sstevel@tonic-gate 
54747c478bd9Sstevel@tonic-gate   /* Iterate probing modes.  */
54757c478bd9Sstevel@tonic-gate   for (mode_list
54767c478bd9Sstevel@tonic-gate 	 = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode);
54777c478bd9Sstevel@tonic-gate        *mode_list != 0xFFFF;
54787c478bd9Sstevel@tonic-gate        mode_list++)
54797c478bd9Sstevel@tonic-gate     {
54807c478bd9Sstevel@tonic-gate       struct vbe_mode mode;
54817c478bd9Sstevel@tonic-gate 
54827c478bd9Sstevel@tonic-gate       if (get_vbe_mode_info (*mode_list, &mode) != 0x004F)
54837c478bd9Sstevel@tonic-gate 	continue;
54847c478bd9Sstevel@tonic-gate 
54857c478bd9Sstevel@tonic-gate       /* Skip this, if this is not supported or linear frame buffer
54867c478bd9Sstevel@tonic-gate 	 mode is not support.  */
54877c478bd9Sstevel@tonic-gate       if ((mode.mode_attributes & 0x0081) != 0x0081)
54887c478bd9Sstevel@tonic-gate 	continue;
54897c478bd9Sstevel@tonic-gate 
54907c478bd9Sstevel@tonic-gate       if (mode_number == -1 || mode_number == *mode_list)
54917c478bd9Sstevel@tonic-gate 	{
54927c478bd9Sstevel@tonic-gate 	  char *model;
54937c478bd9Sstevel@tonic-gate 	  switch (mode.memory_model)
54947c478bd9Sstevel@tonic-gate 	    {
54957c478bd9Sstevel@tonic-gate 	    case 0x00: model = "Text"; break;
54967c478bd9Sstevel@tonic-gate 	    case 0x01: model = "CGA graphics"; break;
54977c478bd9Sstevel@tonic-gate 	    case 0x02: model = "Hercules graphics"; break;
54987c478bd9Sstevel@tonic-gate 	    case 0x03: model = "Planar"; break;
54997c478bd9Sstevel@tonic-gate 	    case 0x04: model = "Packed pixel"; break;
55007c478bd9Sstevel@tonic-gate 	    case 0x05: model = "Non-chain 4, 256 color"; break;
55017c478bd9Sstevel@tonic-gate 	    case 0x06: model = "Direct Color"; break;
55027c478bd9Sstevel@tonic-gate 	    case 0x07: model = "YUV"; break;
55037c478bd9Sstevel@tonic-gate 	    default: model = "Unknown"; break;
55047c478bd9Sstevel@tonic-gate 	    }
55057c478bd9Sstevel@tonic-gate 
55067c478bd9Sstevel@tonic-gate 	  grub_printf ("  0x%x: %s, %ux%ux%u\n",
55077c478bd9Sstevel@tonic-gate 		       (unsigned) *mode_list,
55087c478bd9Sstevel@tonic-gate 		       model,
55097c478bd9Sstevel@tonic-gate 		       (unsigned) mode.x_resolution,
55107c478bd9Sstevel@tonic-gate 		       (unsigned) mode.y_resolution,
55117c478bd9Sstevel@tonic-gate 		       (unsigned) mode.bits_per_pixel);
55127c478bd9Sstevel@tonic-gate 
55137c478bd9Sstevel@tonic-gate 	  if (mode_number != -1)
55147c478bd9Sstevel@tonic-gate 	    break;
55157c478bd9Sstevel@tonic-gate 	}
55167c478bd9Sstevel@tonic-gate     }
55177c478bd9Sstevel@tonic-gate 
55187c478bd9Sstevel@tonic-gate   if (mode_number != -1 && mode_number != *mode_list)
55197c478bd9Sstevel@tonic-gate     grub_printf ("  Mode 0x%x is not found or supported.\n", mode_number);
55207c478bd9Sstevel@tonic-gate 
55217c478bd9Sstevel@tonic-gate   return 0;
55227c478bd9Sstevel@tonic-gate }
55237c478bd9Sstevel@tonic-gate 
55247c478bd9Sstevel@tonic-gate static struct builtin builtin_vbeprobe =
55257c478bd9Sstevel@tonic-gate {
55267c478bd9Sstevel@tonic-gate   "vbeprobe",
55277c478bd9Sstevel@tonic-gate   vbeprobe_func,
55287c478bd9Sstevel@tonic-gate   BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
55297c478bd9Sstevel@tonic-gate   "vbeprobe [MODE]",
55307c478bd9Sstevel@tonic-gate   "Probe VBE information. If the mode number MODE is specified, show only"
55317c478bd9Sstevel@tonic-gate   " the information about only the mode."
55327c478bd9Sstevel@tonic-gate };
5533a5602e1bSKeith M Wesolowski 
5534a5602e1bSKeith M Wesolowski static int
variable_func(char * arg,int flags)5535a5602e1bSKeith M Wesolowski variable_func(char *arg, int flags)
5536a5602e1bSKeith M Wesolowski {
5537a5602e1bSKeith M Wesolowski 	char name[EV_NAMELEN];
5538a5602e1bSKeith M Wesolowski 	char *val;
5539a5602e1bSKeith M Wesolowski 	int err;
5540a5602e1bSKeith M Wesolowski 
5541a5602e1bSKeith M Wesolowski 	if (*arg == '\0') {
5542a5602e1bSKeith M Wesolowski 		dump_variables();
5543a5602e1bSKeith M Wesolowski 		return (0);
5544a5602e1bSKeith M Wesolowski 	}
5545a5602e1bSKeith M Wesolowski 
5546a5602e1bSKeith M Wesolowski 	if ((val = grub_strchr(arg, ' ')) != NULL) {
5547a5602e1bSKeith M Wesolowski 		if (val - arg >= sizeof (name)) {
5548a5602e1bSKeith M Wesolowski 			errnum = ERR_WONT_FIT;
5549a5602e1bSKeith M Wesolowski 			return (1);
5550a5602e1bSKeith M Wesolowski 		}
5551a5602e1bSKeith M Wesolowski 		(void) grub_memcpy(name, arg, (val - arg));
5552a5602e1bSKeith M Wesolowski 		name[val - arg] = '\0';
5553a5602e1bSKeith M Wesolowski 		val = skip_to(0, arg);
5554a5602e1bSKeith M Wesolowski 	} else {
5555a5602e1bSKeith M Wesolowski 		if (grub_strlen(arg) >= sizeof (name)) {
5556a5602e1bSKeith M Wesolowski 			errnum = ERR_WONT_FIT;
5557a5602e1bSKeith M Wesolowski 			return (1);
5558a5602e1bSKeith M Wesolowski 		}
5559a5602e1bSKeith M Wesolowski 		(void) grub_strcpy(name, arg);
5560a5602e1bSKeith M Wesolowski 	}
5561a5602e1bSKeith M Wesolowski 
5562a5602e1bSKeith M Wesolowski 	if ((err = set_variable(name, val)) != 0) {
5563a5602e1bSKeith M Wesolowski 		errnum = err;
5564a5602e1bSKeith M Wesolowski 		return (1);
5565a5602e1bSKeith M Wesolowski 	}
5566a5602e1bSKeith M Wesolowski 
5567a5602e1bSKeith M Wesolowski 	return (0);
5568a5602e1bSKeith M Wesolowski }
5569a5602e1bSKeith M Wesolowski 
5570a5602e1bSKeith M Wesolowski static struct builtin builtin_variable =
5571a5602e1bSKeith M Wesolowski {
5572a5602e1bSKeith M Wesolowski   "variable",
5573a5602e1bSKeith M Wesolowski   variable_func,
5574a5602e1bSKeith M Wesolowski   BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_SCRIPT | BUILTIN_HELP_LIST,
5575a5602e1bSKeith M Wesolowski   "variable NAME [VALUE]",
5576a5602e1bSKeith M Wesolowski   "Set the variable NAME to VALUE, or to the empty string if no value is"
5577a5602e1bSKeith M Wesolowski   " given. NAME must contain no spaces. There is no quoting mechanism"
5578a5602e1bSKeith M Wesolowski   " and nested variable references are not allowed. Variable values may"
5579a5602e1bSKeith M Wesolowski   " be substituted into the kernel$ and module$ commands using ${NAME}."
5580a5602e1bSKeith M Wesolowski };
55817c478bd9Sstevel@tonic-gate 
55827c478bd9Sstevel@tonic-gate 
55837c478bd9Sstevel@tonic-gate /* The table of builtin commands. Sorted in dictionary order.  */
55847c478bd9Sstevel@tonic-gate struct builtin *builtin_table[] =
55857c478bd9Sstevel@tonic-gate {
55867c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
55877c478bd9Sstevel@tonic-gate   &builtin_background,
55887c478bd9Sstevel@tonic-gate #endif
55897c478bd9Sstevel@tonic-gate   &builtin_blocklist,
55907c478bd9Sstevel@tonic-gate   &builtin_boot,
5591b1b8ab34Slling   &builtin_bootfs,
55927c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
55937c478bd9Sstevel@tonic-gate   &builtin_bootp,
55947c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
55957c478bd9Sstevel@tonic-gate   &builtin_cat,
55967c478bd9Sstevel@tonic-gate   &builtin_chainloader,
55977c478bd9Sstevel@tonic-gate   &builtin_clear,
55987c478bd9Sstevel@tonic-gate   &builtin_cmp,
55997c478bd9Sstevel@tonic-gate   &builtin_color,
56007c478bd9Sstevel@tonic-gate   &builtin_configfile,
56017c478bd9Sstevel@tonic-gate   &builtin_debug,
56027c478bd9Sstevel@tonic-gate   &builtin_default,
56037c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
56047c478bd9Sstevel@tonic-gate   &builtin_device,
56057c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
56067c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
56077c478bd9Sstevel@tonic-gate   &builtin_dhcp,
56087c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
56097c478bd9Sstevel@tonic-gate   &builtin_displayapm,
56107c478bd9Sstevel@tonic-gate   &builtin_displaymem,
56117c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
56127c478bd9Sstevel@tonic-gate   &builtin_dump,
56137c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
56147c478bd9Sstevel@tonic-gate   &builtin_embed,
56157c478bd9Sstevel@tonic-gate   &builtin_fallback,
56167c478bd9Sstevel@tonic-gate   &builtin_find,
5617eb2bd662Svikram   &builtin_findroot,
56187c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
56197c478bd9Sstevel@tonic-gate   &builtin_foreground,
56207c478bd9Sstevel@tonic-gate #endif
56217c478bd9Sstevel@tonic-gate   &builtin_fstest,
56227c478bd9Sstevel@tonic-gate   &builtin_geometry,
56237c478bd9Sstevel@tonic-gate   &builtin_halt,
56247c478bd9Sstevel@tonic-gate   &builtin_help,
56257c478bd9Sstevel@tonic-gate   &builtin_hiddenmenu,
56267c478bd9Sstevel@tonic-gate   &builtin_hide,
56277c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
56287c478bd9Sstevel@tonic-gate   &builtin_ifconfig,
56297c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
56307c478bd9Sstevel@tonic-gate   &builtin_impsprobe,
56317c478bd9Sstevel@tonic-gate   &builtin_initrd,
56327c478bd9Sstevel@tonic-gate   &builtin_install,
56337c478bd9Sstevel@tonic-gate   &builtin_ioprobe,
56347c478bd9Sstevel@tonic-gate   &builtin_kernel,
5635ae115bc7Smrj   &builtin_kernel_dollar,
56367c478bd9Sstevel@tonic-gate   &builtin_lock,
56377c478bd9Sstevel@tonic-gate   &builtin_makeactive,
56387c478bd9Sstevel@tonic-gate   &builtin_map,
56397c478bd9Sstevel@tonic-gate #ifdef USE_MD5_PASSWORDS
56407c478bd9Sstevel@tonic-gate   &builtin_md5crypt,
56417c478bd9Sstevel@tonic-gate #endif /* USE_MD5_PASSWORDS */
5642342440ecSPrasad Singamsetty   &builtin_min_mem64,
56437c478bd9Sstevel@tonic-gate   &builtin_module,
5644ae115bc7Smrj   &builtin_module_dollar,
56457c478bd9Sstevel@tonic-gate   &builtin_modulenounzip,
56467c478bd9Sstevel@tonic-gate   &builtin_pager,
56477c478bd9Sstevel@tonic-gate   &builtin_partnew,
56487c478bd9Sstevel@tonic-gate   &builtin_parttype,
56497c478bd9Sstevel@tonic-gate   &builtin_password,
56507c478bd9Sstevel@tonic-gate   &builtin_pause,
56517c478bd9Sstevel@tonic-gate #if defined(RPC_DEBUG) && defined(SUPPORT_NETBOOT)
56527c478bd9Sstevel@tonic-gate   &builtin_portmap,
56537c478bd9Sstevel@tonic-gate #endif /* RPC_DEBUG && SUPPORT_NETBOOT */
56547c478bd9Sstevel@tonic-gate #ifdef GRUB_UTIL
56557c478bd9Sstevel@tonic-gate   &builtin_quit,
56567c478bd9Sstevel@tonic-gate #endif /* GRUB_UTIL */
56577c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
56587c478bd9Sstevel@tonic-gate   &builtin_rarp,
56597c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
56607c478bd9Sstevel@tonic-gate   &builtin_read,
56617c478bd9Sstevel@tonic-gate   &builtin_reboot,
56627c478bd9Sstevel@tonic-gate   &builtin_root,
56637c478bd9Sstevel@tonic-gate   &builtin_rootnoverify,
56647c478bd9Sstevel@tonic-gate   &builtin_savedefault,
56657c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
56667c478bd9Sstevel@tonic-gate   &builtin_serial,
56677c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
56687c478bd9Sstevel@tonic-gate   &builtin_setkey,
56697c478bd9Sstevel@tonic-gate   &builtin_setup,
56707c478bd9Sstevel@tonic-gate #ifdef SUPPORT_GRAPHICS
56717c478bd9Sstevel@tonic-gate   &builtin_splashimage,
56727c478bd9Sstevel@tonic-gate #endif /* SUPPORT_GRAPHICS */
56737c478bd9Sstevel@tonic-gate #if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES) || defined(SUPPORT_GRAPHICS)
56747c478bd9Sstevel@tonic-gate   &builtin_terminal,
56757c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL || SUPPORT_HERCULES || SUPPORT_GRAPHICS */
56767c478bd9Sstevel@tonic-gate #ifdef SUPPORT_SERIAL
56777c478bd9Sstevel@tonic-gate   &builtin_terminfo,
56787c478bd9Sstevel@tonic-gate #endif /* SUPPORT_SERIAL */
56797c478bd9Sstevel@tonic-gate   &builtin_testload,
56807c478bd9Sstevel@tonic-gate   &builtin_testvbe,
56817c478bd9Sstevel@tonic-gate #ifdef SUPPORT_NETBOOT
56827c478bd9Sstevel@tonic-gate   &builtin_tftpserver,
56837c478bd9Sstevel@tonic-gate #endif /* SUPPORT_NETBOOT */
56847c478bd9Sstevel@tonic-gate   &builtin_timeout,
56857c478bd9Sstevel@tonic-gate   &builtin_title,
56867c478bd9Sstevel@tonic-gate   &builtin_unhide,
56877c478bd9Sstevel@tonic-gate   &builtin_uppermem,
5688a5602e1bSKeith M Wesolowski   &builtin_variable,
56897c478bd9Sstevel@tonic-gate   &builtin_vbeprobe,
56901fac5a60Ssetje   &builtin_verbose,
56917c478bd9Sstevel@tonic-gate   0
56927c478bd9Sstevel@tonic-gate };
5693