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