All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Save/Load environment variable support
@ 2008-06-13  7:07 Bean
  2008-06-14 18:47 ` Robert Millan
  2008-06-14 19:30 ` Robert Millan
  0 siblings, 2 replies; 18+ messages in thread
From: Bean @ 2008-06-13  7:07 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 219 bytes --]

Hi,

I separate the save/load environment variable function from my
previous patch on environment block. It contains the command
save_env/load_env/list_env and tool grub-editenv, but without the
kernel patch.

-- 
Bean

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: envblk_3a.diff --]
[-- Type: text/x-diff; name=envblk_3a.diff, Size: 19879 bytes --]


diff --git a/commands/loadenv.c b/commands/loadenv.c
new file mode 100755
index 0000000..970baf3
--- /dev/null
+++ b/commands/loadenv.c
@@ -0,0 +1,250 @@
+/* loadenv.c - command to load/save environment variable.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/arg.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/envblk.h>
+
+static const struct grub_arg_option options[] =
+  {
+    {"file", 'f', 0, "specify filename", 0, ARG_TYPE_PATHNAME},
+    {0, 0, 0, 0, 0, 0}
+  };
+
+char buffer[GRUB_ENVBLK_MAXLEN];
+grub_envblk_t envblk;
+
+static grub_file_t
+read_envblk_file (char *filename, void NESTED_FUNC_ATTR read_hook (grub_disk_addr_t sector, unsigned offset, unsigned length))
+{
+  char *buf = 0;
+  grub_file_t file;
+
+  if (! filename)
+    {
+      char *prefix;
+
+      prefix = grub_env_get ("prefix");
+      if (prefix)
+        {
+          int len;
+
+          len = grub_strlen (prefix);
+          buf = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG));
+          grub_strcpy (buf, prefix);
+          buf[len] = '/';
+          grub_strcpy (buf + len + 1, GRUB_ENVBLK_DEFCFG);
+          filename = buf;
+        }
+      else
+        {
+          grub_error (GRUB_ERR_FILE_NOT_FOUND, "prefix is not found");
+          return 0;
+        }
+    }
+
+  file = grub_file_open (filename);
+  grub_free (buf);
+  if (! file)
+    return 0;
+
+  if (read_hook)
+    {
+      if (! file->device->disk)
+        {
+          grub_file_close (file);
+          grub_error (GRUB_ERR_BAD_DEVICE,
+                      "this command is available only for disk devices.");
+          return 0;
+        }
+      file->read_hook = read_hook;
+    }
+
+  if (grub_file_read (file, buffer, GRUB_ENVBLK_MAXLEN) != GRUB_ENVBLK_MAXLEN)
+    {
+      grub_file_close (file);
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "file too short");
+      return 0;
+    }
+
+  envblk = grub_envblk_find (buffer);
+  if (! envblk)
+    {
+      grub_file_close (file);
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "environment block not found");
+      return 0;
+    }
+
+  return file;
+}
+
+static grub_err_t
+grub_cmd_load_env (struct grub_arg_list *state,
+                   int argc __attribute__ ((unused)), char **args __attribute__ ((unused)))
+
+{
+  grub_file_t file;
+
+  auto int hook (char *name, char *value);
+  int hook (char *name, char *value)
+    {
+      grub_env_set (name, value);
+
+      return 0;
+    }
+
+  file = read_envblk_file ((state[0].set) ? state[0].arg : 0, 0);
+  if (! file)
+    return grub_errno;
+
+  grub_file_close (file);
+
+  grub_envblk_iterate (envblk, hook);
+
+  return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_list_env (struct grub_arg_list *state,
+                   int argc __attribute__ ((unused)), char **args __attribute__ ((unused)))
+{
+  grub_file_t file;
+
+  auto int hook (char *name, char *value);
+  int hook (char *name, char *value)
+    {
+      grub_printf ("%s=%s\n", name, value);
+
+      return 0;
+    }
+
+  file = read_envblk_file ((state[0].set) ? state[0].arg : 0, 0);
+  if (! file)
+    return grub_errno;
+
+  grub_file_close (file);
+
+  grub_envblk_iterate (envblk, hook);
+
+  return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_save_env (struct grub_arg_list *state, int argc, char **args)
+{
+  grub_file_t file;
+  grub_disk_t disk;
+  grub_disk_addr_t addr[GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS];
+  char buf[GRUB_DISK_SECTOR_SIZE];
+  int num = 0;
+
+  auto void NESTED_FUNC_ATTR hook (grub_disk_addr_t sector, unsigned offset,
+                                   unsigned length);
+
+  void NESTED_FUNC_ATTR hook (grub_disk_addr_t sector,
+                              unsigned offset, unsigned length)
+    {
+      if ((offset != 0) || (length != GRUB_DISK_SECTOR_SIZE))
+        return;
+
+      if (num < (GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS))
+        addr[num++] = sector;
+    }
+
+  if (! argc)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "No variable is specified");
+
+  file = read_envblk_file ((state[0].set) ? state[0].arg : 0, hook);
+  if (! file)
+    return grub_errno;
+
+  file->read_hook = 0;
+
+  if (num != GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS)
+    {
+      grub_error (GRUB_ERR_BAD_DEVICE, "invalid blocklist");
+      goto quit;
+    }
+
+  disk = file->device->disk;
+  for (num = 0; num < (GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS); num++)
+    {
+      if (disk->dev->read (disk, addr[num], 1, buf))
+        goto quit;
+
+      if (grub_memcmp (&buffer[num << GRUB_DISK_SECTOR_BITS], buf,
+                       GRUB_DISK_SECTOR_SIZE))
+        {
+          grub_error (GRUB_ERR_BAD_DEVICE, "invalid blocklist");
+          goto quit;
+        }
+    }
+
+  while (argc)
+    {
+      char *value;
+
+      value = grub_env_get (args[0]);
+      if (value)
+        {
+          if (grub_envblk_insert (envblk, args[0], value))
+            {
+              grub_error (GRUB_ERR_BAD_ARGUMENT, "environment block too small");
+              goto quit;
+            }
+        }
+
+      argc--;
+      args++;
+    }
+
+  for (num = 0; num < (GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS); num++)
+    if (disk->dev->write (disk, addr[num], 1,
+                          &buffer[num << GRUB_DISK_SECTOR_BITS]))
+      goto quit;
+
+quit:
+  grub_file_close (file);
+
+  return grub_errno;
+}
+
+GRUB_MOD_INIT(loadenv)
+{
+  (void) mod;
+  grub_register_command ("load_env", grub_cmd_load_env, GRUB_COMMAND_FLAG_BOTH,
+			 "load_env [-f FILE]", "Load variables from environment block file.", options);
+  grub_register_command ("list_env", grub_cmd_list_env, GRUB_COMMAND_FLAG_BOTH,
+			 "list_env [-f FILE]", "List variables from environment block file.", options);
+  grub_register_command ("save_env", grub_cmd_save_env, GRUB_COMMAND_FLAG_BOTH,
+			 "save_env [-f FILE] variable_name [...]", "Save variables to environment block file.", options);
+}
+
+GRUB_MOD_FINI(loadenv)
+{
+  grub_unregister_command ("load_env");
+  grub_unregister_command ("list_env");
+  grub_unregister_command ("save_env");
+}
diff --git a/conf/common.rmk b/conf/common.rmk
index acbebc7..99252ac 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -94,6 +94,11 @@ grub_fstest_init.c: grub_fstest_init.lst $(filter-out grub_fstest_init.c,$(grub_
 	rm -f $@; sh $(srcdir)/geninit.sh $< $(filter %.c,$^) > $@
 DISTCLEANFILES += grub_fstest_init.c
 
+# for grub-editenv
+bin_UTILITIES += grub-editenv
+grub_editenv_SOURCES = util/grub-editenv.c util/envblk.c util/misc.c
+CLEANFILES += grub-editenv
+
 # For update-grub
 update-grub: util/update-grub.in config.status
 	./config.status --file=$@:$<
@@ -282,7 +287,7 @@ pkglib_MODULES += hello.mod boot.mod terminal.mod ls.mod	\
 	cmp.mod cat.mod help.mod font.mod search.mod		\
 	loopback.mod configfile.mod echo.mod			\
 	terminfo.mod test.mod blocklist.mod hexdump.mod		\
-	read.mod sleep.mod
+	read.mod sleep.mod loadenv.mod
 
 # For hello.mod.
 hello_mod_SOURCES = hello/hello.c
@@ -364,8 +369,23 @@ hexdump_mod_SOURCES = commands/hexdump.c
 hexdump_mod_CFLAGS = $(COMMON_CFLAGS)
 hexdump_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For read.mod.
+read_mod_SOURCES = commands/read.c
+read_mod_CFLAGS = $(COMMON_CFLAGS)
+read_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For sleep.mod.
+sleep_mod_SOURCES = commands/sleep.c
+sleep_mod_CFLAGS = $(COMMON_CFLAGS)
+sleep_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For loadenv.mod.
+loadenv_mod_SOURCES = commands/loadenv.c util/envblk.c
+loadenv_mod_CFLAGS = $(COMMON_CFLAGS)
+loadenv_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # Misc.
-pkglib_MODULES += gzio.mod elf.mod
+pkglib_MODULES += gzio.mod elf.mod findroot.mod
 
 # For elf.mod.
 elf_mod_SOURCES = kern/elf.c
@@ -377,12 +397,7 @@ gzio_mod_SOURCES = io/gzio.c
 gzio_mod_CFLAGS = $(COMMON_CFLAGS)
 gzio_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
-# For read.mod.
-read_mod_SOURCES = commands/read.c
-read_mod_CFLAGS = $(COMMON_CFLAGS)
-read_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
-# For sleep.mod.
-sleep_mod_SOURCES = commands/sleep.c
-sleep_mod_CFLAGS = $(COMMON_CFLAGS)
-sleep_mod_LDFLAGS = $(COMMON_LDFLAGS)
+# For findroot.mod.
+findroot_mod_SOURCES = kern/findroot.c
+findroot_mod_CFLAGS = $(COMMON_CFLAGS)
+findroot_mod_LDFLAGS = $(COMMON_LDFLAGS)
diff --git a/include/grub/envblk.h b/include/grub/envblk.h
new file mode 100755
index 0000000..e075089
--- /dev/null
+++ b/include/grub/envblk.h
@@ -0,0 +1,51 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#ifndef GRUB_ENVBLK_HEADER
+#define GRUB_ENVBLK_HEADER	1
+
+#define GRUB_ENVBLK_SIGNATURE	0x4b627645	/* EvbK  */
+
+#define GRUB_ENVBLK_MAXLEN	8192
+
+/* Names of important environment variables.  */
+#define GRUB_ENVBLK_RDIR	"rdir"
+#define GRUB_ENVBLK_UUID	"uuid"
+#define GRUB_ENVBLK_LABEL	"label"
+#define GRUB_ENVBLK_IDFILE	"idfile"
+
+#define GRUB_ENVBLK_DEFCFG	"grubenv"
+
+#ifndef ASM_FILE
+
+struct grub_envblk
+{
+  grub_uint32_t signature;
+  grub_uint16_t length;
+  char data[0];
+} __attribute__ ((packed));
+typedef struct grub_envblk *grub_envblk_t;
+
+grub_envblk_t grub_envblk_find (char *buf);
+int grub_envblk_insert (grub_envblk_t envblk, char *name, char *value);
+void grub_envblk_delete (grub_envblk_t envblk, char *name);
+void grub_envblk_iterate (grub_envblk_t envblk, int hook (char *name, char *value));
+
+#endif
+
+#endif /* ! GRUB_ENVBLK_HEADER */
diff --git a/util/envblk.c b/util/envblk.c
new file mode 100755
index 0000000..5b27062
--- /dev/null
+++ b/util/envblk.c
@@ -0,0 +1,171 @@
+/* envblk.c - Common function for environment block.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#include <config.h>
+#include <grub/types.h>
+#include <grub/envblk.h>
+
+#ifdef GRUB_UTIL
+
+#include <string.h>
+
+#define grub_strlen	strlen
+#define grub_strcpy	strcpy
+#define grub_strchr	strchr
+#define grub_memcmp	memcmp
+#define grub_memcpy	memcpy
+
+#else
+
+#include <grub/misc.h>
+
+#endif
+
+grub_envblk_t
+grub_envblk_find (char *buf)
+{
+  grub_uint32_t *pd;
+  int len;
+
+  pd = (grub_uint32_t *) buf;
+
+  for (len = GRUB_ENVBLK_MAXLEN - 6; len > 0; len -= 4, pd++)
+    if (*pd == GRUB_ENVBLK_SIGNATURE)
+      {
+        grub_envblk_t p;
+
+        p = (grub_envblk_t) pd;
+        if (p->length <= len)
+          return p;
+      }
+
+  return 0;
+}
+
+int
+grub_envblk_insert (grub_envblk_t envblk, char *name, char *value)
+{
+  char *p, *pend;
+  char *found = 0;
+  int nl;
+
+  nl = grub_strlen (name);
+  p = envblk->data;
+  pend = p + envblk->length;
+
+  while (*p)
+    {
+      if ((! found) && (! grub_memcmp (name, p, nl)) && (p[nl] == '='))
+        found = p + nl + 1;
+
+      p += grub_strlen (p) + 1;
+      if (p >= pend)
+        return 1;
+    }
+
+  if (found)
+    {
+      int len1, len2;
+
+      len1 = grub_strlen (found);
+      len2 = grub_strlen (value);
+      if ((p - envblk->data) + 1 - len1 + len2 > envblk->length)
+        return 1;
+
+      grub_memcpy (found + len2 + 1, found + len1 + 1, (p - found) - len1);
+      grub_strcpy (found, value);
+    }
+  else
+    {
+      int len2 = grub_strlen (value);
+
+      if ((p - envblk->data) + nl + 1 + len2 + 2 > envblk->length)
+        return 1;
+
+      grub_strcpy (p, name);
+      p[nl] = '=';
+      grub_strcpy (p + nl + 1, value);
+      p[nl + 1 + len2 + 1] = 0;
+    }
+
+  return 0;
+}
+
+void
+grub_envblk_delete (grub_envblk_t envblk, char *name)
+{
+  char *p, *pend;
+  char *found = 0;
+  int nl;
+
+  nl = grub_strlen (name);
+  p = envblk->data;
+  pend = p + envblk->length;
+
+  while (*p)
+    {
+      if ((! found) && (! grub_memcmp (name, p, nl)) && (p[nl] == '='))
+        found = p;
+
+      p += grub_strlen (p) + 1;
+      if (p >= pend)
+        return;
+    }
+
+  if (found)
+    {
+      int len;
+
+      len = grub_strlen (found);
+      grub_memcpy (found, found + len + 1, (p - found) - len);
+    }
+}
+
+void
+grub_envblk_iterate (grub_envblk_t envblk,
+                     int hook (char *name, char *value))
+{
+  char *p, *pend;
+
+  p = envblk->data;
+  pend = p + envblk->length;
+
+  while (*p)
+    {
+      char *v;
+      int r;
+
+      v = grub_strchr (p, '=');
+      if (v)
+        {
+          *v = 0;
+          r = hook (p, v + 1);
+          *v = '=';
+        }
+      else
+        r = hook (p, "");
+
+      if (r)
+        break;
+
+      p += grub_strlen (p) + 1;
+      if (p >= pend)
+        break;
+    }
+}
diff --git a/util/grub-editenv.c b/util/grub-editenv.c
new file mode 100755
index 0000000..8c08694
--- /dev/null
+++ b/util/grub-editenv.c
@@ -0,0 +1,228 @@
+/* grub-editenv.c - tool to edit environment block.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008 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/>.
+ */
+
+#include <config.h>
+#include <grub/types.h>
+#include <grub/util/misc.h>
+
+#include <grub/envblk.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+static struct option options[] = {
+  {"help", no_argument, 0, 'h'},
+  {"version", no_argument, 0, 'V'},
+  {"verbose", no_argument, 0, 'v'},
+  {0, 0, 0, 0}
+};
+
+char buffer[GRUB_ENVBLK_MAXLEN];
+grub_envblk_t envblk;
+
+static void
+usage (int status)
+{
+  if (status)
+    fprintf (stderr, "Try ``grub-editenv --help'' for more information.\n");
+  else
+    printf ("\
+Usage: grub-editenv [OPTIONS] FILENAME COMMAND\n\
+\n\
+Tool to edit environment block.\n\
+\nCommands:\n\
+  create                    create a blank environment block file\n\
+  info                      show information about the environment block\n\
+  list                      list the current variables\n\
+  set [name=value] ...      change/delete variables\n\
+  clear                     delete all variables\n\
+\nOptions:\n\
+  -h, --help                display this message and exit\n\
+  -V, --version             print version information and exit\n\
+  -v, --verbose             print verbose messages\n\
+\n\
+Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
+
+  exit (status);
+}
+
+int
+create_envblk_file (char *name)
+{
+  FILE *f;
+  grub_envblk_t p;
+
+  f = fopen (name, "wb");
+  if (! f)
+    return 1;
+
+  /* Just in case OS don't save 0s.  */
+  memset (buffer, -1, sizeof (buffer));
+
+  p = (grub_envblk_t) &buffer[0];
+  p->signature = GRUB_ENVBLK_SIGNATURE;
+  p->length = sizeof (buffer) - sizeof (struct grub_envblk);
+  p->data[0] = p->data[1] = 0;
+
+  fwrite (buffer, sizeof (buffer), 1, f);
+
+  fclose (f);
+  return 0;
+}
+
+FILE *
+open_envblk_file (char *name)
+{
+  FILE *f;
+
+  f = fopen (name, "r+b");
+  if (! f)
+    grub_util_error ("Can\'t open file %s", name);
+
+  if (fread (buffer, 1, sizeof (buffer), f) != sizeof (buffer))
+    grub_util_error ("The envblk file is too short");
+
+  envblk = grub_envblk_find (buffer);
+  if (! envblk)
+    grub_util_error ("Can\'t find environment block");
+
+  return f;
+}
+
+static void
+cmd_info (void)
+{
+  printf ("Envblk offset: %d\n", envblk->data - buffer);
+  printf ("Envblk length: %d\n", envblk->length);
+}
+
+static void
+cmd_list (void)
+{
+  auto int hook (char *name, char *value);
+  int hook (char *name, char *value)
+    {
+      printf ("%s=%s\n", name, value);
+      return 0;
+    }
+
+  grub_envblk_iterate (envblk, hook);
+}
+
+static void
+cmd_set (int argc, char *argv[])
+{
+  while (argc)
+    {
+      char *p;
+
+      p = strchr (argv[0], '=');
+      if (! p)
+        grub_util_error ("Invalid parameter");
+
+      *(p++) = 0;
+
+      if (*p)
+        {
+          if (grub_envblk_insert (envblk, argv[0], p))
+            grub_util_error ("Environment block too small");
+        }
+      else
+        grub_envblk_delete (envblk, argv[0]);
+
+      argc--;
+      argv++;
+    }
+}
+
+static void
+cmd_clear (void)
+{
+  envblk->data[0] = envblk->data[1] = 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  FILE *f;
+
+  progname = "grub-editenv";
+
+  /* Check for options.  */
+  while (1)
+    {
+      int c = getopt_long (argc, argv, "hVv", options, 0);
+
+      if (c == -1)
+	break;
+      else
+	switch (c)
+	  {
+	  case 'h':
+	    usage (0);
+	    break;
+
+	  case 'V':
+	    printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
+	    return 0;
+
+	  case 'v':
+	    verbosity++;
+	    break;
+
+	  default:
+	    usage (1);
+	    break;
+	  }
+    }
+
+  /* Obtain PATH.  */
+  if (optind + 1 >= argc)
+    {
+      fprintf (stderr, "Not enough parameter.\n");
+      usage (1);
+    }
+
+  if (! strcmp (argv[optind + 1], "create"))
+    return create_envblk_file (argv[optind]);
+
+  f = open_envblk_file (argv[optind]);
+
+  optind++;
+  if (! strcmp (argv[optind], "info"))
+    cmd_info ();
+  else if (! strcmp (argv[optind], "list"))
+    cmd_list ();
+  else
+    {
+      if (! strcmp (argv[optind], "set"))
+        cmd_set (argc - optind - 1, argv + optind + 1);
+      else if (! strcmp (argv[optind], "clear"))
+        cmd_clear ();
+
+      fseek (f, 0, SEEK_SET);
+      fwrite (buffer, sizeof (buffer), 1, f);
+    }
+  fclose (f);
+
+  return 0;
+}

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-13  7:07 [PATCH] Save/Load environment variable support Bean
@ 2008-06-14 18:47 ` Robert Millan
  2008-06-14 19:03   ` Bean
  2008-06-14 19:30 ` Robert Millan
  1 sibling, 1 reply; 18+ messages in thread
From: Robert Millan @ 2008-06-14 18:47 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Jun 13, 2008 at 03:07:54PM +0800, Bean wrote:
> Hi,
> 
> I separate the save/load environment variable function from my
> previous patch on environment block. It contains the command
> save_env/load_env/list_env and tool grub-editenv, but without the
> kernel patch.
> -- 
> Bean

> 
> diff --git a/commands/loadenv.c b/commands/loadenv.c
> new file mode 100755
> index 0000000..970baf3
> --- /dev/null
> +++ b/commands/loadenv.c
> @@ -0,0 +1,250 @@
> +/* loadenv.c - command to load/save environment variable.  */

Is this useful as a standalone command?  If we're in a stage in which commands
can be executed, the same effect could be archieved with the "." command on
a grub.cfg-like formatted file?

IIRC you explained that this feature could be useful as the basis for
findroot style search, or to override existing variables like "root", "prefix"
or "default".  In both cases (if I understood correctly) you want it to be run
automaticaly as the init routine for your module.

However if your code is small enough, maybe it could replace the existing
use of grub_prefix (I commented this on the other mail), thereby reducing
kernel size and making it preferable to be part of kernel than a separate
module.  Do you think that's possible?

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What good is a phone call… if you are unable to speak?
(as seen on /.)



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-14 18:47 ` Robert Millan
@ 2008-06-14 19:03   ` Bean
  2008-06-14 19:20     ` Robert Millan
  0 siblings, 1 reply; 18+ messages in thread
From: Bean @ 2008-06-14 19:03 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Jun 15, 2008 at 2:47 AM, Robert Millan <rmh@aybabtu.com> wrote:
> On Fri, Jun 13, 2008 at 03:07:54PM +0800, Bean wrote:
>> Hi,
>>
>> I separate the save/load environment variable function from my
>> previous patch on environment block. It contains the command
>> save_env/load_env/list_env and tool grub-editenv, but without the
>> kernel patch.
>> --
>> Bean
>
>>
>> diff --git a/commands/loadenv.c b/commands/loadenv.c
>> new file mode 100755
>> index 0000000..970baf3
>> --- /dev/null
>> +++ b/commands/loadenv.c
>> @@ -0,0 +1,250 @@
>> +/* loadenv.c - command to load/save environment variable.  */
>
> Is this useful as a standalone command?  If we're in a stage in which commands
> can be executed, the same effect could be archieved with the "." command on
> a grub.cfg-like formatted file?
>
> IIRC you explained that this feature could be useful as the basis for
> findroot style search, or to override existing variables like "root", "prefix"
> or "default".  In both cases (if I understood correctly) you want it to be run
> automaticaly as the init routine for your module.
>
> However if your code is small enough, maybe it could replace the existing
> use of grub_prefix (I commented this on the other mail), thereby reducing
> kernel size and making it preferable to be part of kernel than a separate
> module.  Do you think that's possible?

Hi,

Yes, this is a standalone command, it's used to support persistent
variable. For example, we can archive the result of savedefault using
the following command:

load_env

menuentry aa {
  save_env default
}

load_env loads the environment variable from $prefix/grubenv, and
save_env save selected variable to it. grubenv contain a environment
block, so that we can manage it using grub-editenv, just like the
environment block in the kernel.

-- 
Bean



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-14 19:03   ` Bean
@ 2008-06-14 19:20     ` Robert Millan
  2008-06-14 19:28       ` Bean
  0 siblings, 1 reply; 18+ messages in thread
From: Robert Millan @ 2008-06-14 19:20 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Jun 15, 2008 at 03:03:43AM +0800, Bean wrote:
> 
> Hi,
> 
> Yes, this is a standalone command, it's used to support persistent
> variable. For example, we can archive the result of savedefault using
> the following command:
> 
> load_env
> 
> menuentry aa {
>   save_env default
> }
> 
> load_env loads the environment variable from $prefix/grubenv, and
> save_env save selected variable to it. grubenv contain a environment
> block, so that we can manage it using grub-editenv, just like the
> environment block in the kernel.

Sounds interesting.. does the 8 kiB size assure us that we won't have any
trouble with filesystems when writing to it?

Also, which parts of this would be reused by findroot?

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What good is a phone call… if you are unable to speak?
(as seen on /.)



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-14 19:20     ` Robert Millan
@ 2008-06-14 19:28       ` Bean
  0 siblings, 0 replies; 18+ messages in thread
From: Bean @ 2008-06-14 19:28 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Jun 15, 2008 at 3:20 AM, Robert Millan <rmh@aybabtu.com> wrote:
> On Sun, Jun 15, 2008 at 03:03:43AM +0800, Bean wrote:
>>
>> Hi,
>>
>> Yes, this is a standalone command, it's used to support persistent
>> variable. For example, we can archive the result of savedefault using
>> the following command:
>>
>> load_env
>>
>> menuentry aa {
>>   save_env default
>> }
>>
>> load_env loads the environment variable from $prefix/grubenv, and
>> save_env save selected variable to it. grubenv contain a environment
>> block, so that we can manage it using grub-editenv, just like the
>> environment block in the kernel.
>
> Sounds interesting.. does the 8 kiB size assure us that we won't have any
> trouble with filesystems when writing to it?

I first read from the disk, compare content, then write back. If it's
tail packing by the file system, it would fail at the compare stage.

>
> Also, which parts of this would be reused by findroot?

No parts is shared by findroot. Actually, findroot only work on
variable, whose value is fetched in main.c.

-- 
Bean



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-13  7:07 [PATCH] Save/Load environment variable support Bean
  2008-06-14 18:47 ` Robert Millan
@ 2008-06-14 19:30 ` Robert Millan
  2008-06-14 19:44   ` Bean
  1 sibling, 1 reply; 18+ messages in thread
From: Robert Millan @ 2008-06-14 19:30 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Jun 13, 2008 at 03:07:54PM +0800, Bean wrote:
>  # Misc.
> -pkglib_MODULES += gzio.mod elf.mod
> +pkglib_MODULES += gzio.mod elf.mod findroot.mod
>  
> [...]
> +# For findroot.mod.
> +findroot_mod_SOURCES = kern/findroot.c
> +findroot_mod_CFLAGS = $(COMMON_CFLAGS)
> +findroot_mod_LDFLAGS = $(COMMON_LDFLAGS)

Some findroot bits were mixed up in the patch.

> +/* Names of important environment variables.  */
> +#define GRUB_ENVBLK_RDIR	"rdir"
> +#define GRUB_ENVBLK_UUID	"uuid"
> +#define GRUB_ENVBLK_LABEL	"label"
> +#define GRUB_ENVBLK_IDFILE	"idfile"

I'd prefer if the envblk part was agnostic about which variables have a
meaning.

> +++ b/util/envblk.c
> @@ -0,0 +1,171 @@
> +/* envblk.c - Common function for environment block.  */
> [...]
> +
> +#ifdef GRUB_UTIL

Files that are meant to be used both by grub and util are usually put in
the non-util dir (I'm not sure which non-util dir would fit, though, as it
depends on what you want to do next).

> +#include <string.h>
> +
> +#define grub_strlen	strlen
> +#define grub_strcpy	strcpy
> +#define grub_strchr	strchr
> +#define grub_memcmp	memcmp
> +#define grub_memcpy	memcpy

Uhm can we avoid this?  The rest of non-util code just calls the grub_*
functions (linking with kern/misc.c in this case).

> +grub_envblk_t
> +grub_envblk_find (char *buf)
> +{
> +  grub_uint32_t *pd;
> +  int len;
> +
> +  pd = (grub_uint32_t *) buf;
> +
> +  for (len = GRUB_ENVBLK_MAXLEN - 6; len > 0; len -= 4, pd++)
> +    if (*pd == GRUB_ENVBLK_SIGNATURE)

I wonder if this would be dangerous when run on files where env block
presence is optional, like core.img (though we can always think about this
later when that option is added).

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What good is a phone call… if you are unable to speak?
(as seen on /.)



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-14 19:30 ` Robert Millan
@ 2008-06-14 19:44   ` Bean
  2008-06-15 13:25     ` Robert Millan
  0 siblings, 1 reply; 18+ messages in thread
From: Bean @ 2008-06-14 19:44 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Jun 15, 2008 at 3:30 AM, Robert Millan <rmh@aybabtu.com> wrote:
> On Fri, Jun 13, 2008 at 03:07:54PM +0800, Bean wrote:
>>  # Misc.
>> -pkglib_MODULES += gzio.mod elf.mod
>> +pkglib_MODULES += gzio.mod elf.mod findroot.mod
>>
>> [...]
>> +# For findroot.mod.
>> +findroot_mod_SOURCES = kern/findroot.c
>> +findroot_mod_CFLAGS = $(COMMON_CFLAGS)
>> +findroot_mod_LDFLAGS = $(COMMON_LDFLAGS)
>
> Some findroot bits were mixed up in the patch.

Oh, I forget to remove them.

>
>> +/* Names of important environment variables.  */
>> +#define GRUB_ENVBLK_RDIR     "rdir"
>> +#define GRUB_ENVBLK_UUID     "uuid"
>> +#define GRUB_ENVBLK_LABEL    "label"
>> +#define GRUB_ENVBLK_IDFILE   "idfile"
>
> I'd prefer if the envblk part was agnostic about which variables have a
> meaning.
>
>> +++ b/util/envblk.c
>> @@ -0,0 +1,171 @@
>> +/* envblk.c - Common function for environment block.  */
>> [...]
>> +
>> +#ifdef GRUB_UTIL
>
> Files that are meant to be used both by grub and util are usually put in
> the non-util dir (I'm not sure which non-util dir would fit, though, as it
> depends on what you want to do next).
>
>> +#include <string.h>
>> +
>> +#define grub_strlen  strlen
>> +#define grub_strcpy  strcpy
>> +#define grub_strchr  strchr
>> +#define grub_memcmp  memcmp
>> +#define grub_memcpy  memcpy
>
> Uhm can we avoid this?  The rest of non-util code just calls the grub_*
> functions (linking with kern/misc.c in this case).

I fount out that if I use grub_*, I end up adding quite a few of extra
modules that serve no purpose other than string manipulation. Perhaps
we should separate those routines from kern/misc.c ?

>
>> +grub_envblk_t
>> +grub_envblk_find (char *buf)
>> +{
>> +  grub_uint32_t *pd;
>> +  int len;
>> +
>> +  pd = (grub_uint32_t *) buf;
>> +
>> +  for (len = GRUB_ENVBLK_MAXLEN - 6; len > 0; len -= 4, pd++)
>> +    if (*pd == GRUB_ENVBLK_SIGNATURE)
>
> I wonder if this would be dangerous when run on files where env block
> presence is optional, like core.img (though we can always think about this
> later when that option is added).

Yes, perhaps we should store a pointer to environment block so that we
don't need to scan for it.

-- 
Bean



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-14 19:44   ` Bean
@ 2008-06-15 13:25     ` Robert Millan
  2008-06-15 14:09       ` Bean
  0 siblings, 1 reply; 18+ messages in thread
From: Robert Millan @ 2008-06-15 13:25 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Jun 15, 2008 at 03:44:56AM +0800, Bean wrote:
> >> +#define grub_strlen  strlen
> >> +#define grub_strcpy  strcpy
> >> +#define grub_strchr  strchr
> >> +#define grub_memcmp  memcmp
> >> +#define grub_memcpy  memcpy
> >
> > Uhm can we avoid this?  The rest of non-util code just calls the grub_*
> > functions (linking with kern/misc.c in this case).
> 
> I fount out that if I use grub_*, I end up adding quite a few of extra
> modules that serve no purpose other than string manipulation. Perhaps
> we should separate those routines from kern/misc.c ?

Which modules?  If these functions are part of kernel, they shouldn't be
dragging modules in, AFAICT.

> >> +  for (len = GRUB_ENVBLK_MAXLEN - 6; len > 0; len -= 4, pd++)
> >> +    if (*pd == GRUB_ENVBLK_SIGNATURE)
> >
> > I wonder if this would be dangerous when run on files where env block
> > presence is optional, like core.img (though we can always think about this
> > later when that option is added).
> 
> Yes, perhaps we should store a pointer to environment block so that we
> don't need to scan for it.

If the env block could have variable length (in core.img, not the filesystem
one), then maybe a zero-length block could be embedded unconditionaly.

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What good is a phone call… if you are unable to speak?
(as seen on /.)



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-15 13:25     ` Robert Millan
@ 2008-06-15 14:09       ` Bean
  2008-06-30 13:06         ` Bean
  0 siblings, 1 reply; 18+ messages in thread
From: Bean @ 2008-06-15 14:09 UTC (permalink / raw)
  To: The development of GRUB 2

On Sun, Jun 15, 2008 at 9:25 PM, Robert Millan <rmh@aybabtu.com> wrote:
> On Sun, Jun 15, 2008 at 03:44:56AM +0800, Bean wrote:
>> >> +#define grub_strlen  strlen
>> >> +#define grub_strcpy  strcpy
>> >> +#define grub_strchr  strchr
>> >> +#define grub_memcmp  memcmp
>> >> +#define grub_memcpy  memcpy
>> >
>> > Uhm can we avoid this?  The rest of non-util code just calls the grub_*
>> > functions (linking with kern/misc.c in this case).
>>
>> I fount out that if I use grub_*, I end up adding quite a few of extra
>> modules that serve no purpose other than string manipulation. Perhaps
>> we should separate those routines from kern/misc.c ?
>
> Which modules?  If these functions are part of kernel, they shouldn't be
> dragging modules in, AFAICT.

Oh, I actually means the files, in kern/misc.c, there is reference to
other function, which requires other unrelated files to be included.

>
>> >> +  for (len = GRUB_ENVBLK_MAXLEN - 6; len > 0; len -= 4, pd++)
>> >> +    if (*pd == GRUB_ENVBLK_SIGNATURE)
>> >
>> > I wonder if this would be dangerous when run on files where env block
>> > presence is optional, like core.img (though we can always think about this
>> > later when that option is added).
>>
>> Yes, perhaps we should store a pointer to environment block so that we
>> don't need to scan for it.
>
> If the env block could have variable length (in core.img, not the filesystem
> one), then maybe a zero-length block could be embedded unconditionaly.

It can have zero length. The len variable is used to count the distant
to the end of buffer.

-- 
Bean



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-15 14:09       ` Bean
@ 2008-06-30 13:06         ` Bean
  2008-07-01 15:54           ` Robert Millan
  0 siblings, 1 reply; 18+ messages in thread
From: Bean @ 2008-06-30 13:06 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 402 bytes --]

Hi,

This is the new patch, some changes:

1, envblk.h, remove GRUB_ENVBLK_RDIR and the like, they're not needed
in this patch.
2, util/envblk.c, use grub_* function for string manipulation.
3, commands/loadenv.c, use grub_disk_read/grub_disk_write to
read/write disk, the problem of lower level api is that they don't
update the cache.

If there is no problem, I'd like to commit this soon.

-- 
Bean

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: envblk_4.diff --]
[-- Type: text/x-diff; name=envblk_4.diff, Size: 19892 bytes --]

diff --git a/commands/loadenv.c b/commands/loadenv.c
new file mode 100755
index 0000000..7359683
--- /dev/null
+++ b/commands/loadenv.c
@@ -0,0 +1,257 @@
+/* loadenv.c - command to load/save environment variable.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/arg.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/envblk.h>
+#include <grub/partition.h>
+
+static const struct grub_arg_option options[] =
+  {
+    {"file", 'f', 0, "specify filename", 0, ARG_TYPE_PATHNAME},
+    {0, 0, 0, 0, 0, 0}
+  };
+
+char buffer[GRUB_ENVBLK_MAXLEN];
+grub_envblk_t envblk;
+
+static grub_file_t
+read_envblk_file (char *filename, void NESTED_FUNC_ATTR read_hook (grub_disk_addr_t sector, unsigned offset, unsigned length))
+{
+  char *buf = 0;
+  grub_file_t file;
+
+  if (! filename)
+    {
+      char *prefix;
+
+      prefix = grub_env_get ("prefix");
+      if (prefix)
+        {
+          int len;
+
+          len = grub_strlen (prefix);
+          buf = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG));
+          grub_strcpy (buf, prefix);
+          buf[len] = '/';
+          grub_strcpy (buf + len + 1, GRUB_ENVBLK_DEFCFG);
+          filename = buf;
+        }
+      else
+        {
+          grub_error (GRUB_ERR_FILE_NOT_FOUND, "prefix is not found");
+          return 0;
+        }
+    }
+
+  file = grub_file_open (filename);
+  grub_free (buf);
+  if (! file)
+    return 0;
+
+  if (read_hook)
+    {
+      if (! file->device->disk)
+        {
+          grub_file_close (file);
+          grub_error (GRUB_ERR_BAD_DEVICE,
+                      "this command is available only for disk devices.");
+          return 0;
+        }
+      file->read_hook = read_hook;
+    }
+
+  if (grub_file_read (file, buffer, GRUB_ENVBLK_MAXLEN) != GRUB_ENVBLK_MAXLEN)
+    {
+      grub_file_close (file);
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "file too short");
+      return 0;
+    }
+
+  envblk = grub_envblk_find (buffer);
+  if (! envblk)
+    {
+      grub_file_close (file);
+      grub_error (GRUB_ERR_BAD_FILE_TYPE, "environment block not found");
+      return 0;
+    }
+
+  return file;
+}
+
+static grub_err_t
+grub_cmd_load_env (struct grub_arg_list *state,
+                   int argc __attribute__ ((unused)), char **args __attribute__ ((unused)))
+
+{
+  grub_file_t file;
+
+  auto int hook (char *name, char *value);
+  int hook (char *name, char *value)
+    {
+      grub_env_set (name, value);
+
+      return 0;
+    }
+
+  file = read_envblk_file ((state[0].set) ? state[0].arg : 0, 0);
+  if (! file)
+    return grub_errno;
+
+  grub_file_close (file);
+
+  grub_envblk_iterate (envblk, hook);
+
+  return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_list_env (struct grub_arg_list *state,
+                   int argc __attribute__ ((unused)), char **args __attribute__ ((unused)))
+{
+  grub_file_t file;
+
+  auto int hook (char *name, char *value);
+  int hook (char *name, char *value)
+    {
+      grub_printf ("%s=%s\n", name, value);
+
+      return 0;
+    }
+
+  file = read_envblk_file ((state[0].set) ? state[0].arg : 0, 0);
+  if (! file)
+    return grub_errno;
+
+  grub_file_close (file);
+
+  grub_envblk_iterate (envblk, hook);
+
+  return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_save_env (struct grub_arg_list *state, int argc, char **args)
+{
+  grub_file_t file;
+  grub_disk_t disk;
+  grub_disk_addr_t addr[GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS];
+  char buf[GRUB_DISK_SECTOR_SIZE];
+  grub_disk_addr_t part_start = 0;
+  int num = 0;
+
+  auto void NESTED_FUNC_ATTR hook (grub_disk_addr_t sector, unsigned offset,
+                                   unsigned length);
+
+  void NESTED_FUNC_ATTR hook (grub_disk_addr_t sector,
+                              unsigned offset, unsigned length)
+    {
+      if ((offset != 0) || (length != GRUB_DISK_SECTOR_SIZE))
+        return;
+
+      if (num < (GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS))
+        addr[num++] = sector;
+    }
+
+  if (! argc)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "No variable is specified");
+
+  file = read_envblk_file ((state[0].set) ? state[0].arg : 0, hook);
+  if (! file)
+    return grub_errno;
+
+  file->read_hook = 0;
+
+  if (num != GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS)
+    {
+      grub_error (GRUB_ERR_BAD_DEVICE, "invalid blocklist");
+      goto quit;
+    }
+
+  disk = file->device->disk;
+  if (disk->partition)
+    part_start = grub_partition_get_start (disk->partition);
+
+  for (num = 0; num < (GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS); num++)
+    {
+      if (grub_disk_read (disk, addr[num] - part_start, 0,
+                          GRUB_DISK_SECTOR_SIZE,  buf))
+        goto quit;
+
+      if (grub_memcmp (&buffer[num << GRUB_DISK_SECTOR_BITS], buf,
+                       GRUB_DISK_SECTOR_SIZE))
+        {
+          grub_error (GRUB_ERR_BAD_DEVICE, "invalid blocklist");
+          goto quit;
+        }
+    }
+
+  while (argc)
+    {
+      char *value;
+
+      value = grub_env_get (args[0]);
+      if (value)
+        {
+          if (grub_envblk_insert (envblk, args[0], value))
+            {
+              grub_error (GRUB_ERR_BAD_ARGUMENT, "environment block too small");
+              goto quit;
+            }
+        }
+
+      argc--;
+      args++;
+    }
+
+  for (num = 0; num < (GRUB_ENVBLK_MAXLEN >> GRUB_DISK_SECTOR_BITS); num++)
+    if (grub_disk_write (disk, addr[num] - part_start, 0,
+                         GRUB_DISK_SECTOR_SIZE,
+                         &buffer[num << GRUB_DISK_SECTOR_BITS]))
+      goto quit;
+
+quit:
+  grub_file_close (file);
+
+  return grub_errno;
+}
+
+GRUB_MOD_INIT(loadenv)
+{
+  (void) mod;
+  grub_register_command ("load_env", grub_cmd_load_env, GRUB_COMMAND_FLAG_BOTH,
+			 "load_env [-f FILE]", "Load variables from environment block file.", options);
+  grub_register_command ("list_env", grub_cmd_list_env, GRUB_COMMAND_FLAG_BOTH,
+			 "list_env [-f FILE]", "List variables from environment block file.", options);
+  grub_register_command ("save_env", grub_cmd_save_env, GRUB_COMMAND_FLAG_BOTH,
+			 "save_env [-f FILE] variable_name [...]", "Save variables to environment block file.", options);
+}
+
+GRUB_MOD_FINI(loadenv)
+{
+  grub_unregister_command ("load_env");
+  grub_unregister_command ("list_env");
+  grub_unregister_command ("save_env");
+}
diff --git a/conf/common.rmk b/conf/common.rmk
index f34a2bf..ecb8e04 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -94,6 +94,11 @@ grub_fstest_init.c: grub_fstest_init.lst $(filter-out grub_fstest_init.c,$(grub_
 	rm -f $@; sh $(srcdir)/geninit.sh $< $(filter %.c,$^) > $@
 DISTCLEANFILES += grub_fstest_init.c
 
+# for grub-editenv
+bin_UTILITIES += grub-editenv
+grub_editenv_SOURCES = util/grub-editenv.c util/envblk.c util/misc.c kern/misc.c kern/err.c
+CLEANFILES += grub-editenv
+
 # For update-grub
 update-grub: util/update-grub.in config.status
 	./config.status --file=$@:$<
@@ -282,7 +287,7 @@ pkglib_MODULES += hello.mod boot.mod terminal.mod ls.mod	\
 	cmp.mod cat.mod help.mod font.mod search.mod		\
 	loopback.mod fs_uuid.mod configfile.mod echo.mod	\
 	terminfo.mod test.mod blocklist.mod hexdump.mod		\
-	read.mod sleep.mod
+	read.mod sleep.mod loadenv.mod
 
 # For hello.mod.
 hello_mod_SOURCES = hello/hello.c
@@ -369,6 +374,21 @@ hexdump_mod_SOURCES = commands/hexdump.c
 hexdump_mod_CFLAGS = $(COMMON_CFLAGS)
 hexdump_mod_LDFLAGS = $(COMMON_LDFLAGS)
 
+# For read.mod.
+read_mod_SOURCES = commands/read.c
+read_mod_CFLAGS = $(COMMON_CFLAGS)
+read_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For sleep.mod.
+sleep_mod_SOURCES = commands/sleep.c
+sleep_mod_CFLAGS = $(COMMON_CFLAGS)
+sleep_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
+# For loadenv.mod.
+loadenv_mod_SOURCES = commands/loadenv.c util/envblk.c
+loadenv_mod_CFLAGS = $(COMMON_CFLAGS)
+loadenv_mod_LDFLAGS = $(COMMON_LDFLAGS)
+
 # Misc.
 pkglib_MODULES += gzio.mod elf.mod
 
@@ -381,13 +401,3 @@ elf_mod_LDFLAGS = $(COMMON_LDFLAGS)
 gzio_mod_SOURCES = io/gzio.c
 gzio_mod_CFLAGS = $(COMMON_CFLAGS)
 gzio_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
-# For read.mod.
-read_mod_SOURCES = commands/read.c
-read_mod_CFLAGS = $(COMMON_CFLAGS)
-read_mod_LDFLAGS = $(COMMON_LDFLAGS)
-
-# For sleep.mod.
-sleep_mod_SOURCES = commands/sleep.c
-sleep_mod_CFLAGS = $(COMMON_CFLAGS)
-sleep_mod_LDFLAGS = $(COMMON_LDFLAGS)
diff --git a/include/grub/envblk.h b/include/grub/envblk.h
new file mode 100755
index 0000000..5c1157e
--- /dev/null
+++ b/include/grub/envblk.h
@@ -0,0 +1,45 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#ifndef GRUB_ENVBLK_HEADER
+#define GRUB_ENVBLK_HEADER	1
+
+#define GRUB_ENVBLK_SIGNATURE	0x764e6547	/* GeNv  */
+
+#define GRUB_ENVBLK_MAXLEN	8192
+
+#define GRUB_ENVBLK_DEFCFG	"grubenv"
+
+#ifndef ASM_FILE
+
+struct grub_envblk
+{
+  grub_uint32_t signature;
+  grub_uint16_t length;
+  char data[0];
+} __attribute__ ((packed));
+typedef struct grub_envblk *grub_envblk_t;
+
+grub_envblk_t grub_envblk_find (char *buf);
+int grub_envblk_insert (grub_envblk_t envblk, char *name, char *value);
+void grub_envblk_delete (grub_envblk_t envblk, char *name);
+void grub_envblk_iterate (grub_envblk_t envblk, int hook (char *name, char *value));
+
+#endif
+
+#endif /* ! GRUB_ENVBLK_HEADER */
diff --git a/util/envblk.c b/util/envblk.c
new file mode 100755
index 0000000..9cea7d6
--- /dev/null
+++ b/util/envblk.c
@@ -0,0 +1,156 @@
+/* envblk.c - Common function for environment block.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008  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/>.
+ */
+
+#include <config.h>
+#include <grub/types.h>
+#include <grub/envblk.h>
+#include <grub/misc.h>
+
+grub_envblk_t
+grub_envblk_find (char *buf)
+{
+  grub_uint32_t *pd;
+  int len;
+
+  pd = (grub_uint32_t *) buf;
+
+  for (len = GRUB_ENVBLK_MAXLEN - 6; len > 0; len -= 4, pd++)
+    if (*pd == GRUB_ENVBLK_SIGNATURE)
+      {
+        grub_envblk_t p;
+
+        p = (grub_envblk_t) pd;
+        if (p->length <= len)
+          return p;
+      }
+
+  return 0;
+}
+
+int
+grub_envblk_insert (grub_envblk_t envblk, char *name, char *value)
+{
+  char *p, *pend;
+  char *found = 0;
+  int nl;
+
+  nl = grub_strlen (name);
+  p = envblk->data;
+  pend = p + envblk->length;
+
+  while (*p)
+    {
+      if ((! found) && (! grub_memcmp (name, p, nl)) && (p[nl] == '='))
+        found = p + nl + 1;
+
+      p += grub_strlen (p) + 1;
+      if (p >= pend)
+        return 1;
+    }
+
+  if (found)
+    {
+      int len1, len2;
+
+      len1 = grub_strlen (found);
+      len2 = grub_strlen (value);
+      if ((p - envblk->data) + 1 - len1 + len2 > envblk->length)
+        return 1;
+
+      grub_memcpy (found + len2 + 1, found + len1 + 1, (p - found) - len1);
+      grub_strcpy (found, value);
+    }
+  else
+    {
+      int len2 = grub_strlen (value);
+
+      if ((p - envblk->data) + nl + 1 + len2 + 2 > envblk->length)
+        return 1;
+
+      grub_strcpy (p, name);
+      p[nl] = '=';
+      grub_strcpy (p + nl + 1, value);
+      p[nl + 1 + len2 + 1] = 0;
+    }
+
+  return 0;
+}
+
+void
+grub_envblk_delete (grub_envblk_t envblk, char *name)
+{
+  char *p, *pend;
+  char *found = 0;
+  int nl;
+
+  nl = grub_strlen (name);
+  p = envblk->data;
+  pend = p + envblk->length;
+
+  while (*p)
+    {
+      if ((! found) && (! grub_memcmp (name, p, nl)) && (p[nl] == '='))
+        found = p;
+
+      p += grub_strlen (p) + 1;
+      if (p >= pend)
+        return;
+    }
+
+  if (found)
+    {
+      int len;
+
+      len = grub_strlen (found);
+      grub_memcpy (found, found + len + 1, (p - found) - len);
+    }
+}
+
+void
+grub_envblk_iterate (grub_envblk_t envblk,
+                     int hook (char *name, char *value))
+{
+  char *p, *pend;
+
+  p = envblk->data;
+  pend = p + envblk->length;
+
+  while (*p)
+    {
+      char *v;
+      int r;
+
+      v = grub_strchr (p, '=');
+      if (v)
+        {
+          *v = 0;
+          r = hook (p, v + 1);
+          *v = '=';
+        }
+      else
+        r = hook (p, "");
+
+      if (r)
+        break;
+
+      p += grub_strlen (p) + 1;
+      if (p >= pend)
+        break;
+    }
+}
diff --git a/util/grub-editenv.c b/util/grub-editenv.c
new file mode 100755
index 0000000..b2b2d67
--- /dev/null
+++ b/util/grub-editenv.c
@@ -0,0 +1,258 @@
+/* grub-editenv.c - tool to edit environment block.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008 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/>.
+ */
+
+#include <config.h>
+#include <grub/types.h>
+#include <grub/util/misc.h>
+
+#include <grub/envblk.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+void
+grub_putchar (int c)
+{
+  putchar (c);
+}
+
+void
+grub_refresh (void)
+{
+  fflush (stdout);
+}
+
+void *
+grub_term_get_current (void)
+{
+  return 0;
+}
+
+int
+grub_getkey (void)
+{
+  return 0;
+}
+
+char *
+grub_env_get (const char *name __attribute__ ((unused)))
+{
+  return NULL;
+}
+
+static struct option options[] = {
+  {"help", no_argument, 0, 'h'},
+  {"version", no_argument, 0, 'V'},
+  {"verbose", no_argument, 0, 'v'},
+  {0, 0, 0, 0}
+};
+
+char buffer[GRUB_ENVBLK_MAXLEN];
+grub_envblk_t envblk;
+
+static void
+usage (int status)
+{
+  if (status)
+    fprintf (stderr, "Try ``grub-editenv --help'' for more information.\n");
+  else
+    printf ("\
+Usage: grub-editenv [OPTIONS] FILENAME COMMAND\n\
+\n\
+Tool to edit environment block.\n\
+\nCommands:\n\
+  create                    create a blank environment block file\n\
+  info                      show information about the environment block\n\
+  list                      list the current variables\n\
+  set [name=value] ...      change/delete variables\n\
+  clear                     delete all variables\n\
+\nOptions:\n\
+  -h, --help                display this message and exit\n\
+  -V, --version             print version information and exit\n\
+  -v, --verbose             print verbose messages\n\
+\n\
+Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
+
+  exit (status);
+}
+
+int
+create_envblk_file (char *name)
+{
+  FILE *f;
+  grub_envblk_t p;
+
+  f = fopen (name, "wb");
+  if (! f)
+    return 1;
+
+  /* Just in case OS don't save 0s.  */
+  memset (buffer, -1, sizeof (buffer));
+
+  p = (grub_envblk_t) &buffer[0];
+  p->signature = GRUB_ENVBLK_SIGNATURE;
+  p->length = sizeof (buffer) - sizeof (struct grub_envblk);
+  p->data[0] = p->data[1] = 0;
+
+  fwrite (buffer, sizeof (buffer), 1, f);
+
+  fclose (f);
+  return 0;
+}
+
+FILE *
+open_envblk_file (char *name)
+{
+  FILE *f;
+
+  f = fopen (name, "r+b");
+  if (! f)
+    grub_util_error ("Can\'t open file %s", name);
+
+  if (fread (buffer, 1, sizeof (buffer), f) != sizeof (buffer))
+    grub_util_error ("The envblk file is too short");
+
+  envblk = grub_envblk_find (buffer);
+  if (! envblk)
+    grub_util_error ("Can\'t find environment block");
+
+  return f;
+}
+
+static void
+cmd_info (void)
+{
+  printf ("Envblk offset: %d\n", envblk->data - buffer);
+  printf ("Envblk length: %d\n", envblk->length);
+}
+
+static void
+cmd_list (void)
+{
+  auto int hook (char *name, char *value);
+  int hook (char *name, char *value)
+    {
+      printf ("%s=%s\n", name, value);
+      return 0;
+    }
+
+  grub_envblk_iterate (envblk, hook);
+}
+
+static void
+cmd_set (int argc, char *argv[])
+{
+  while (argc)
+    {
+      char *p;
+
+      p = strchr (argv[0], '=');
+      if (! p)
+        grub_util_error ("Invalid parameter");
+
+      *(p++) = 0;
+
+      if (*p)
+        {
+          if (grub_envblk_insert (envblk, argv[0], p))
+            grub_util_error ("Environment block too small");
+        }
+      else
+        grub_envblk_delete (envblk, argv[0]);
+
+      argc--;
+      argv++;
+    }
+}
+
+static void
+cmd_clear (void)
+{
+  envblk->data[0] = envblk->data[1] = 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  FILE *f;
+
+  progname = "grub-editenv";
+
+  /* Check for options.  */
+  while (1)
+    {
+      int c = getopt_long (argc, argv, "hVv", options, 0);
+
+      if (c == -1)
+	break;
+      else
+	switch (c)
+	  {
+	  case 'h':
+	    usage (0);
+	    break;
+
+	  case 'V':
+	    printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
+	    return 0;
+
+	  case 'v':
+	    verbosity++;
+	    break;
+
+	  default:
+	    usage (1);
+	    break;
+	  }
+    }
+
+  /* Obtain PATH.  */
+  if (optind + 1 >= argc)
+    {
+      fprintf (stderr, "Not enough parameter.\n");
+      usage (1);
+    }
+
+  if (! strcmp (argv[optind + 1], "create"))
+    return create_envblk_file (argv[optind]);
+
+  f = open_envblk_file (argv[optind]);
+
+  optind++;
+  if (! strcmp (argv[optind], "info"))
+    cmd_info ();
+  else if (! strcmp (argv[optind], "list"))
+    cmd_list ();
+  else
+    {
+      if (! strcmp (argv[optind], "set"))
+        cmd_set (argc - optind - 1, argv + optind + 1);
+      else if (! strcmp (argv[optind], "clear"))
+        cmd_clear ();
+
+      fseek (f, 0, SEEK_SET);
+      fwrite (buffer, sizeof (buffer), 1, f);
+    }
+  fclose (f);
+
+  return 0;
+}

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-06-30 13:06         ` Bean
@ 2008-07-01 15:54           ` Robert Millan
  2008-07-02  7:39             ` Bean
  0 siblings, 1 reply; 18+ messages in thread
From: Robert Millan @ 2008-07-01 15:54 UTC (permalink / raw)
  To: The development of GRUB 2

On Mon, Jun 30, 2008 at 09:06:28PM +0800, Bean wrote:
> Hi,
> 
> This is the new patch, some changes:
> 
> 1, envblk.h, remove GRUB_ENVBLK_RDIR and the like, they're not needed
> in this patch.
> 2, util/envblk.c, use grub_* function for string manipulation.
> 3, commands/loadenv.c, use grub_disk_read/grub_disk_write to
> read/write disk, the problem of lower level api is that they don't
> update the cache.
> 
> If there is no problem, I'd like to commit this soon.

Fine with me!

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What good is a phone call… if you are unable to speak?
(as seen on /.)



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-07-01 15:54           ` Robert Millan
@ 2008-07-02  7:39             ` Bean
  2008-07-03 18:04               ` Marco Gerards
  0 siblings, 1 reply; 18+ messages in thread
From: Bean @ 2008-07-02  7:39 UTC (permalink / raw)
  To: The development of GRUB 2

On Tue, Jul 1, 2008 at 11:54 PM, Robert Millan <rmh@aybabtu.com> wrote:
> On Mon, Jun 30, 2008 at 09:06:28PM +0800, Bean wrote:
>> Hi,
>>
>> This is the new patch, some changes:
>>
>> 1, envblk.h, remove GRUB_ENVBLK_RDIR and the like, they're not needed
>> in this patch.
>> 2, util/envblk.c, use grub_* function for string manipulation.
>> 3, commands/loadenv.c, use grub_disk_read/grub_disk_write to
>> read/write disk, the problem of lower level api is that they don't
>> update the cache.
>>
>> If there is no problem, I'd like to commit this soon.
>
> Fine with me!

Committed.

-- 
Bean



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-07-02  7:39             ` Bean
@ 2008-07-03 18:04               ` Marco Gerards
  2008-07-03 18:09                 ` Pavel Roskin
  0 siblings, 1 reply; 18+ messages in thread
From: Marco Gerards @ 2008-07-03 18:04 UTC (permalink / raw)
  To: The development of GRUB 2

Bean <bean123ch@gmail.com> writes:

> On Tue, Jul 1, 2008 at 11:54 PM, Robert Millan <rmh@aybabtu.com> wrote:
>> On Mon, Jun 30, 2008 at 09:06:28PM +0800, Bean wrote:
>>> Hi,
>>>
>>> This is the new patch, some changes:
>>>
>>> 1, envblk.h, remove GRUB_ENVBLK_RDIR and the like, they're not needed
>>> in this patch.
>>> 2, util/envblk.c, use grub_* function for string manipulation.
>>> 3, commands/loadenv.c, use grub_disk_read/grub_disk_write to
>>> read/write disk, the problem of lower level api is that they don't
>>> update the cache.
>>>
>>> If there is no problem, I'd like to commit this soon.
>>
>> Fine with me!
>
> Committed.

Great!  Can you explain how it works?

--
Marco




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-07-03 18:04               ` Marco Gerards
@ 2008-07-03 18:09                 ` Pavel Roskin
  2008-07-03 20:11                   ` Bean
  2008-07-03 20:41                   ` Marco Gerards
  0 siblings, 2 replies; 18+ messages in thread
From: Pavel Roskin @ 2008-07-03 18:09 UTC (permalink / raw)
  To: The development of GRUB 2

On Thu, 2008-07-03 at 20:04 +0200, Marco Gerards wrote:

> Great!  Can you explain how it works?

Very good question.  It's not "discoverable".  I could not find way to
figure out that /boot/grub/grubenv is the default without looking at the
code.

load_env without arguments merely prints "error: file not found" without
telling which file it needs.  Help texts are silent about the defaults.
Many commands ignore extra arguments silently.  The whole code needs a
serious cleanup with end users in mind.

We also have too many commands regarding environment.  There is even
freebsd_loadenv, which should probably merged with load_env somehow.  Or
maybe not.  Maybe all native environment files should be handled with
one command, such as "env".

We also need mechanisms to implement "savedefault" functionality,
perhaps with easy examples.  Maybe update-grub should use it.

Anyway, to start using it, create the environment file: grub-editenv (by
the way, grub-env would be a better name):

grub-editenv /boot/grub/grubenv create
grub-editenv /boot/grub/grubenv set foo=bar

Now you can inspect it with "list_env", load it into environment with
"load_env" and save variables into it with "save_env".

-- 
Regards,
Pavel Roskin



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-07-03 18:09                 ` Pavel Roskin
@ 2008-07-03 20:11                   ` Bean
  2008-07-03 22:52                     ` Robert Millan
  2008-07-03 20:41                   ` Marco Gerards
  1 sibling, 1 reply; 18+ messages in thread
From: Bean @ 2008-07-03 20:11 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Jul 4, 2008 at 2:09 AM, Pavel Roskin <proski@gnu.org> wrote:
> On Thu, 2008-07-03 at 20:04 +0200, Marco Gerards wrote:
>
>> Great!  Can you explain how it works?
>
> Very good question.  It's not "discoverable".  I could not find way to
> figure out that /boot/grub/grubenv is the default without looking at the
> code.
>
> load_env without arguments merely prints "error: file not found" without
> telling which file it needs.  Help texts are silent about the defaults.
> Many commands ignore extra arguments silently.  The whole code needs a
> serious cleanup with end users in mind.

load_env would load /boot/grub/grubenv with no input, you can also
overwrite the default with -f parameter.

BTW, I think update-grub should create a new grubenv if it doesn't
exists, so that user won't see the file not found error.

>
> We also have too many commands regarding environment.  There is even
> freebsd_loadenv, which should probably merged with load_env somehow.  Or
> maybe not.  Maybe all native environment files should be handled with
> one command, such as "env".

freebsd_loadenv is used to load the hint file, which is plain text. It
also add the FreeBSD prefix so that they won't conflict with native
variables of grub2.

>
> We also need mechanisms to implement "savedefault" functionality,
> perhaps with easy examples.  Maybe update-grub should use it.
>
> Anyway, to start using it, create the environment file: grub-editenv (by
> the way, grub-env would be a better name):
>
> grub-editenv /boot/grub/grubenv create
> grub-editenv /boot/grub/grubenv set foo=bar
>
> Now you can inspect it with "list_env", load it into environment with
> "load_env" and save variables into it with "save_env".

Yes, this is the basic idea.

-- 
Bean



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-07-03 18:09                 ` Pavel Roskin
  2008-07-03 20:11                   ` Bean
@ 2008-07-03 20:41                   ` Marco Gerards
  2008-07-03 21:06                     ` Bean
  1 sibling, 1 reply; 18+ messages in thread
From: Marco Gerards @ 2008-07-03 20:41 UTC (permalink / raw)
  To: The development of GRUB 2

Pavel Roskin <proski@gnu.org> writes:

> On Thu, 2008-07-03 at 20:04 +0200, Marco Gerards wrote:
>
>> Great!  Can you explain how it works?
>
> Very good question.  It's not "discoverable".  I could not find way to
> figure out that /boot/grub/grubenv is the default without looking at the
> code.

Actually, I meant how it works technically.

--
Marco




^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-07-03 20:41                   ` Marco Gerards
@ 2008-07-03 21:06                     ` Bean
  0 siblings, 0 replies; 18+ messages in thread
From: Bean @ 2008-07-03 21:06 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Jul 4, 2008 at 4:41 AM, Marco Gerards <mgerards@xs4all.nl> wrote:
> Pavel Roskin <proski@gnu.org> writes:
>
>> On Thu, 2008-07-03 at 20:04 +0200, Marco Gerards wrote:
>>
>>> Great!  Can you explain how it works?
>>
>> Very good question.  It's not "discoverable".  I could not find way to
>> figure out that /boot/grub/grubenv is the default without looking at the
>> code.
>
> Actually, I meant how it works technically.

Hi,

It first reads the first 8192 bytes into memory, then, set read_hook
and do it again. Inside the hook, it records the sector location. It
then uses the location list to read from disk, and compare the result.
If they match, we assume it's the right one.

There are some consideration about the environment file. First, it
must be at least 8192 bytes long, this is used to avoid tail packing
in some fs. Then, we have the signature "GeNv", followed by the length
of the block. The signature doesn't need to the at the beginning, but
it has to been within the first 8192 byte, and dword aligned. This is
used to simplify the search function, also reduce the change of a
mismatch. The environment block consists of name=value strings,
terminated by an empty string.

The environment block can be embedded in other files, like core.img.
Then we can use grub-editenv, or save_env from grub console, to set
variable which can be used to locate root at runtime, like uuid, etc.
But this is the subject of another patch.

-- 
Bean



^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH] Save/Load environment variable support
  2008-07-03 20:11                   ` Bean
@ 2008-07-03 22:52                     ` Robert Millan
  0 siblings, 0 replies; 18+ messages in thread
From: Robert Millan @ 2008-07-03 22:52 UTC (permalink / raw)
  To: The development of GRUB 2

On Fri, Jul 04, 2008 at 04:11:07AM +0800, Bean wrote:
> 
> BTW, I think update-grub should create a new grubenv if it doesn't
> exists, so that user won't see the file not found error.

Would be interesting if update-grub added a "savedefault" blob to each
menuentry, and loaded the default afterwards (unless instructed otherwise
by the user).

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What good is a phone call… if you are unable to speak?
(as seen on /.)



^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2008-07-03 22:53 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-13  7:07 [PATCH] Save/Load environment variable support Bean
2008-06-14 18:47 ` Robert Millan
2008-06-14 19:03   ` Bean
2008-06-14 19:20     ` Robert Millan
2008-06-14 19:28       ` Bean
2008-06-14 19:30 ` Robert Millan
2008-06-14 19:44   ` Bean
2008-06-15 13:25     ` Robert Millan
2008-06-15 14:09       ` Bean
2008-06-30 13:06         ` Bean
2008-07-01 15:54           ` Robert Millan
2008-07-02  7:39             ` Bean
2008-07-03 18:04               ` Marco Gerards
2008-07-03 18:09                 ` Pavel Roskin
2008-07-03 20:11                   ` Bean
2008-07-03 22:52                     ` Robert Millan
2008-07-03 20:41                   ` Marco Gerards
2008-07-03 21:06                     ` Bean

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.