+diff --git a/grub-core/commands/legacycfg.c b/grub-core/commands/legacycfg.c
+index db7a8f00273..891eac5a33f 100644
+--- a/grub-core/commands/legacycfg.c
++++ b/grub-core/commands/legacycfg.c
+@@ -133,7 +133,7 @@ legacy_file (const char *filename)
+ args[0] = oldname;
+ grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
+ NULL, NULL,
+- entrysrc, 0);
++ entrysrc, 0, NULL, NULL);
+ grub_free (args);
+ entrysrc[0] = 0;
+ grub_free (oldname);
+@@ -186,7 +186,8 @@ legacy_file (const char *filename)
+ }
+ args[0] = entryname;
+ grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
+- NULL, NULL, entrysrc, 0);
++ NULL, NULL, entrysrc, 0, NULL,
++ NULL);
+ grub_free (args);
+ }
+
+diff --git a/grub-core/commands/loadenv.c b/grub-core/commands/loadenv.c
+index 3fd664aac33..163b9a09042 100644
+--- a/grub-core/commands/loadenv.c
++++ b/grub-core/commands/loadenv.c
+@@ -28,6 +28,8 @@
+ #include <grub/extcmd.h>
+ #include <grub/i18n.h>
+
++#include "loadenv.h"
++
+ GRUB_MOD_LICENSE ("GPLv3+");
+
+ static const struct grub_arg_option options[] =
+@@ -79,81 +81,6 @@ open_envblk_file (char *filename,
+ return file;
+ }
+
+-static grub_envblk_t
+-read_envblk_file (grub_file_t file)
+-{
+- grub_off_t offset = 0;
+- char *buf;
+- grub_size_t size = grub_file_size (file);
+- grub_envblk_t envblk;
+-
+- buf = grub_malloc (size);
+- if (! buf)
+- return 0;
+-
+- while (size > 0)
+- {
+- grub_ssize_t ret;
+-
+- ret = grub_file_read (file, buf + offset, size);
+- if (ret <= 0)
+- {
+- grub_free (buf);
+- return 0;
+- }
+-
+- size -= ret;
+- offset += ret;
+- }
+-
+- envblk = grub_envblk_open (buf, offset);
+- if (! envblk)
+- {
+- grub_free (buf);
+- grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
+- return 0;
+- }
+-
+- return envblk;
+-}
+-
+-struct grub_env_whitelist
+-{
+- grub_size_t len;
+- char **list;
+-};
+-typedef struct grub_env_whitelist grub_env_whitelist_t;
+-
+-static int
+-test_whitelist_membership (const char* name,
+- const grub_env_whitelist_t* whitelist)
+-{
+- grub_size_t i;
+-
+- for (i = 0; i < whitelist->len; i++)
+- if (grub_strcmp (name, whitelist->list[i]) == 0)
+- return 1; /* found it */
+-
+- return 0; /* not found */
+-}
+-
+-/* Helper for grub_cmd_load_env. */
+-static int
+-set_var (const char *name, const char *value, void *whitelist)
+-{
+- if (! whitelist)
+- {
+- grub_env_set (name, value);
+- return 0;
+- }
+-
+- if (test_whitelist_membership (name,
+- (const grub_env_whitelist_t *) whitelist))
+- grub_env_set (name, value);
+-
+- return 0;
+-}
+-
+ static grub_err_t
+ grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args)
+ {
+diff --git a/grub-core/commands/menuentry.c b/grub-core/commands/menuentry.c
+index 2c5363da7f5..9faf2be0f64 100644
+--- a/grub-core/commands/menuentry.c
++++ b/grub-core/commands/menuentry.c
+@@ -78,7 +78,7 @@ grub_normal_add_menu_entry (int argc, const char **args,
+ char **classes, const char *id,
+ const char *users, const char *hotkey,
+ const char *prefix, const char *sourcecode,
+- int submenu)
++ int submenu, int *index, struct bls_entry *bls)
+ {
+ int menu_hotkey = 0;
+ char **menu_args = NULL;
+@@ -149,9 +149,12 @@ grub_normal_add_menu_entry (int argc, const char **args,
+ if (! menu_title)
+ goto fail;
+
++ grub_dprintf ("menu", "id:\"%s\"\n", id);
++ grub_dprintf ("menu", "title:\"%s\"\n", menu_title);
+ menu_id = grub_strdup (id ? : menu_title);
+ if (! menu_id)
+ goto fail;
++ grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id);
+
+ /* Save argc, args to pass as parameters to block arg later. */
+ menu_args = grub_calloc (argc + 1, sizeof (char *));
+@@ -170,8 +173,12 @@ grub_normal_add_menu_entry (int argc, const char **args,
+ }
+
+ /* Add the menu entry at the end of the list. */
++ int ind=0;
+ while (*last)
+- last = &(*last)->next;
++ {
++ ind++;
++ last = &(*last)->next;
++ }
+
+ *last = grub_zalloc (sizeof (**last));
+ if (! *last)
+@@ -188,8 +195,11 @@ grub_normal_add_menu_entry (int argc, const char **args,
+ (*last)->args = menu_args;
+ (*last)->sourcecode = menu_sourcecode;
+ (*last)->submenu = submenu;
++ (*last)->bls = bls;
+
+ menu->size++;
++ if (index)
++ *index = ind;
+ return GRUB_ERR_NONE;
+
+ fail:
+@@ -286,7 +296,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
+ users,
+ ctxt->state[2].arg, 0,
+ ctxt->state[3].arg,
+- ctxt->extcmd->cmd->name[0] == 's');
++ ctxt->extcmd->cmd->name[0] == 's',
++ NULL, NULL);
+
+ src = args[argc - 1];
+ args[argc - 1] = NULL;
+@@ -303,7 +314,8 @@ grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
+ ctxt->state[0].args, ctxt->state[4].arg,
+ users,
+ ctxt->state[2].arg, prefix, src + 1,
+- ctxt->extcmd->cmd->name[0] == 's');
++ ctxt->extcmd->cmd->name[0] == 's', NULL,
++ NULL);
+
+ src[len - 1] = ch;
+ args[argc - 1] = src;
+diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
+index 9ef98481f70..a326b192c89 100644
+--- a/grub-core/normal/main.c
++++ b/grub-core/normal/main.c
+@@ -20,6 +20,7 @@
+ #include <grub/net.h>
+ #include <grub/normal.h>
+ #include <grub/dl.h>
++#include <grub/menu.h>
+ #include <grub/misc.h>
+ #include <grub/file.h>
+ #include <grub/mm.h>
+@@ -70,6 +71,11 @@ grub_normal_free_menu (grub_menu_t menu)
+ grub_free (entry->args);
+ }
+
++ if (entry->bls)
++ {
++ entry->bls->visible = 0;
++ }
++
+ grub_free ((void *) entry->id);
+ grub_free ((void *) entry->users);
+ grub_free ((void *) entry->title);
+diff --git a/grub-core/commands/loadenv.h b/grub-core/commands/loadenv.h
+new file mode 100644
+index 00000000000..952f46121bd
+--- /dev/null
++++ b/grub-core/commands/loadenv.h
+@@ -0,0 +1,93 @@
++/* loadenv.c - command to load/save environment variable. */
++/*
++ * GRUB -- GRand Unified Bootloader
++ * Copyright (C) 2008,2009,2010 Free Software Foundation, Inc.
++ *
++ * GRUB is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * GRUB is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++static grub_envblk_t UNUSED
++read_envblk_file (grub_file_t file)
++{
++ grub_off_t offset = 0;
++ char *buf;
++ grub_size_t size = grub_file_size (file);
++ grub_envblk_t envblk;
++
++ buf = grub_malloc (size);
++ if (! buf)
++ return 0;
++
++ while (size > 0)
++ {
++ grub_ssize_t ret;
++
++ ret = grub_file_read (file, buf + offset, size);
++ if (ret <= 0)
++ {
++ grub_free (buf);
++ return 0;
++ }
++
++ size -= ret;
++ offset += ret;
++ }
++
++ envblk = grub_envblk_open (buf, offset);
++ if (! envblk)
++ {
++ grub_free (buf);
++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
++ return 0;
++ }
++
++ return envblk;
++}
++
++struct grub_env_whitelist
++{
++ grub_size_t len;
++ char **list;
++};
++typedef struct grub_env_whitelist grub_env_whitelist_t;
++
++static int UNUSED
++test_whitelist_membership (const char* name,
++ const grub_env_whitelist_t* whitelist)
++{
++ grub_size_t i;
++
++ for (i = 0; i < whitelist->len; i++)
++ if (grub_strcmp (name, whitelist->list[i]) == 0)
++ return 1; /* found it */
++
++ return 0; /* not found */
++}
++
++/* Helper for grub_cmd_load_env. */
++static int UNUSED
++set_var (const char *name, const char *value, void *whitelist)
++{
++ if (! whitelist)
++ {
++ grub_env_set (name, value);
++ return 0;
++ }
++
++ if (test_whitelist_membership (name,
++ (const grub_env_whitelist_t *) whitelist))
++ grub_env_set (name, value);
++
++ return 0;
++}
+diff --git a/include/grub/compiler.h b/include/grub/compiler.h
+index c9e1d7a73dc..9859ff4cc79 100644
+--- a/include/grub/compiler.h
++++ b/include/grub/compiler.h
+@@ -48,4 +48,6 @@
+ # define CLANG_PREREQ(maj,min) 0
+ #endif
+
++#define UNUSED __attribute__((__unused__))
++
+ #endif /* ! GRUB_COMPILER_HEADER */
+diff --git a/include/grub/menu.h b/include/grub/menu.h
+index ee2b5e91045..0acdc2aa6bf 100644
+--- a/include/grub/menu.h
++++ b/include/grub/menu.h
+@@ -20,6 +20,16 @@
+ #ifndef GRUB_MENU_HEADER
+ #define GRUB_MENU_HEADER 1
+
++struct bls_entry
++{
++ struct bls_entry *next;
++ struct bls_entry *prev;
++ struct keyval **keyvals;
++ int nkeyvals;
++ char *filename;
++ int visible;
++};
++
+ struct grub_menu_entry_class
+ {
+ char *name;
+@@ -60,6 +70,9 @@ struct grub_menu_entry
+
+ /* The next element. */
+ struct grub_menu_entry *next;
++
++ /* BLS used to populate the entry */
++ struct bls_entry *bls;
+ };
+ typedef struct grub_menu_entry *grub_menu_entry_t;
+
+diff --git a/include/grub/normal.h b/include/grub/normal.h
+index 218cbabccaf..8839ad85a19 100644
+--- a/include/grub/normal.h
++++ b/include/grub/normal.h
+@@ -145,7 +145,7 @@ grub_normal_add_menu_entry (int argc, const char **args, char **classes,
+ const char *id,
+ const char *users, const char *hotkey,
+ const char *prefix, const char *sourcecode,
+- int submenu);
++ int submenu, int *index, struct bls_entry *bls);
+
+ grub_err_t
+ grub_normal_set_password (const char *user, const char *password);