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