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