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