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