~hamo/ubuntu/precise/grub2/grub2.hi_res

« back to all changes in this revision

Viewing changes to grub-core/lib/legacy_parse.c

  • Committer: Bazaar Package Importer
  • Author(s): Colin Watson, Colin Watson, Evan Broder, Mario Limonciello
  • Date: 2010-11-24 13:59:55 UTC
  • mfrom: (1.17.6 upstream) (17.6.15 experimental)
  • Revision ID: james.westby@ubuntu.com-20101124135955-r6ii5sepayr7jt53
Tags: 1.99~20101124-1ubuntu1
[ Colin Watson ]
* Resynchronise with Debian experimental.  Remaining changes:
  - Adjust for default Ubuntu boot options ("quiet splash").
  - Default to hiding the menu; holding down Shift at boot will show it.
  - Set a monochromatic theme for Ubuntu.
  - Apply Ubuntu GRUB Legacy changes to legacy update-grub script: title,
    recovery mode, quiet option, tweak how memtest86+ is displayed, and
    use UUIDs where appropriate.
  - Fix backslash-escaping in merge_debconf_into_conf.
  - Remove "GNU/Linux" from default distributor string.
  - Add crashkernel= options if kdump and makedumpfile are available.
  - If other operating systems are installed, then automatically unhide
    the menu.  Otherwise, if GRUB_HIDDEN_TIMEOUT is 0, then use keystatus
    if available to check whether Shift is pressed.  If it is, show the
    menu, otherwise boot immediately.  If keystatus is not available, then
    fall back to a short delay interruptible with Escape.
  - Allow Shift to interrupt 'sleep --interruptible'.
  - Don't display introductory message about line editing unless we're
    actually offering a shell prompt.  Don't clear the screen just before
    booting if we never drew the menu in the first place.
  - Remove some verbose messages printed before reading the configuration
    file.
  - Suppress progress messages as the kernel and initrd load for
    non-recovery kernel menu entries.
  - Change prepare_grub_to_access_device to handle filesystems
    loop-mounted on file images.
  - Ignore devices loop-mounted from files in 10_linux.
  - Show the boot menu if the previous boot failed, that is if it failed
    to get to the end of one of the normal runlevels.
  - Don't generate /boot/grub/device.map during grub-install or
    grub-mkconfig by default.
  - Adjust upgrade version checks for Ubuntu.
  - Don't display "GRUB loading" unless Shift is held down.
  - Adjust versions of grub-doc and grub-legacy-doc conflicts to tolerate
    our backport of the grub-doc split.
  - Fix LVM/RAID probing in the absence of /boot/grub/device.map.
  - Look for .mo files in /usr/share/locale-langpack as well, in
    preference.
  - Make sure GRUB_TIMEOUT isn't quoted unnecessarily.
  - Probe all devices in 'grub-probe --target=drive' if
    /boot/grub/device.map is missing.
  - Build-depend on qemu-kvm rather than qemu-system for grub-pc tests.
  - Use qemu rather than qemu-system-i386.
  - Program vesafb on BIOS systems rather than efifb.
  - Add a grub-rescue-efi-amd64 package containing a rescue CD-ROM image
    for EFI-AMD64.
  - On Wubi, don't ask for an install device, but just update wubildr
    using the diverted grub-install.
  - When embedding the core image in a post-MBR gap, check for and avoid
    sectors matching any of a list of known signatures.
  - Disable video_bochs and video_cirrus on PC BIOS systems, as probing
    PCI space seems to break on some systems.
* Downgrade "ACPI shutdown failed" error to a debug message, since it can
  cause spurious test failures.

[ Evan Broder ]
* Enable lua from grub-extras.
* Incorporate the bitop library into lua.
* Add enum_pci function to grub module in lua.
* Switch back to gfxpayload=keep by default, unless the video hardware
  is known to not support it.

[ Mario Limonciello ]
* Built part_msdos and vfat into bootx64.efi (LP: #677758)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 1999,2000,2001,2002,2003,2004,2010  Free Software Foundation, Inc.
 
4
 *
 
5
 *  GRUB is free software: you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation, either version 3 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  GRUB is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
 
17
 */
 
18
 
 
19
#include <grub/types.h>
 
20
#include <grub/misc.h>
 
21
#include <grub/mm.h>
 
22
#include <grub/err.h>
 
23
#include <grub/legacy_parse.h>
 
24
#include <grub/i386/pc/vesa_modes_table.h>
 
25
 
 
26
struct legacy_command
 
27
{
 
28
  const char *name;
 
29
  const char *map;
 
30
  const char *suffix;
 
31
  unsigned suffixarg;
 
32
  unsigned argc;
 
33
  enum arg_type {
 
34
    TYPE_VERBATIM,
 
35
    TYPE_FORCE_OPTION,
 
36
    TYPE_NOAPM_OPTION,
 
37
    TYPE_TYPE_OR_NOMEM_OPTION,
 
38
    TYPE_OPTION,
 
39
    TYPE_FILE,
 
40
    TYPE_FILE_NO_CONSUME,
 
41
    TYPE_PARTITION,
 
42
    TYPE_BOOL,
 
43
    TYPE_INT,
 
44
    TYPE_REST_VERBATIM,
 
45
    TYPE_VBE_MODE
 
46
  } argt[4];
 
47
  enum {
 
48
    FLAG_IGNORE_REST        =  0x001,
 
49
    FLAG_FALLBACK_AVAILABLE =  0x004,
 
50
    FLAG_FALLBACK           =  0x008,
 
51
    FLAG_COLOR_INVERT       =  0x010,
 
52
    FLAG_NO_MENUENTRY       =  0x020,
 
53
    FLAG_MENUENTRY_ONLY     =  0x040,
 
54
    FLAG_TERMINAL           =  0x080,
 
55
    FLAG_TITLE              =  0x100,
 
56
  } flags;
 
57
  const char *shortdesc;
 
58
  const char *longdesc;
 
59
};
 
60
 
 
61
struct legacy_command legacy_commands[] =
 
62
  {
 
63
    {"blocklist", "blocklist '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE",
 
64
     "Print the blocklist notation of the file FILE."},
 
65
    {"boot", "boot\n", NULL, 0, 0, {}, 0, 0,
 
66
     "Boot the OS/chain-loader which has been loaded."},
 
67
    /* FIXME: bootp unsupported.  */
 
68
    {"cat", "cat '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE",
 
69
     "Print the contents of the file FILE."},
 
70
    {"chainloader", "chainloader %s '%s'\n", NULL, 0,
 
71
     2, {TYPE_FORCE_OPTION, TYPE_FILE}, 0, "[--force] FILE",
 
72
     "Load the chain-loader FILE. If --force is specified, then load it"
 
73
     " forcibly, whether the boot loader signature is present or not."},
 
74
    {"cmp", "cmp '%s' '%s'\n", NULL, 0,
 
75
     2, {TYPE_FILE, TYPE_FILE}, FLAG_IGNORE_REST, "FILE1 FILE2",
 
76
     "Compare the file FILE1 with the FILE2 and inform the different values"
 
77
     " if any."},
 
78
    {"color", "set color_normal='%s'; set color_highlight='%s'\n", NULL, 0, 
 
79
     2, {TYPE_VERBATIM, TYPE_VERBATIM},
 
80
     FLAG_IGNORE_REST | FLAG_FALLBACK_AVAILABLE, "NORMAL [HIGHLIGHT]",
 
81
     "Change the menu colors. The color NORMAL is used for most"
 
82
     " lines in the menu, and the color HIGHLIGHT is used to highlight the"
 
83
     " line where the cursor points. If you omit HIGHLIGHT, then the"
 
84
     " inverted color of NORMAL is used for the highlighted line."
 
85
     " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
 
86
     " A symbolic color name must be one of these: black, blue, green,"
 
87
     " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
 
88
     " light-green, light-cyan, light-red, light-magenta, yellow and white."
 
89
     " But only the first eight names can be used for BG. You can prefix"
 
90
     " \"blink-\" to FG if you want a blinking foreground color."},
 
91
    {"color", "set color_normal='%s'; set color_highlight='%s'\n", NULL, 0,
 
92
     1, {TYPE_VERBATIM},
 
93
     FLAG_IGNORE_REST | FLAG_FALLBACK | FLAG_COLOR_INVERT, NULL, NULL},
 
94
    {"configfile", "legacy_configfile '%s'\n", NULL, 0, 1, {TYPE_FILE},
 
95
     0, "FILE", "Load FILE as the configuration file."},
 
96
    {"debug",
 
97
     "if [ -z \"$debug\" ]; then set debug=all; else set debug=; fi\n", NULL, 0,
 
98
     0, {}, 0, 0, "Turn on/off the debug mode."},
 
99
    {"default",
 
100
     "set default='%s'; if [ x\"$default\" = xsaved ]; then load_env; "
 
101
     "set default=\"$saved_entry\"; fi\n", NULL, 0, 1, {TYPE_VERBATIM}, 0, 
 
102
     "[NUM | `saved']",
 
103
     "Set the default entry to entry number NUM (if not specified, it is"
 
104
     " 0, the first entry) or the entry number saved by savedefault."},
 
105
    /* FIXME: dhcp unsupported.  */
 
106
    {"displayapm", "lsapm\n", NULL, 0, 0, {}, 0, 0,
 
107
     "Display APM BIOS information."},
 
108
    {"displaymem", "lsmmap\n", NULL, 0, 0, {}, 0, 0, 
 
109
     "Display what GRUB thinks the system address space map of the"
 
110
     " machine is, including all regions of physical RAM installed."},
 
111
    /* NOTE: embed unsupported.  */
 
112
    {"fallback", "set fallback='%s'\n", NULL, 0,
 
113
     1, {TYPE_VERBATIM}, 0, "NUM...",
 
114
     "Go into unattended boot mode: if the default boot entry has any"
 
115
     " errors, instead of waiting for the user to do anything, it"
 
116
     " immediately starts over using the NUM entry (same numbering as the"
 
117
     " `default' command). This obviously won't help if the machine"
 
118
     " was rebooted by a kernel that GRUB loaded."},
 
119
    {"find", "search -sf '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILENAME",
 
120
     "Search for the filename FILENAME in all of partitions and print the list of"
 
121
     " the devices which contain the file."},
 
122
    /* FIXME: fstest unsupported.  */
 
123
    /* NOTE: The obsolete C/H/S geometry isn't shown anymore.  */
 
124
    {"geometry", "insmod regexp; ls -l (%s*)\n", NULL, 0, 1, {TYPE_VERBATIM}, 0, "DRIVE",
 
125
     "Print the information for a drive DRIVE. "},
 
126
    {"halt", "halt %s\n", NULL, 0, 1, {TYPE_NOAPM_OPTION}, 0, "[--no-apm]",
 
127
     "Halt your system. If APM is available on it, turn off the power using"
 
128
     " the APM BIOS, unless you specify the option `--no-apm'."},
 
129
    /* FIXME: help unsupported.  */    /* NUL_TERMINATE */
 
130
    {"hiddenmenu", NULL,
 
131
     "if sleep -i $timeout; then timeout=0; else timeout=-1; fi\n", 0,
 
132
     0, {}, 0, "", "Hide the menu."},
 
133
    {"hide", "parttool '%s' hidden+\n", NULL, 0, 1, {TYPE_PARTITION},
 
134
     0, "PARTITION",
 
135
     "Hide PARTITION by setting the \"hidden\" bit in"
 
136
     " its partition type code."},
 
137
    /* FIXME: ifconfig unsupported.  */
 
138
    /* FIXME: impsprobe unsupported.  */
 
139
    {"initrd", "legacy_initrd '%s' %s\n", NULL, 0, 2, {TYPE_FILE_NO_CONSUME,
 
140
                                                       TYPE_REST_VERBATIM}, 0,
 
141
     "FILE [ARG ...]",
 
142
     "Load an initial ramdisk FILE for a Linux format boot image and set the"
 
143
     " appropriate parameters in the Linux setup area in memory."},
 
144
    /* NOTE: install unsupported.  */
 
145
    /* FIXME: ioprobe unsupported.  */
 
146
    /* FIXME: really support --no-mem-option.  */
 
147
    {"kernel", "legacy_kernel %s %s '%s' %s\n", NULL, 0,
 
148
     4, {TYPE_TYPE_OR_NOMEM_OPTION, TYPE_TYPE_OR_NOMEM_OPTION,
 
149
         TYPE_FILE_NO_CONSUME, TYPE_REST_VERBATIM}, 0,
 
150
     "[--no-mem-option] [--type=TYPE] FILE [ARG ...]",
 
151
     "Attempt to load the primary boot image from FILE. The rest of the"
 
152
     " line is passed verbatim as the \"kernel command line\".  Any modules"
 
153
     " must be reloaded after using this command. The option --type is used"
 
154
     " to suggest what type of kernel to be loaded. TYPE must be either of"
 
155
     " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
 
156
     " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
 
157
     " Linux's mem option automatically."},
 
158
    {"lock", "if ! authenticate legacy; then return; fi", NULL, 0, 0, {}, 0,
 
159
     0, "Break a command execution unless the user is authenticated."},
 
160
    {"makeactive", "parttool \"$root\" boot+\n", NULL, 0, 0, {}, 0, 0,
 
161
     "Set the active partition on the root disk to GRUB's root device."
 
162
     " This command is limited to _primary_ PC partitions on a hard disk."},
 
163
    {"map", "drivemap '%s' '%s'\n", NULL, 0,
 
164
     2, {TYPE_PARTITION, TYPE_PARTITION},
 
165
     FLAG_IGNORE_REST, "TO_DRIVE FROM_DRIVE",
 
166
     "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
 
167
     " when you chain-load some operating systems, such as DOS, if such an"
 
168
     " OS resides at a non-first drive."},
 
169
    /* NOTE: md5crypt unsupported since GRUB has not enough entropy and this
 
170
       hash shouldn't be used anymore.  */
 
171
    {"module", "legacy_initrd '%s' %s\n", NULL, 0, 2, {TYPE_FILE_NO_CONSUME,
 
172
                                                       TYPE_REST_VERBATIM}, 0,
 
173
     "FILE [ARG ...]",
 
174
     "Load a boot module FILE for a Multiboot format boot image (no"
 
175
     " interpretation of the file contents is made, so users of this"
 
176
     " command must know what the kernel in question expects). The"
 
177
     " rest of the line is passed as the \"module command line\", like"
 
178
     " the `kernel' command."},
 
179
    {"modulenounzip", "legacy_initrd_nounzip '%s' %s\n", NULL, 0, 2,
 
180
     {TYPE_FILE_NO_CONSUME, TYPE_REST_VERBATIM}, 0,
 
181
     "FILE [ARG ...]",
 
182
     "The same as `module', except that automatic decompression is"
 
183
     " disabled."},
 
184
    {"pager", "set pager=%s; if [ \"$pager\" = 0 ]; then "
 
185
     " echo Internal pager is now off; else "
 
186
     "echo Internal pager is now on; fi\n", NULL, 0,
 
187
     1, {TYPE_BOOL}, FLAG_FALLBACK_AVAILABLE, "[FLAG]",
 
188
     "Toggle pager mode with no argument. If FLAG is given and its value"
 
189
     " is `on', turn on the mode. If FLAG is `off', turn off the mode."},
 
190
    {"pager", 
 
191
     "if [ \"$pager\" = 1 ]; then pager=0; echo Internal pager is now off;"
 
192
      "else pager=1; echo Internal pager is now on; fi\n", NULL, 0, 0, {},
 
193
     FLAG_FALLBACK, NULL, NULL},
 
194
    /* FIXME: partnew unsupported.  */
 
195
    {"parttype", "parttool '%s' type=%s\n", NULL, 0,
 
196
     2, {TYPE_PARTITION, TYPE_INT}, 0,
 
197
     "PART TYPE", "Change the type of the partition PART to TYPE."},
 
198
    {"password", "if [ \"$superusers\" = "" ]; then superusers=legacy; fi;\n"
 
199
     "legacy_password %s '%s'\n",
 
200
     "menuentry \"Superuser menu\" --users \"legacy\" { configfile '%s'; }\n",
 
201
     2, 3, {TYPE_OPTION, TYPE_VERBATIM, TYPE_FILE},
 
202
     FLAG_IGNORE_REST | FLAG_FALLBACK_AVAILABLE | FLAG_NO_MENUENTRY,
 
203
     "[--md5] PASSWD [FILE]",
 
204
     "If used in the first section of a menu file, disable all"
 
205
     " interactive editing control (menu entry editor and"
 
206
     " command line). If the password PASSWD is entered, it loads the"
 
207
     " FILE as a new config file and restarts the GRUB Stage 2. If you"
 
208
     " omit the argument FILE, then GRUB just unlocks privileged"
 
209
     " instructions.  You can also use it in the script section, in"
 
210
     " which case it will ask for the password, before continuing."
 
211
     " The option --md5 tells GRUB that PASSWD is encrypted with"
 
212
     " md5crypt."},
 
213
    {"password", "if [ \"$superusers\" = "" ]; then superusers=legacy; fi;\n"
 
214
     "legacy_password %s '%s'\n", NULL, 0, 2, {TYPE_OPTION, TYPE_VERBATIM},
 
215
     FLAG_IGNORE_REST | FLAG_FALLBACK | FLAG_NO_MENUENTRY, NULL, NULL},
 
216
    {"password", "if legacy_check_password %s '%s'; then configfile '%s'; "
 
217
     "else return; fi\n", NULL, 2, 3, {TYPE_OPTION, TYPE_VERBATIM, TYPE_FILE},
 
218
     FLAG_IGNORE_REST | FLAG_FALLBACK_AVAILABLE | FLAG_MENUENTRY_ONLY,
 
219
     NULL, NULL},
 
220
    {"password", "if ! legacy_check_password %s '%s'; then return fi;\n",
 
221
     NULL, 0, 2, {TYPE_OPTION, TYPE_VERBATIM},
 
222
     FLAG_IGNORE_REST | FLAG_FALLBACK | FLAG_MENUENTRY_ONLY, NULL, NULL},
 
223
    /* NOTE: GRUB2 has a design principle of not eternally waiting for user
 
224
       input. 60 seconds should be enough.
 
225
     */
 
226
    {"pause", "echo %s; if ! sleep -i 60; then return; fi\n", NULL, 0, 1,
 
227
     {TYPE_REST_VERBATIM}, 0,
 
228
     "[MESSAGE ...]", "Print MESSAGE, then wait until a key is pressed."},
 
229
    /* FIXME: rarp unsupported.  */
 
230
    {"read", "read_dword %s\n", NULL, 0, 1, {TYPE_INT}, 0, "ADDR",
 
231
     "Read a 32-bit value from memory at address ADDR and"
 
232
     " display it in hex format."},
 
233
    {"reboot", "reboot\n", NULL, 0, 0, {}, 0, 0, "Reboot your system."},
 
234
    {"root", "set root='%s'; set legacy_hdbias='%s'\n", NULL, 0,
 
235
     2, {TYPE_PARTITION, TYPE_INT}, FLAG_FALLBACK_AVAILABLE,
 
236
     "[DEVICE [HDBIAS]]",
 
237
     "Set the current \"root device\" to the device DEVICE, then"
 
238
     " attempt to mount it to get the partition size (for passing the"
 
239
     " partition descriptor in `ES:ESI', used by some chain-loaded"
 
240
     " bootloaders), the BSD drive-type (for booting BSD kernels using"
 
241
     " their native boot format), and correctly determine "
 
242
     " the PC partition where a BSD sub-partition is located. The"
 
243
     " optional HDBIAS parameter is a number to tell a BSD kernel"
 
244
     " how many BIOS drive numbers are on controllers before the current"
 
245
     " one. For example, if there is an IDE disk and a SCSI disk, and your"
 
246
     " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."},
 
247
    {"root", "echo \"$root\"\n", NULL, 0, 0, {}, FLAG_FALLBACK, NULL, NULL},
 
248
    {"rootnoverify", "set root='%s'; set legacy_hdbias='%s'\n", NULL, 0,
 
249
     2, {TYPE_PARTITION, TYPE_INT}, 0,
 
250
     "[DEVICE [HDBIAS]]",
 
251
     "Similar to `root', but don't attempt to mount the partition. This"
 
252
     " is useful for when an OS is outside of the area of the disk that"
 
253
     " GRUB can read, but setting the correct root device is still"
 
254
     " desired. Note that the items mentioned in `root' which"
 
255
     " derived from attempting the mount will NOT work correctly."},
 
256
    {"rootnoverify", "echo \"$root\"\n", NULL, 0,
 
257
     0, {}, FLAG_FALLBACK, NULL, NULL},
 
258
    /* FIXME: support saving NUM and fallback.  */
 
259
    {"savedefault", "saved_entry=${chosen}; save_env saved_entry\n", NULL, 0,
 
260
     0, {}, 0, "[NUM | `fallback']",
 
261
     "Save the current entry as the default boot entry if no argument is"
 
262
     " specified. If a number is specified, this number is saved. If"
 
263
     " `fallback' is used, next fallback entry is saved."},
 
264
    {"serial", "serial %s\n", NULL, 0, 1, {TYPE_REST_VERBATIM}, 0, 
 
265
     "[--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] "
 
266
     "[--parity=PARITY] [--stop=STOP] [--device=DEV]",
 
267
     "Initialize a serial device. UNIT is a digit that specifies which serial"
 
268
     " device is used (e.g. 0 == COM1). If you need to specify the port number,"
 
269
     " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
 
270
     " PARITY is the type of parity, which is one of `no', `odd' and `even'."
 
271
     " STOP is the length of stop bit(s). The option --device can be used only"
 
272
     " in the grub shell, which specifies the file name of a tty device. The"
 
273
     " default values are COM1, 9600, 8N1."},
 
274
    /* FIXME: setkey unsupported.  */    /* NUL_TERMINATE */
 
275
    /* NOTE: setup unsupported.  */
 
276
    /* FIXME: --no-echo, --no-edit, hercules unsupported.  */
 
277
    /* NOTE: both terminals are activated so --silent and --timeout
 
278
       are useless.  */
 
279
    {"terminal", NULL, NULL, 0, 0, {}, FLAG_TERMINAL | FLAG_IGNORE_REST,
 
280
     "[--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] "
 
281
     "[--silent] [console] [serial] [hercules]",
 
282
     "Select a terminal. When multiple terminals are specified, wait until"
 
283
     " you push any key to continue. If both console and serial are specified,"
 
284
     " the terminal to which you input a key first will be selected. If no"
 
285
     " argument is specified, print current setting. The option --dumb"
 
286
     " specifies that your terminal is dumb, otherwise, vt100-compatibility"
 
287
     " is assumed. If you specify --no-echo, input characters won't be echoed."
 
288
     " If you specify --no-edit, the BASH-like editing feature will be disabled."
 
289
     " If --timeout is present, this command will wait at most for SECS"
 
290
     " seconds. The option --lines specifies the maximum number of lines."
 
291
     " The option --silent is used to suppress messages."},
 
292
    /* FIXME: terminfo unsupported.  */    /* NUL_TERMINATE */
 
293
    {"testload", "cat '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE",
 
294
     "Read the entire contents of FILE in several different ways and"
 
295
     " compares them, to test the filesystem code. "
 
296
     " If this test succeeds, then a good next"
 
297
     " step is to try loading a kernel."},
 
298
    {"testvbe", "insmod vbe; videotest '%s'\n", NULL, 0, 1, {TYPE_VBE_MODE}, 0,
 
299
     "MODE", "Test the VBE mode MODE. Hit any key to return."},
 
300
    /* FIXME: tftpserver unsupported.  */
 
301
    {"timeout", "set timeout=%s\n", NULL, 0, 1, {TYPE_INT}, 0, "SEC",
 
302
     "Set a timeout, in SEC seconds, before automatically booting the"
 
303
     " default entry (normally the first entry defined)."},
 
304
    {"title", NULL, NULL, 0, 0, {}, FLAG_TITLE, "NAME ...",
 
305
     "Start a new boot entry, and set its name to the contents of the"
 
306
     " rest of the line, starting with the first non-space character."},
 
307
    {"unhide", "parttool '%s' hidden-\n", NULL, 0,
 
308
     1, {TYPE_PARTITION}, 0, "PARTITION",
 
309
     "Unhide PARTITION by clearing the \"hidden\" bit in its"
 
310
     " partition type code."},
 
311
    /* FIXME: uppermem unsupported.  */
 
312
    {"uuid", "search --set=root --fs-uuid '%s'\n", NULL, 0, 1, {TYPE_VERBATIM},
 
313
     0, "UUID", "Find root by UUID"},
 
314
    {"vbeprobe", "insmod vbe; videoinfo '%s'\n", NULL, 0, 1, {TYPE_VBE_MODE},
 
315
     FLAG_FALLBACK_AVAILABLE, "[MODE]",
 
316
     "Probe VBE information. If the mode number MODE is specified, show only"
 
317
     " the information about only the mode."},
 
318
    {"vbeprobe", "insmod vbe; videoinfo\n", NULL, 0, 0, {},
 
319
     FLAG_FALLBACK, NULL, NULL}
 
320
  };
 
321
 
 
322
char *
 
323
grub_legacy_escape (const char *in, grub_size_t len)
 
324
{
 
325
  const char *ptr;
 
326
  char *ret, *outptr;
 
327
  int overhead = 0;
 
328
  for (ptr = in; ptr < in + len && *ptr; ptr++)
 
329
    if (*ptr == '\'')
 
330
      overhead += 3;
 
331
  ret = grub_malloc (ptr - in + overhead + 1);
 
332
  if (!ret)
 
333
    return NULL;
 
334
  outptr = ret;
 
335
  for (ptr = in; ptr < in + len && *ptr; ptr++)
 
336
    {
 
337
      if (*ptr == '\'')
 
338
        {
 
339
          *outptr++ = '\'';
 
340
          *outptr++ = '\\';
 
341
          *outptr++ = '\'';
 
342
          *outptr++ = '\'';
 
343
          continue;
 
344
        }
 
345
      
 
346
      *outptr++ = *ptr;
 
347
    }
 
348
  *outptr++ = 0;
 
349
  return ret;
 
350
}
 
351
 
 
352
static char *
 
353
adjust_file (const char *in, grub_size_t len)
 
354
{
 
355
  const char *comma, *ptr, *rest;
 
356
  char *ret, *outptr;
 
357
  int overhead = 0;
 
358
  int part = -1, subpart = -1;
 
359
  if (in[0] != '(')
 
360
    return grub_legacy_escape (in, len);
 
361
  for (ptr = in + 1; ptr < in + len && *ptr && *ptr != ')'
 
362
         && *ptr != ','; ptr++)
 
363
    if (*ptr == '\'' || *ptr == '\\')
 
364
      overhead++;
 
365
  comma = ptr;
 
366
  if (*comma != ',')
 
367
    return grub_legacy_escape (in, len);
 
368
  part = grub_strtoull (comma + 1, (char **) &rest, 0);
 
369
  if (rest[0] == ',' && rest[1] >= 'a' && rest[1] <= 'z')
 
370
    {
 
371
      subpart = rest[1] - 'a';
 
372
      rest += 2;
 
373
    }
 
374
  for (ptr = rest; ptr < in + len && *ptr; ptr++)
 
375
    if (*ptr == '\'' || *ptr == '\\')
 
376
      overhead++;
 
377
 
 
378
  /* 35 is enough for any 2 numbers.  */
 
379
  ret = grub_malloc (ptr - in + overhead + 35);
 
380
  if (!ret)
 
381
    return NULL;
 
382
 
 
383
  outptr = ret;
 
384
  for (ptr = in; ptr < in + len && ptr <= comma; ptr++)
 
385
    {
 
386
      if (*ptr == '\'' || *ptr == '\\')
 
387
        *outptr++ = '\\';
 
388
      
 
389
      *outptr++ = *ptr;
 
390
    }
 
391
  if (subpart != -1)
 
392
    grub_snprintf (outptr, 35, "%d,%d", part + 1, subpart + 1);
 
393
  else
 
394
    grub_snprintf (outptr, 35, "%d", part + 1);
 
395
  while (*outptr)
 
396
    outptr++;
 
397
  for (ptr = rest; ptr < in + len; ptr++)
 
398
    {
 
399
      if (*ptr == '\'' || *ptr == '\\')
 
400
        *outptr++ = '\\';
 
401
      
 
402
      *outptr++ = *ptr;
 
403
    }
 
404
  *outptr = 0;
 
405
  return ret;
 
406
}
 
407
 
 
408
static int
 
409
check_option (const char *a, char *b, grub_size_t len)
 
410
{
 
411
  if (grub_strlen (b) != len)
 
412
    return 0;
 
413
  return grub_strncmp (a, b, len) == 0;
 
414
}
 
415
 
 
416
static int
 
417
is_option (enum arg_type opt, const char *curarg, grub_size_t len)
 
418
{
 
419
  switch (opt)
 
420
    {
 
421
    case TYPE_NOAPM_OPTION:
 
422
      return check_option (curarg, "--no-apm", len);
 
423
    case TYPE_FORCE_OPTION:
 
424
      return check_option (curarg, "--force", len);
 
425
    case TYPE_TYPE_OR_NOMEM_OPTION:
 
426
      return check_option (curarg, "--type=netbsd", len)
 
427
        || check_option (curarg, "--type=freebsd", len)
 
428
        || check_option (curarg, "--type=openbsd", len)
 
429
        || check_option (curarg, "--type=linux", len)
 
430
        || check_option (curarg, "--type=biglinux", len)
 
431
        || check_option (curarg, "--type=multiboot", len)
 
432
        || check_option (curarg, "--no-mem-option", len);
 
433
    case TYPE_OPTION:
 
434
      return (len >= 2 && curarg[0] == '-' && curarg[1] == '-');
 
435
    default:
 
436
      return 0;
 
437
    } 
 
438
}
 
439
 
 
440
char *
 
441
grub_legacy_parse (const char *buf, char **entryname, char **suffix)
 
442
{
 
443
  const char *ptr;
 
444
  const char *cmdname;
 
445
  unsigned i, cmdnum;
 
446
  char *args[ARRAY_SIZE (legacy_commands[0].argt)];
 
447
 
 
448
  *suffix = NULL;
 
449
 
 
450
  for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
 
451
  if (!*ptr || *ptr == '#')
 
452
    {
 
453
      char *ret;
 
454
      int len = grub_strlen (buf);
 
455
      ret = grub_malloc (len + 2);
 
456
      grub_memcpy (ret, buf, len);
 
457
      if (len && ret[len - 1] == '\n')
 
458
        ret[len] = 0;
 
459
      else
 
460
        {
 
461
          ret[len] = '\n';
 
462
          ret[len + 1] = 0;
 
463
        }
 
464
      return ret;
 
465
    }
 
466
 
 
467
  cmdname = ptr;
 
468
  for (ptr = buf; *ptr && !grub_isspace (*ptr) && *ptr != '='; ptr++);
 
469
 
 
470
  for (cmdnum = 0; cmdnum < ARRAY_SIZE (legacy_commands); cmdnum++)
 
471
    if (grub_strncmp (legacy_commands[cmdnum].name, cmdname, ptr - cmdname) == 0
 
472
        && legacy_commands[cmdnum].name[ptr - cmdname] == 0
 
473
        && (!(*entryname != NULL && (legacy_commands[cmdnum].flags
 
474
                                     & FLAG_NO_MENUENTRY)))
 
475
        && (!(*entryname == NULL && (legacy_commands[cmdnum].flags
 
476
                                     & FLAG_MENUENTRY_ONLY))))
 
477
      break;
 
478
  if (cmdnum == ARRAY_SIZE (legacy_commands))
 
479
    return grub_xasprintf ("# Unsupported legacy command: %s\n", buf);
 
480
 
 
481
  for (; grub_isspace (*ptr) || *ptr == '='; ptr++);
 
482
 
 
483
  if (legacy_commands[cmdnum].flags & FLAG_TITLE)
 
484
    {
 
485
      const char *ptr2;
 
486
      ptr2 = ptr + grub_strlen (ptr);
 
487
      while (ptr2 > ptr && grub_isspace (*(ptr2 - 1)))
 
488
        ptr2--;
 
489
      *entryname = grub_strndup (ptr, ptr2 - ptr);
 
490
      return NULL;
 
491
    }
 
492
 
 
493
  if (legacy_commands[cmdnum].flags & FLAG_TERMINAL)
 
494
    {
 
495
      int dumb = 0, lines = 24;
 
496
#ifdef TODO
 
497
      int no_echo = 0, no_edit = 0;
 
498
      int hercules = 0;
 
499
#endif
 
500
      int console = 0, serial = 0;
 
501
      /* Big enough for any possible resulting command. */
 
502
      char outbuf[256] = "";
 
503
      char *outptr;
 
504
      while (*ptr)
 
505
        {
 
506
          /*      "[--timeout=SECS] [--silent]"
 
507
                  " [console] [serial] [hercules]"*/
 
508
          if (grub_memcmp (ptr, "--dumb", sizeof ("--dumb") - 1) == 0)
 
509
            dumb = 1;
 
510
#ifdef TODO
 
511
          if (grub_memcmp (ptr, "--no-echo", sizeof ("--no-echo") - 1) == 0)
 
512
            no_echo = 1;
 
513
 
 
514
          if (grub_memcmp (ptr, "--no-edit", sizeof ("--no-edit") - 1) == 0)
 
515
            no_edit = 1;
 
516
#endif
 
517
          if (grub_memcmp (ptr, "--lines=", sizeof ("--lines=") - 1) == 0)
 
518
            {
 
519
              lines = grub_strtoul (ptr + sizeof ("--lines=") - 1, 0, 0);
 
520
              if (grub_errno)
 
521
                {
 
522
                  lines = 24;
 
523
                  grub_errno = GRUB_ERR_NONE;
 
524
                }
 
525
            }
 
526
 
 
527
          if (grub_memcmp (ptr, "console", sizeof ("console") - 1) == 0)
 
528
            console = 1;
 
529
 
 
530
          if (grub_memcmp (ptr, "serial", sizeof ("serial") - 1) == 0)
 
531
            serial = 1;
 
532
#ifdef TODO
 
533
          if (grub_memcmp (ptr, "hercules", sizeof ("hercules") - 1) == 0)
 
534
            hercules = 1;
 
535
#endif
 
536
          while (*ptr && !grub_isspace (*ptr))
 
537
            ptr++;
 
538
          while (*ptr && grub_isspace (*ptr))
 
539
            ptr++;
 
540
        }
 
541
 
 
542
      if (!console && !serial)
 
543
        return grub_strdup ("terminal_input; terminal_output; terminfo\n");
 
544
 
 
545
      grub_strcpy (outbuf, "terminal_input ");
 
546
      outptr = outbuf + grub_strlen (outbuf);
 
547
      if (serial)
 
548
        {
 
549
          grub_strcpy (outptr, "serial ");
 
550
          outptr += grub_strlen (outptr);
 
551
        }
 
552
      if (console)
 
553
        {
 
554
          grub_strcpy (outptr, "console ");
 
555
          outptr += grub_strlen (outptr);
 
556
        }
 
557
      grub_strcpy (outptr, "; terminal_output ");
 
558
      outptr += grub_strlen (outptr);
 
559
      if (serial)
 
560
        {
 
561
          grub_strcpy (outptr, "serial ");
 
562
          outptr += grub_strlen (outptr);
 
563
        }
 
564
      if (console)
 
565
        {
 
566
          grub_strcpy (outptr, "console ");
 
567
          outptr += grub_strlen (outptr);
 
568
        }
 
569
      grub_strcpy (outptr, "; ");
 
570
      outptr += grub_strlen (outptr);
 
571
      if (serial)
 
572
        {
 
573
          grub_snprintf (outptr, outbuf + sizeof (outbuf) - outptr,
 
574
                         "terminfo serial -g 80x%d %s; ",
 
575
                         lines, dumb ? "dumb" : "vt100");
 
576
          outptr += grub_strlen (outptr);
 
577
        }
 
578
 
 
579
      grub_strcpy (outptr, "\n");
 
580
 
 
581
      return grub_strdup (outbuf);
 
582
    }
 
583
 
 
584
  grub_memset (args, 0, sizeof (args));
 
585
 
 
586
  {
 
587
    int hold_arg = 0;
 
588
    const char *curarg = NULL; 
 
589
    for (i = 0; i < legacy_commands[cmdnum].argc; i++)
 
590
      {
 
591
        grub_size_t curarglen;
 
592
        if (hold_arg)
 
593
          {
 
594
            ptr = curarg;
 
595
            hold_arg = 0;
 
596
          }
 
597
        for (; grub_isspace (*ptr); ptr++);
 
598
        curarg = ptr;
 
599
        if (!*curarg)
 
600
          break;
 
601
        for (; *ptr && !grub_isspace (*ptr); ptr++);
 
602
        if (i != legacy_commands[cmdnum].argc - 1
 
603
            || (legacy_commands[cmdnum].flags & FLAG_IGNORE_REST))
 
604
          curarglen = ptr - curarg;
 
605
        else
 
606
          {
 
607
            curarglen = grub_strlen (curarg);
 
608
            while (curarglen > 0 && grub_isspace (curarg[curarglen - 1]))
 
609
              curarglen--;
 
610
          }
 
611
        if (*ptr)
 
612
          ptr++;
 
613
        switch (legacy_commands[cmdnum].argt[i])
 
614
          {
 
615
          case TYPE_FILE_NO_CONSUME:
 
616
            hold_arg = 1;
 
617
          case TYPE_PARTITION:
 
618
          case TYPE_FILE:
 
619
            args[i] = adjust_file (curarg, curarglen);
 
620
            break;
 
621
 
 
622
          case TYPE_REST_VERBATIM:
 
623
            {
 
624
              char *outptr, *outptr0;
 
625
              int overhead = 3;
 
626
              ptr = curarg;
 
627
              while (*ptr)
 
628
                {
 
629
                  for (; *ptr && grub_isspace (*ptr); ptr++);
 
630
                  for (; *ptr && !grub_isspace (*ptr); ptr++)
 
631
                    if (*ptr == '\'')
 
632
                      overhead += 3;
 
633
                  if (*ptr)
 
634
                    ptr++;
 
635
                  overhead += 3;
 
636
                }
 
637
                
 
638
              outptr0 = args[i] = grub_malloc (overhead + (ptr - curarg));
 
639
              if (!outptr0)
 
640
                return NULL;
 
641
              ptr = curarg;
 
642
              outptr = outptr0;
 
643
              while (*ptr)
 
644
                {
 
645
                  for (; *ptr && grub_isspace (*ptr); ptr++);
 
646
                  if (outptr != outptr0)
 
647
                    *outptr++ = ' ';
 
648
                  *outptr++ = '\'';
 
649
                  for (; *ptr && !grub_isspace (*ptr); ptr++)
 
650
                    {
 
651
                      if (*ptr == '\'')
 
652
                        {
 
653
                          *outptr++ = '\'';
 
654
                          *outptr++ = '\\';
 
655
                          *outptr++ = '\'';
 
656
                          *outptr++ = '\'';
 
657
                        }
 
658
                      else
 
659
                        *outptr++ = *ptr;
 
660
                    }
 
661
                  *outptr++ = '\'';
 
662
                  if (*ptr)
 
663
                    ptr++;
 
664
                }
 
665
              *outptr++ = 0;
 
666
            }
 
667
            break;
 
668
 
 
669
          case TYPE_VERBATIM:
 
670
            args[i] = grub_legacy_escape (curarg, curarglen);
 
671
            break;
 
672
          case TYPE_FORCE_OPTION:
 
673
          case TYPE_NOAPM_OPTION:
 
674
          case TYPE_TYPE_OR_NOMEM_OPTION:
 
675
          case TYPE_OPTION:
 
676
            if (is_option (legacy_commands[cmdnum].argt[i], curarg, curarglen))
 
677
              {
 
678
                args[i] = grub_strndup (curarg, curarglen);
 
679
                break;
 
680
              }
 
681
            args[i] = grub_strdup ("");
 
682
            hold_arg = 1;
 
683
            break;
 
684
          case TYPE_INT:
 
685
            {
 
686
              const char *brk;
 
687
              int base = 10;
 
688
              brk = curarg;
 
689
              if (brk[0] == '0' && brk[1] == 'x')
 
690
                base = 16;
 
691
              else if (brk[0] == '0')
 
692
                base = 8;
 
693
              for (; *brk && brk < curarg + curarglen; brk++)
 
694
                {
 
695
                  if (base == 8 &&  (*brk == '8' || *brk == '9'))
 
696
                    break;
 
697
                  if (grub_isdigit (*brk))
 
698
                    continue;
 
699
                  if (base != 16)
 
700
                    break;
 
701
                  if (!(*brk >= 'a' && *brk <= 'f')
 
702
                      && !(*brk >= 'A' && *brk <= 'F'))
 
703
                    break;
 
704
                }
 
705
              if (brk == curarg)
 
706
                args[i] = grub_strdup ("0");
 
707
              else
 
708
                args[i] = grub_strndup (curarg, brk - curarg);
 
709
            }
 
710
            break;
 
711
          case TYPE_VBE_MODE:
 
712
            {
 
713
              unsigned mod;
 
714
              struct grub_vesa_mode_table_entry *modedesc;
 
715
 
 
716
              mod = grub_strtoul (curarg, 0, 0);
 
717
              if (grub_errno)
 
718
                {
 
719
                  mod = 0;
 
720
                  grub_errno = GRUB_ERR_NONE;
 
721
                }
 
722
              if (mod < GRUB_VESA_MODE_TABLE_START
 
723
                  || mod > GRUB_VESA_MODE_TABLE_END)
 
724
                {
 
725
                  args[i] = grub_strdup ("auto");
 
726
                  break;
 
727
                }
 
728
              modedesc = &grub_vesa_mode_table[mod - GRUB_VESA_MODE_TABLE_START];
 
729
              if (!modedesc->width)
 
730
                {
 
731
                  args[i] = grub_strdup ("auto");
 
732
                  break;
 
733
                }
 
734
              args[i] = grub_xasprintf ("%ux%ux%u",
 
735
                                        modedesc->width, modedesc->height,
 
736
                                        modedesc->depth);
 
737
              break;
 
738
            }
 
739
          case TYPE_BOOL:
 
740
            if (curarglen == 2 && curarg[0] == 'o' && curarg[1] == 'n')
 
741
              args[i] = grub_strdup ("1");
 
742
            else
 
743
              args[i] = grub_strdup ("0");
 
744
            break;
 
745
          }
 
746
      }
 
747
  }
 
748
 
 
749
  while (legacy_commands[cmdnum].argc > 0
 
750
         && args[legacy_commands[cmdnum].argc - 1] == NULL
 
751
         && (legacy_commands[cmdnum].flags & FLAG_FALLBACK_AVAILABLE)
 
752
         && args[legacy_commands[cmdnum + 1].argc] == NULL)
 
753
    cmdnum++;
 
754
 
 
755
  for (; i < legacy_commands[cmdnum].argc; i++)
 
756
    switch (legacy_commands[cmdnum].argt[i])
 
757
      {
 
758
      case TYPE_FILE_NO_CONSUME:
 
759
      case TYPE_PARTITION:
 
760
      case TYPE_FILE:
 
761
      case TYPE_REST_VERBATIM:
 
762
      case TYPE_VERBATIM:
 
763
      case TYPE_FORCE_OPTION:
 
764
      case TYPE_NOAPM_OPTION:
 
765
      case TYPE_TYPE_OR_NOMEM_OPTION:
 
766
      case TYPE_OPTION: 
 
767
        args[i] = grub_strdup ("");
 
768
        break;
 
769
      case TYPE_BOOL:
 
770
      case TYPE_INT:
 
771
        args[i] = grub_strdup ("0");
 
772
        break;
 
773
      case TYPE_VBE_MODE:    
 
774
        args[i] = grub_strdup ("auto");
 
775
        break;
 
776
      }
 
777
 
 
778
  if (legacy_commands[cmdnum].flags & FLAG_COLOR_INVERT)
 
779
    {
 
780
      char *corig = args[legacy_commands[cmdnum].argc - 1];
 
781
      char *slash = grub_strchr (corig, '/');
 
782
      char *invert;
 
783
      grub_size_t len;
 
784
 
 
785
      len = grub_strlen (corig);
 
786
      if (!slash)
 
787
        {
 
788
          grub_error (GRUB_ERR_BAD_ARGUMENT, "bad color specification %s",
 
789
                      args[0]);
 
790
          return NULL;
 
791
        }
 
792
      invert = grub_malloc (len + 1);
 
793
      if (!invert)
 
794
        return NULL;
 
795
      grub_memcpy (invert, slash + 1, len - (slash - corig) - 1);
 
796
      invert[len - (slash - args[0]) - 1] = '/'; 
 
797
      grub_memcpy (invert + len - (slash - corig), corig, slash - corig);
 
798
      invert[len] = 0;
 
799
      args[legacy_commands[cmdnum].argc] = invert;
 
800
    }
 
801
 
 
802
  if (legacy_commands[cmdnum].suffix)
 
803
    {
 
804
      *suffix = grub_xasprintf (legacy_commands[cmdnum].suffix,
 
805
                                args[legacy_commands[cmdnum].suffixarg]);
 
806
      if (*suffix)
 
807
        return NULL;
 
808
    }
 
809
 
 
810
  {
 
811
    char *ret = grub_xasprintf (legacy_commands[cmdnum].map, args[0], args[1],
 
812
                                args[2], args[3]);
 
813
    grub_free (args[0]);
 
814
    grub_free (args[1]);
 
815
    grub_free (args[2]);
 
816
    grub_free (args[3]);
 
817
    return ret;
 
818
  }
 
819
}