main.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. /* main.c - the normal mode main routine */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB 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 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB 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 GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <grub/kernel.h>
  20. #include <grub/normal.h>
  21. #include <grub/dl.h>
  22. #include <grub/misc.h>
  23. #include <grub/file.h>
  24. #include <grub/mm.h>
  25. #include <grub/term.h>
  26. #include <grub/env.h>
  27. #include <grub/parser.h>
  28. #include <grub/reader.h>
  29. #include <grub/menu_viewer.h>
  30. #include <grub/auth.h>
  31. #include <grub/i18n.h>
  32. #include <grub/charset.h>
  33. #include <grub/script_sh.h>
  34. #include <grub/bufio.h>
  35. GRUB_MOD_LICENSE ("GPLv3+");
  36. #define GRUB_DEFAULT_HISTORY_SIZE 50
  37. static int nested_level = 0;
  38. int grub_normal_exit_level = 0;
  39. void
  40. grub_normal_free_menu (grub_menu_t menu)
  41. {
  42. grub_menu_entry_t entry = menu->entry_list;
  43. while (entry)
  44. {
  45. grub_menu_entry_t next_entry = entry->next;
  46. grub_size_t i;
  47. if (entry->classes)
  48. {
  49. struct grub_menu_entry_class *class;
  50. for (class = entry->classes; class; class = class->next)
  51. grub_free (class->name);
  52. grub_free (entry->classes);
  53. }
  54. if (entry->args)
  55. {
  56. for (i = 0; entry->args[i]; i++)
  57. grub_free (entry->args[i]);
  58. grub_free (entry->args);
  59. }
  60. grub_free ((void *) entry->id);
  61. grub_free ((void *) entry->users);
  62. grub_free ((void *) entry->title);
  63. grub_free ((void *) entry->sourcecode);
  64. grub_free (entry);
  65. entry = next_entry;
  66. }
  67. grub_free (menu);
  68. grub_env_unset_menu ();
  69. }
  70. /* Helper for read_config_file. */
  71. static grub_err_t
  72. read_config_file_getline (char **line, int cont __attribute__ ((unused)),
  73. void *data)
  74. {
  75. grub_file_t file = data;
  76. while (1)
  77. {
  78. char *buf;
  79. *line = buf = grub_file_getline (file);
  80. if (! buf)
  81. return grub_errno;
  82. if (buf[0] == '#')
  83. grub_free (*line);
  84. else
  85. break;
  86. }
  87. return GRUB_ERR_NONE;
  88. }
  89. static grub_menu_t
  90. read_config_file (const char *config)
  91. {
  92. grub_file_t rawfile, file;
  93. char *old_file = 0, *old_dir = 0;
  94. char *config_dir, *ptr = 0;
  95. const char *ctmp;
  96. grub_menu_t newmenu;
  97. newmenu = grub_env_get_menu ();
  98. if (! newmenu)
  99. {
  100. newmenu = grub_zalloc (sizeof (*newmenu));
  101. if (! newmenu)
  102. return 0;
  103. grub_env_set_menu (newmenu);
  104. }
  105. /* Try to open the config file. */
  106. rawfile = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
  107. if (! rawfile)
  108. return 0;
  109. file = grub_bufio_open (rawfile, 0);
  110. if (! file)
  111. {
  112. grub_file_close (rawfile);
  113. return 0;
  114. }
  115. ctmp = grub_env_get ("config_file");
  116. if (ctmp)
  117. old_file = grub_strdup (ctmp);
  118. ctmp = grub_env_get ("config_directory");
  119. if (ctmp)
  120. old_dir = grub_strdup (ctmp);
  121. if (*config == '(')
  122. {
  123. grub_env_set ("config_file", config);
  124. config_dir = grub_strdup (config);
  125. }
  126. else
  127. {
  128. /* $root is guranteed to be defined, otherwise open above would fail */
  129. config_dir = grub_xasprintf ("(%s)%s", grub_env_get ("root"), config);
  130. if (config_dir)
  131. grub_env_set ("config_file", config_dir);
  132. }
  133. if (config_dir)
  134. {
  135. ptr = grub_strrchr (config_dir, '/');
  136. if (ptr)
  137. *ptr = 0;
  138. grub_env_set ("config_directory", config_dir);
  139. grub_free (config_dir);
  140. }
  141. grub_env_export ("config_file");
  142. grub_env_export ("config_directory");
  143. while (1)
  144. {
  145. char *line;
  146. /* Print an error, if any. */
  147. grub_print_error ();
  148. grub_errno = GRUB_ERR_NONE;
  149. if ((read_config_file_getline (&line, 0, file)) || (! line))
  150. break;
  151. grub_normal_parse_line (line, read_config_file_getline, file);
  152. grub_free (line);
  153. }
  154. if (old_file)
  155. grub_env_set ("config_file", old_file);
  156. else
  157. grub_env_unset ("config_file");
  158. if (old_dir)
  159. grub_env_set ("config_directory", old_dir);
  160. else
  161. grub_env_unset ("config_directory");
  162. grub_free (old_file);
  163. grub_free (old_dir);
  164. grub_file_close (file);
  165. return newmenu;
  166. }
  167. /* Initialize the screen. */
  168. void
  169. grub_normal_init_page (struct grub_term_output *term,
  170. int y)
  171. {
  172. grub_ssize_t msg_len;
  173. int posx;
  174. char *msg_formatted;
  175. grub_uint32_t *unicode_msg;
  176. grub_uint32_t *last_position;
  177. grub_term_cls (term);
  178. msg_formatted = grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION);
  179. if (!msg_formatted)
  180. return;
  181. msg_len = grub_utf8_to_ucs4_alloc (msg_formatted,
  182. &unicode_msg, &last_position);
  183. grub_free (msg_formatted);
  184. if (msg_len < 0)
  185. {
  186. return;
  187. }
  188. posx = grub_getstringwidth (unicode_msg, last_position, term);
  189. posx = ((int) grub_term_width (term) - posx) / 2;
  190. if (posx < 0)
  191. posx = 0;
  192. grub_term_gotoxy (term, (struct grub_term_coordinate) { posx, y });
  193. grub_print_ucs4 (unicode_msg, last_position, 0, 0, term);
  194. grub_putcode ('\n', term);
  195. grub_putcode ('\n', term);
  196. grub_free (unicode_msg);
  197. }
  198. static void
  199. read_lists (const char *val)
  200. {
  201. if (! grub_no_modules)
  202. {
  203. read_command_list (val);
  204. read_fs_list (val);
  205. read_crypto_list (val);
  206. read_terminal_list (val);
  207. }
  208. grub_gettext_reread_prefix (val);
  209. }
  210. static char *
  211. read_lists_hook (struct grub_env_var *var __attribute__ ((unused)),
  212. const char *val)
  213. {
  214. read_lists (val);
  215. return val ? grub_strdup (val) : NULL;
  216. }
  217. /* Read the config file CONFIG and execute the menu interface or
  218. the command line interface if BATCH is false. */
  219. void
  220. grub_normal_execute (const char *config, int nested, int batch)
  221. {
  222. grub_menu_t menu = 0;
  223. const char *prefix;
  224. if (! nested)
  225. {
  226. prefix = grub_env_get ("prefix");
  227. read_lists (prefix);
  228. grub_register_variable_hook ("prefix", NULL, read_lists_hook);
  229. }
  230. grub_boot_time ("Executing config file");
  231. if (config)
  232. {
  233. menu = read_config_file (config);
  234. /* Ignore any error. */
  235. grub_errno = GRUB_ERR_NONE;
  236. }
  237. grub_boot_time ("Executed config file");
  238. if (! batch)
  239. {
  240. if (menu && menu->size)
  241. {
  242. grub_boot_time ("Entering menu");
  243. grub_show_menu (menu, nested, 0);
  244. if (nested)
  245. grub_normal_free_menu (menu);
  246. }
  247. }
  248. }
  249. /* This starts the normal mode. */
  250. void
  251. grub_enter_normal_mode (const char *config)
  252. {
  253. grub_boot_time ("Entering normal mode");
  254. nested_level++;
  255. grub_normal_execute (config, 0, 0);
  256. grub_boot_time ("Entering shell");
  257. grub_cmdline_run (0, 1);
  258. nested_level--;
  259. if (grub_normal_exit_level)
  260. grub_normal_exit_level--;
  261. grub_boot_time ("Exiting normal mode");
  262. }
  263. /* Enter normal mode from rescue mode. */
  264. static grub_err_t
  265. grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
  266. int argc, char *argv[])
  267. {
  268. if (argc == 0)
  269. {
  270. /* Guess the config filename. It is necessary to make CONFIG static,
  271. so that it won't get broken by longjmp. */
  272. char *config;
  273. const char *prefix;
  274. prefix = grub_env_get ("prefix");
  275. if (prefix)
  276. {
  277. config = grub_xasprintf ("%s/grub.cfg", prefix);
  278. if (! config)
  279. goto quit;
  280. grub_enter_normal_mode (config);
  281. grub_free (config);
  282. }
  283. else
  284. grub_enter_normal_mode (0);
  285. }
  286. else
  287. grub_enter_normal_mode (argv[0]);
  288. quit:
  289. return 0;
  290. }
  291. /* Exit from normal mode to rescue mode. */
  292. static grub_err_t
  293. grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)),
  294. int argc __attribute__ ((unused)),
  295. char *argv[] __attribute__ ((unused)))
  296. {
  297. if (nested_level <= grub_normal_exit_level)
  298. return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment");
  299. grub_normal_exit_level++;
  300. return GRUB_ERR_NONE;
  301. }
  302. static grub_err_t
  303. grub_normal_reader_init (int nested)
  304. {
  305. struct grub_term_output *term;
  306. const char *msg_esc = _("ESC at any time exits.");
  307. char *msg_formatted;
  308. msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For "
  309. "the first word, TAB lists possible command completions. Anywhere "
  310. "else TAB lists possible device or file completions. %s"),
  311. nested ? msg_esc : "");
  312. if (!msg_formatted)
  313. return grub_errno;
  314. FOR_ACTIVE_TERM_OUTPUTS(term)
  315. {
  316. grub_normal_init_page (term, 1);
  317. grub_term_setcursor (term, 1);
  318. if (grub_term_width (term) > 3 + STANDARD_MARGIN + 20)
  319. grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
  320. else
  321. grub_print_message_indented (msg_formatted, 0, 0, term);
  322. grub_putcode ('\n', term);
  323. grub_putcode ('\n', term);
  324. grub_putcode ('\n', term);
  325. }
  326. grub_free (msg_formatted);
  327. return 0;
  328. }
  329. static grub_err_t
  330. grub_normal_read_line_real (char **line, int cont, int nested)
  331. {
  332. const char *prompt;
  333. if (cont)
  334. /* TRANSLATORS: it's command line prompt. */
  335. prompt = _(">");
  336. else
  337. /* TRANSLATORS: it's command line prompt. */
  338. prompt = _("grub>");
  339. if (!prompt)
  340. return grub_errno;
  341. while (1)
  342. {
  343. *line = grub_cmdline_get (prompt);
  344. if (*line)
  345. return 0;
  346. if (cont || nested)
  347. {
  348. grub_free (*line);
  349. *line = 0;
  350. return grub_errno;
  351. }
  352. }
  353. }
  354. static grub_err_t
  355. grub_normal_read_line (char **line, int cont,
  356. void *data __attribute__ ((unused)))
  357. {
  358. return grub_normal_read_line_real (line, cont, 0);
  359. }
  360. void
  361. grub_cmdline_run (int nested, int force_auth)
  362. {
  363. grub_err_t err = GRUB_ERR_NONE;
  364. do
  365. {
  366. err = grub_auth_check_authentication (NULL);
  367. }
  368. while (err && force_auth);
  369. if (err)
  370. {
  371. grub_print_error ();
  372. grub_errno = GRUB_ERR_NONE;
  373. return;
  374. }
  375. grub_normal_reader_init (nested);
  376. while (1)
  377. {
  378. char *line = NULL;
  379. if (grub_normal_exit_level)
  380. break;
  381. /* Print an error, if any. */
  382. grub_print_error ();
  383. grub_errno = GRUB_ERR_NONE;
  384. grub_normal_read_line_real (&line, 0, nested);
  385. if (! line)
  386. break;
  387. grub_normal_parse_line (line, grub_normal_read_line, NULL);
  388. grub_free (line);
  389. }
  390. }
  391. static char *
  392. grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
  393. const char *val)
  394. {
  395. grub_set_more ((*val == '1'));
  396. return grub_strdup (val);
  397. }
  398. /* clear */
  399. static grub_err_t
  400. grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)),
  401. int argc __attribute__ ((unused)),
  402. char *argv[] __attribute__ ((unused)))
  403. {
  404. grub_cls ();
  405. return 0;
  406. }
  407. static grub_command_t cmd_clear;
  408. static void (*grub_xputs_saved) (const char *str);
  409. static const char *features[] = {
  410. "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
  411. "feature_default_font_path", "feature_all_video_module",
  412. "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
  413. "feature_nativedisk_cmd", "feature_timeout_style"
  414. };
  415. GRUB_MOD_INIT(normal)
  416. {
  417. unsigned i;
  418. grub_boot_time ("Preparing normal module");
  419. /* Previously many modules depended on gzio. Be nice to user and load it. */
  420. grub_dl_load ("gzio");
  421. grub_errno = 0;
  422. grub_normal_auth_init ();
  423. grub_context_init ();
  424. grub_script_init ();
  425. grub_menu_init ();
  426. grub_xputs_saved = grub_xputs;
  427. grub_xputs = grub_xputs_normal;
  428. /* Normal mode shouldn't be unloaded. */
  429. if (mod)
  430. grub_dl_ref (mod);
  431. cmd_clear =
  432. grub_register_command ("clear", grub_mini_cmd_clear,
  433. 0, N_("Clear the screen."));
  434. grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
  435. grub_register_variable_hook ("pager", 0, grub_env_write_pager);
  436. grub_env_export ("pager");
  437. /* Register a command "normal" for the rescue mode. */
  438. grub_register_command ("normal", grub_cmd_normal,
  439. 0, N_("Enter normal mode."));
  440. grub_register_command ("normal_exit", grub_cmd_normal_exit,
  441. 0, N_("Exit from normal mode."));
  442. /* Reload terminal colors when these variables are written to. */
  443. grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
  444. grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight);
  445. /* Preserve hooks after context changes. */
  446. grub_env_export ("color_normal");
  447. grub_env_export ("color_highlight");
  448. /* Set default color names. */
  449. grub_env_set ("color_normal", "light-gray/black");
  450. grub_env_set ("color_highlight", "black/light-gray");
  451. for (i = 0; i < ARRAY_SIZE (features); i++)
  452. {
  453. grub_env_set (features[i], "y");
  454. grub_env_export (features[i]);
  455. }
  456. grub_env_set ("grub_cpu", GRUB_TARGET_CPU);
  457. grub_env_export ("grub_cpu");
  458. grub_env_set ("grub_platform", GRUB_PLATFORM);
  459. grub_env_export ("grub_platform");
  460. grub_boot_time ("Normal module prepared");
  461. }
  462. GRUB_MOD_FINI(normal)
  463. {
  464. grub_context_fini ();
  465. grub_script_fini ();
  466. grub_menu_fini ();
  467. grub_normal_auth_fini ();
  468. grub_xputs = grub_xputs_saved;
  469. grub_set_history (0);
  470. grub_register_variable_hook ("pager", 0, 0);
  471. grub_fs_autoload_hook = 0;
  472. grub_unregister_command (cmd_clear);
  473. }