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