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