legacy_parse.c 31 KB

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