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