menuentry.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /* menuentry.c - menuentry command */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2010 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/types.h>
  20. #include <grub/misc.h>
  21. #include <grub/err.h>
  22. #include <grub/dl.h>
  23. #include <grub/extcmd.h>
  24. #include <grub/i18n.h>
  25. #include <grub/normal.h>
  26. static const struct grub_arg_option options[] =
  27. {
  28. {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
  29. N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
  30. {"users", 2, 0,
  31. N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
  32. ARG_TYPE_STRING},
  33. {"hotkey", 3, 0,
  34. N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING},
  35. {"source", 4, 0,
  36. N_("Use STRING as menu entry body."), N_("STRING"), ARG_TYPE_STRING},
  37. {"id", 0, 0, N_("Menu entry identifier."), N_("STRING"), ARG_TYPE_STRING},
  38. /* TRANSLATORS: menu entry can either be bootable by anyone or only by
  39. handful of users. By default when security is active only superusers can
  40. boot a given menu entry. With --unrestricted (this option)
  41. anyone can boot it. */
  42. {"unrestricted", 0, 0, N_("This entry can be booted by any user."),
  43. 0, ARG_TYPE_NONE},
  44. {0, 0, 0, 0, 0, 0}
  45. };
  46. static struct
  47. {
  48. const char *name;
  49. int key;
  50. } hotkey_aliases[] =
  51. {
  52. {"backspace", '\b'},
  53. {"tab", '\t'},
  54. {"delete", GRUB_TERM_KEY_DC},
  55. {"insert", GRUB_TERM_KEY_INSERT},
  56. {"f1", GRUB_TERM_KEY_F1},
  57. {"f2", GRUB_TERM_KEY_F2},
  58. {"f3", GRUB_TERM_KEY_F3},
  59. {"f4", GRUB_TERM_KEY_F4},
  60. {"f5", GRUB_TERM_KEY_F5},
  61. {"f6", GRUB_TERM_KEY_F6},
  62. {"f7", GRUB_TERM_KEY_F7},
  63. {"f8", GRUB_TERM_KEY_F8},
  64. {"f9", GRUB_TERM_KEY_F9},
  65. {"f10", GRUB_TERM_KEY_F10},
  66. {"f11", GRUB_TERM_KEY_F11},
  67. {"f12", GRUB_TERM_KEY_F12},
  68. };
  69. /* Add a menu entry to the current menu context (as given by the environment
  70. variable data slot `menu'). As the configuration file is read, the script
  71. parser calls this when a menu entry is to be created. */
  72. grub_err_t
  73. grub_normal_add_menu_entry (int argc, const char **args,
  74. char **classes, const char *id,
  75. const char *users, const char *hotkey,
  76. const char *prefix, const char *sourcecode,
  77. int submenu)
  78. {
  79. int menu_hotkey = 0;
  80. char **menu_args = NULL;
  81. char *menu_users = NULL;
  82. char *menu_title = NULL;
  83. char *menu_sourcecode = NULL;
  84. char *menu_id = NULL;
  85. struct grub_menu_entry_class *menu_classes = NULL;
  86. grub_menu_t menu;
  87. grub_menu_entry_t *last;
  88. menu = grub_env_get_menu ();
  89. if (! menu)
  90. return grub_error (GRUB_ERR_MENU, "no menu context");
  91. last = &menu->entry_list;
  92. menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
  93. if (! menu_sourcecode)
  94. return grub_errno;
  95. if (classes && classes[0])
  96. {
  97. int i;
  98. for (i = 0; classes[i]; i++); /* count # of menuentry classes */
  99. menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class)
  100. * (i + 1));
  101. if (! menu_classes)
  102. goto fail;
  103. for (i = 0; classes[i]; i++)
  104. {
  105. menu_classes[i].name = grub_strdup (classes[i]);
  106. if (! menu_classes[i].name)
  107. goto fail;
  108. menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
  109. }
  110. }
  111. if (users)
  112. {
  113. menu_users = grub_strdup (users);
  114. if (! menu_users)
  115. goto fail;
  116. }
  117. if (hotkey)
  118. {
  119. unsigned i;
  120. for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
  121. if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
  122. {
  123. menu_hotkey = hotkey_aliases[i].key;
  124. break;
  125. }
  126. if (i == ARRAY_SIZE (hotkey_aliases))
  127. menu_hotkey = hotkey[0];
  128. }
  129. if (! argc)
  130. {
  131. grub_error (GRUB_ERR_MENU, "menuentry is missing title");
  132. goto fail;
  133. }
  134. menu_title = grub_strdup (args[0]);
  135. if (! menu_title)
  136. goto fail;
  137. menu_id = grub_strdup (id ? : menu_title);
  138. if (! menu_id)
  139. goto fail;
  140. /* Save argc, args to pass as parameters to block arg later. */
  141. menu_args = grub_malloc (sizeof (char*) * (argc + 1));
  142. if (! menu_args)
  143. goto fail;
  144. {
  145. int i;
  146. for (i = 0; i < argc; i++)
  147. {
  148. menu_args[i] = grub_strdup (args[i]);
  149. if (! menu_args[i])
  150. goto fail;
  151. }
  152. menu_args[argc] = NULL;
  153. }
  154. /* Add the menu entry at the end of the list. */
  155. while (*last)
  156. last = &(*last)->next;
  157. *last = grub_zalloc (sizeof (**last));
  158. if (! *last)
  159. goto fail;
  160. (*last)->title = menu_title;
  161. (*last)->id = menu_id;
  162. (*last)->hotkey = menu_hotkey;
  163. (*last)->classes = menu_classes;
  164. if (menu_users)
  165. (*last)->restricted = 1;
  166. (*last)->users = menu_users;
  167. (*last)->argc = argc;
  168. (*last)->args = menu_args;
  169. (*last)->sourcecode = menu_sourcecode;
  170. (*last)->submenu = submenu;
  171. menu->size++;
  172. return GRUB_ERR_NONE;
  173. fail:
  174. grub_free (menu_sourcecode);
  175. {
  176. int i;
  177. for (i = 0; menu_classes && menu_classes[i].name; i++)
  178. grub_free (menu_classes[i].name);
  179. grub_free (menu_classes);
  180. }
  181. {
  182. int i;
  183. for (i = 0; menu_args && menu_args[i]; i++)
  184. grub_free (menu_args[i]);
  185. grub_free (menu_args);
  186. }
  187. grub_free (menu_users);
  188. grub_free (menu_title);
  189. grub_free (menu_id);
  190. return grub_errno;
  191. }
  192. static char *
  193. setparams_prefix (int argc, char **args)
  194. {
  195. int i;
  196. int j;
  197. char *p;
  198. char *result;
  199. grub_size_t len = 10;
  200. /* Count resulting string length */
  201. for (i = 0; i < argc; i++)
  202. {
  203. len += 3; /* 3 = 1 space + 2 quotes */
  204. p = args[i];
  205. while (*p)
  206. len += (*p++ == '\'' ? 3 : 1);
  207. }
  208. result = grub_malloc (len + 2);
  209. if (! result)
  210. return 0;
  211. grub_strcpy (result, "setparams");
  212. p = result + 9;
  213. for (j = 0; j < argc; j++)
  214. {
  215. *p++ = ' ';
  216. *p++ = '\'';
  217. p = grub_strchrsub (p, args[j], '\'', "'\\''");
  218. *p++ = '\'';
  219. }
  220. *p++ = '\n';
  221. *p = '\0';
  222. return result;
  223. }
  224. static grub_err_t
  225. grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
  226. {
  227. char ch;
  228. char *src;
  229. char *prefix;
  230. unsigned len;
  231. grub_err_t r;
  232. const char *users;
  233. if (! argc)
  234. return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
  235. if (ctxt->state[3].set && ctxt->script)
  236. return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
  237. if (! ctxt->state[3].set && ! ctxt->script)
  238. return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
  239. if (ctxt->state[1].set)
  240. users = ctxt->state[1].arg;
  241. else if (ctxt->state[5].set)
  242. users = NULL;
  243. else
  244. users = "";
  245. if (! ctxt->script)
  246. return grub_normal_add_menu_entry (argc, (const char **) args,
  247. (ctxt->state[0].set ? ctxt->state[0].args
  248. : NULL),
  249. ctxt->state[4].arg,
  250. users,
  251. ctxt->state[2].arg, 0,
  252. ctxt->state[3].arg,
  253. ctxt->extcmd->cmd->name[0] == 's');
  254. src = args[argc - 1];
  255. args[argc - 1] = NULL;
  256. len = grub_strlen(src);
  257. ch = src[len - 1];
  258. src[len - 1] = '\0';
  259. prefix = setparams_prefix (argc - 1, args);
  260. if (! prefix)
  261. return grub_errno;
  262. r = grub_normal_add_menu_entry (argc - 1, (const char **) args,
  263. ctxt->state[0].args, ctxt->state[4].arg,
  264. users,
  265. ctxt->state[2].arg, prefix, src + 1,
  266. ctxt->extcmd->cmd->name[0] == 's');
  267. src[len - 1] = ch;
  268. args[argc - 1] = src;
  269. grub_free (prefix);
  270. return r;
  271. }
  272. static grub_extcmd_t cmd, cmd_sub;
  273. void
  274. grub_menu_init (void)
  275. {
  276. cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
  277. GRUB_COMMAND_FLAG_BLOCKS
  278. | GRUB_COMMAND_ACCEPT_DASH
  279. | GRUB_COMMAND_FLAG_EXTRACTOR,
  280. N_("BLOCK"), N_("Define a menu entry."), options);
  281. cmd_sub = grub_register_extcmd ("submenu", grub_cmd_menuentry,
  282. GRUB_COMMAND_FLAG_BLOCKS
  283. | GRUB_COMMAND_ACCEPT_DASH
  284. | GRUB_COMMAND_FLAG_EXTRACTOR,
  285. N_("BLOCK"), N_("Define a submenu."),
  286. options);
  287. }
  288. void
  289. grub_menu_fini (void)
  290. {
  291. grub_unregister_extcmd (cmd);
  292. grub_unregister_extcmd (cmd_sub);
  293. }