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