* [PATCH] Environment block support for grub2
@ 2008-05-30 20:27 Bean
2008-05-31 10:10 ` Robert Millan
0 siblings, 1 reply; 23+ messages in thread
From: Bean @ 2008-05-30 20:27 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 2238 bytes --]
Hi,
This patch add environment block support, which can be used to locate
root device using uuid or label.
The environment block occupied the space previously used to store
prefix. The structure is like this:
Magic numbe: "EvbK" (4 bytes)
Length of environment block (2 bytes)
null-ended name=value pairs, ended with an empty string.
The previous prefix is stored in variable rdir.
Different platform use grub_machine_get_envblk to return a pointer to
the name=value area of environment block. In main.c, it uses
grub_parse_envblk to walk through the list and assign values to
variables.
I also replace grub_machine_set_prefix with grub_machine_set_root. As
it seems strange to compute the prefix in grub_machine_set_prefix, and
then split it in grub_set_root_dev to get the root device. Now,
grub_machine_set_root set the root directly, and in grub_set_root_dev,
it uses root and rdir to generate the prefix.
A new tool grub-editenv is added to manage the environment block, for example:
grub-editenv FILE create
Create a blank environment block file. It's used to store external
environment file.
grub-editenv FILE info
Show the info about location and size of environment block in core.img
or external environment file.
grub-editenv FILE list
List the content of environment block.
grub-editenv FILE edit name=value
Edit the environment block. If no value is specify, name=, it deletes the item.
grub-editenv FILE clear
Remove all variables in the environment block.
And there is a new module findroot.mod. It will scan all partitions
and compare their uuid/label with the uuid and label variable, whose
value can be set in the environment block.
Here is an example:
First, use grub-mkimage to create core.img:
grub-mkimage -o core.img pc ext2 findroot
grub-mkimage will initialize the environment block with one item:
rdir=/boot/grub
Second, use grub-editenv to set the uuid or label of the root device.
For example:
grub-editenv core.img edit uuid=xxx-xxxx
grub-editenv core.img edit label=System
If both uuid and label is specified, uuid will take preference, unless
the fs don't support uuid.
You can also change rdir to change the default root directory, or add
debug=all to show debug message, etc.
--
Bean
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: envblk.diff --]
[-- Type: text/x-diff; name=envblk.diff, Size: 24877 bytes --]
diff --git a/boot/i386/pc/lnxboot.S b/boot/i386/pc/lnxboot.S
index 955cc41..380ef08 100644
--- a/boot/i386/pc/lnxboot.S
+++ b/boot/i386/pc/lnxboot.S
@@ -185,7 +185,7 @@ real_code_2:
call move_memory
/* Check for multiboot signature. */
- cmpl $MULTIBOOT_MAGIC, %ss:(DATA_ADDR + 0x50)
+ cmpl $MULTIBOOT_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_DATA_END)
jz 1f
movl (ramdisk_image - start), %esi
diff --git a/conf/common.rmk b/conf/common.rmk
index acbebc7..0582d56 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -94,6 +94,12 @@ 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/err.c kern/misc.c
+CLEANFILES += grub-editenv
+
# For update-grub
update-grub: util/update-grub.in config.status
./config.status --file=$@:$<
@@ -365,7 +371,7 @@ hexdump_mod_CFLAGS = $(COMMON_CFLAGS)
hexdump_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
@@ -386,3 +392,8 @@ read_mod_LDFLAGS = $(COMMON_LDFLAGS)
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..7811723
--- /dev/null
+++ b/include/grub/envblk.h
@@ -0,0 +1,47 @@
+/*
+ * 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"
+
+#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);
+
+#endif
+
+#endif /* ! GRUB_ENVBLK_HEADER */
diff --git a/include/grub/i386/pc/kernel.h b/include/grub/i386/pc/kernel.h
index 43a8d5b..13548c5 100644
--- a/include/grub/i386/pc/kernel.h
+++ b/include/grub/i386/pc/kernel.h
@@ -37,14 +37,14 @@
/* The offset of GRUB_MEMDISK_IMAGE_SIZE. */
#define GRUB_KERNEL_MACHINE_MEMDISK_IMAGE_SIZE 0x1c
-/* The offset of GRUB_PREFIX. */
-#define GRUB_KERNEL_MACHINE_PREFIX 0x20
+/* The offset of GRUB_ENVBLK. */
+#define GRUB_KERNEL_MACHINE_ENVBLK 0x26
/* End of the data section. */
-#define GRUB_KERNEL_MACHINE_DATA_END 0x50
+#define GRUB_KERNEL_MACHINE_DATA_END 0x70
/* The size of the first region which won't be compressed. */
-#define GRUB_KERNEL_MACHINE_RAW_SIZE 0x4A0
+#define GRUB_KERNEL_MACHINE_RAW_SIZE 0x4C0
#ifndef ASM_FILE
@@ -66,9 +66,9 @@ extern grub_int32_t grub_install_bsd_part;
/* The size of memory disk image, if present. */
extern grub_int32_t grub_memdisk_image_size;
-/* The prefix which points to the directory where GRUB modules and its
- configuration file are located. */
-extern char grub_prefix[];
+/* The envblk contains variable which can be used to locate the directory where
+ GRUB modules and its configuration file. */
+extern char grub_envblk[];
/* The boot BIOS drive number. */
extern grub_int32_t EXPORT_VAR(grub_boot_drive);
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index 4a4e2cc..49f3516 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -55,8 +55,10 @@ void grub_machine_init (void);
/* The machine-specific finalization. */
void grub_machine_fini (void);
-/* The machine-specific prefix initialization. */
-void grub_machine_set_prefix (void);
+/* The machine-specific root initialization. */
+void grub_machine_set_root (void);
+
+char *grub_machine_get_envblk (void);
/* Register all the exported symbols. This is automatically generated. */
void grub_register_exported_symbols (void);
diff --git a/kern/findroot.c b/kern/findroot.c
new file mode 100755
index 0000000..3ac5ce5
--- /dev/null
+++ b/kern/findroot.c
@@ -0,0 +1,96 @@
+/* findroot.c - search for root device */
+/*
+ * 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/device.h>
+#include <grub/file.h>
+#include <grub/env.h>
+#include <grub/machine/kernel.h>
+
+#define KERNEL_FILE "/normal.mod"
+
+static void
+findroot (void)
+{
+ char *label, *uuid;
+
+ auto int iterate_device (const char *name);
+ int iterate_device (const char *name)
+ {
+ int found = 0;
+ grub_device_t dev;
+ grub_fs_t fs;
+
+ dev = grub_device_open (name);
+ if (dev)
+ {
+ fs = grub_fs_probe (dev);
+ if (fs)
+ {
+ if ((uuid) && (fs->uuid))
+ {
+ char *cur;
+
+ fs->uuid (dev, &cur);
+ if (cur)
+ {
+ found = (! grub_strcmp (uuid, cur));
+ grub_free (cur);
+ }
+ }
+ else if ((label) && (fs->label))
+ {
+ char *cur;
+
+ fs->label (dev, &cur);
+ if (cur)
+ {
+ found = (! grub_strcmp (label, cur));
+ grub_free (cur);
+ }
+ }
+
+ if (found)
+ grub_env_set ("root", name);
+ }
+
+ grub_device_close (dev);
+ }
+
+ grub_errno = GRUB_ERR_NONE;
+ return found;
+ }
+
+ label = grub_env_get ("label");
+ uuid = grub_env_get ("uuid");
+
+ if ((! label) && (! uuid))
+ return;
+
+ grub_device_iterate (iterate_device);
+}
+
+GRUB_MOD_INIT(findroot)
+{
+ findroot ();
+}
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index 757f5d5..aabdff2 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -58,40 +58,6 @@ grub_arch_sync_caches (void *address __attribute__ ((unused)),
{
}
-static char *
-make_install_device (void)
-{
- /* XXX: This should be enough. */
- char dev[100];
-
- if (grub_memdisk_image_size)
- {
- grub_sprintf (dev, "(memdisk)%s", grub_prefix);
- grub_strcpy (grub_prefix, dev);
- }
- else if (grub_install_dos_part != -2)
- {
- /* If the root drive is not set explicitly, assume that it is identical
- to the boot drive. */
- if (grub_root_drive == 0xFF)
- grub_root_drive = grub_boot_drive;
-
- grub_sprintf (dev, "(%cd%u", (grub_root_drive & 0x80) ? 'h' : 'f',
- grub_root_drive & 0x7f);
-
- if (grub_install_dos_part >= 0)
- grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1);
-
- if (grub_install_bsd_part >= 0)
- grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a');
-
- grub_sprintf (dev + grub_strlen (dev), ")%s", grub_prefix);
- grub_strcpy (grub_prefix, dev);
- }
-
- return grub_prefix;
-}
-
/* Add a memory region. */
static void
add_mem_region (grub_addr_t addr, grub_size_t size)
@@ -238,11 +204,40 @@ grub_machine_init (void)
grub_fatal ("no upper memory");
}
+char *
+grub_machine_get_envblk (void)
+{
+ return grub_envblk;
+}
+
void
-grub_machine_set_prefix (void)
+grub_machine_set_root (void)
{
- /* Initialize the prefix. */
- grub_env_set ("prefix", make_install_device ());
+ /* XXX: This should be enough. */
+ char dev[100];
+
+ if (grub_memdisk_image_size)
+ {
+ grub_env_set ("root", "memdisk");
+ }
+ else if (grub_install_dos_part != -2)
+ {
+ /* If the root drive is not set explicitly, assume that it is identical
+ to the boot drive. */
+ if (grub_root_drive == 0xFF)
+ grub_root_drive = grub_boot_drive;
+
+ grub_sprintf (dev, "%cd%u", (grub_root_drive & 0x80) ? 'h' : 'f',
+ grub_root_drive & 0x7f);
+
+ if (grub_install_dos_part >= 0)
+ grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1);
+
+ if (grub_install_bsd_part >= 0)
+ grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a');
+
+ grub_env_set ("root", dev);
+ }
}
void
diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S
index ebb98fe..cba710a 100644
--- a/kern/i386/pc/startup.S
+++ b/kern/i386/pc/startup.S
@@ -52,6 +52,7 @@
#include <grub/term.h>
#include <multiboot.h>
#include <multiboot2.h>
+#include <grub/envblk.h>
#define ABS(x) ((x) - EXT_C(start) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
@@ -98,14 +99,19 @@ VARIABLE(grub_install_bsd_part)
.long 0xFFFFFFFF
VARIABLE(grub_memdisk_image_size)
.long 0
-VARIABLE(grub_prefix)
+ .long GRUB_ENVBLK_SIGNATURE
+ .word envblk_end - grub_envblk
+VARIABLE(grub_envblk)
+ .byte 0
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
- . = EXT_C(start) + 0x50
+ . = EXT_C(start) + 0x70
+
+envblk_end:
/*
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
diff --git a/kern/main.c b/kern/main.c
index 09de03a..729dd78 100644
--- a/kern/main.c
+++ b/kern/main.c
@@ -28,6 +28,33 @@
#include <grub/device.h>
#include <grub/env.h>
+static void
+grub_parse_envblk (void)
+{
+ char *env;
+
+ env = grub_machine_get_envblk ();
+ if (! env)
+ return;
+
+ while (*env)
+ {
+ char *value;
+
+ value = grub_strchr (env, '=');
+ if (value)
+ {
+ *(value++) = 0;
+ grub_env_set (env, value);
+ env = value;
+ }
+ else
+ grub_env_set (env, "");
+
+ env += grub_strlen (env) + 1;
+ }
+}
+
/* Load all modules in core. */
static void
grub_load_modules (void)
@@ -75,24 +102,28 @@ grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
static void
grub_set_root_dev (void)
{
- const char *prefix;
+ char *root, *rdir, *prefix;
+
+ if (! grub_env_get ("root"))
+ grub_machine_set_root ();
grub_register_variable_hook ("root", 0, grub_env_write_root);
grub_env_export ("root");
- prefix = grub_env_get ("prefix");
+ root = grub_env_get ("root");
+ if (! *root)
+ return;
- if (prefix)
- {
- char *dev;
-
- dev = grub_file_get_device_name (prefix);
- if (dev)
- {
- grub_env_set ("root", dev);
- grub_free (dev);
- }
- }
+ rdir = grub_env_get ("rdir");
+ if (! rdir)
+ rdir = "/";
+
+ prefix = grub_malloc (grub_strlen (root) + grub_strlen (rdir) + 3);
+ grub_sprintf (prefix, "(%s)%s", root, rdir);
+
+ grub_env_set ("prefix", prefix);
+
+ grub_free (prefix);
}
/* Load the normal mode module and execute the normal mode if possible. */
@@ -118,13 +149,15 @@ grub_main (void)
grub_printf ("Welcome to GRUB!\n\n");
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ /* Parse the environment block. */
+ grub_parse_envblk ();
+
/* Load pre-loaded modules and free the space. */
grub_register_exported_symbols ();
grub_load_modules ();
/* It is better to set the root device as soon as possible,
for convenience. */
- grub_machine_set_prefix ();
grub_set_root_dev ();
/* Load the normal mode module. */
diff --git a/util/envblk.c b/util/envblk.c
new file mode 100755
index 0000000..82ec674
--- /dev/null
+++ b/util/envblk.c
@@ -0,0 +1,123 @@
+/* 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/misc.h>
+#include <grub/envblk.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 += 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 += strlen (p) + 1;
+ if (p >= pend)
+ return;
+ }
+
+ if (found)
+ {
+ int len;
+
+ len = grub_strlen (found);
+ grub_memcpy (found, found + len + 1, (p - found) - len);
+ }
+}
diff --git a/util/grub-editenv.c b/util/grub-editenv.c
new file mode 100755
index 0000000..d4d7919
--- /dev/null
+++ b/util/grub-editenv.c
@@ -0,0 +1,259 @@
+/* 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);
+}
+
+int
+grub_getkey (void)
+{
+ return -1;
+}
+
+void *
+grub_term_get_current (void)
+{
+ return 0;
+}
+
+void
+grub_refresh (void)
+{
+ fflush (stdout);
+}
+
+char *
+grub_env_get (const char * name)
+{
+ (void) name;
+
+ return 0;
+}
+
+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\
+ edit [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, "w");
+ 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+");
+ 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", (char *) envblk - buffer);
+ printf ("Envblk length: %d\n", envblk->length);
+}
+
+static void
+cmd_list (void)
+{
+ char *p = envblk->data;
+
+ while (*p)
+ {
+ printf ("%s\n", p);
+ p += strlen (p) + 1;
+ }
+}
+
+static void
+cmd_edit (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], "edit"))
+ cmd_edit (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;
+}
diff --git a/util/grub-emu.c b/util/grub-emu.c
index 00a2c49..aa7ceb9 100644
--- a/util/grub-emu.c
+++ b/util/grub-emu.c
@@ -36,15 +36,13 @@
#include <grub/util/getroot.h>
#include <grub/env.h>
#include <grub/partition.h>
+#include <grub/envblk.h>
#include <grub_emu_init.h>
/* Used for going back to the main function. */
jmp_buf main_env;
-/* Store the prefix specified by an argument. */
-static char *prefix = 0;
-
grub_addr_t
grub_arch_modules_addr (void)
{
@@ -76,11 +74,15 @@ grub_machine_init (void)
}
void
-grub_machine_set_prefix (void)
+grub_machine_set_root (void)
{
- grub_env_set ("prefix", prefix);
- free (prefix);
- prefix = 0;
+ /* Do nothing, as root is already set. */
+}
+
+char *
+grub_machine_get_envblk (void)
+{
+ return 0;
}
void
@@ -205,8 +207,8 @@ main (int argc, char *argv[])
}
dir = grub_get_prefix (dir);
- prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1);
- sprintf (prefix, "(%s)%s", root_dev, dir);
+ grub_env_set (GRUB_ENVBLK_RDIR, dir);
+ grub_env_set ("root", root_dev);
free (dir);
/* Start GRUB! */
diff --git a/util/i386/pc/grub-mkimage.c b/util/i386/pc/grub-mkimage.c
index 48d6dfc..f71924b 100644
--- a/util/i386/pc/grub-mkimage.c
+++ b/util/i386/pc/grub-mkimage.c
@@ -27,6 +27,7 @@
#include <grub/util/misc.h>
#include <grub/util/resolve.h>
#include <grub/misc.h>
+#include <grub/envblk.h>
#include <stdio.h>
#include <unistd.h>
@@ -109,9 +110,10 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], char *me
kernel_img = xmalloc (kernel_size + total_module_size + memdisk_size);
grub_util_load_image (kernel_path, kernel_img);
- if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END)
+ if (GRUB_KERNEL_MACHINE_ENVBLK + sizeof (GRUB_ENVBLK_RDIR) + 2 + strlen (prefix) > GRUB_KERNEL_MACHINE_DATA_END)
grub_util_error ("prefix too long");
- strcpy (kernel_img + GRUB_KERNEL_MACHINE_PREFIX, prefix);
+ strcpy (kernel_img + GRUB_KERNEL_MACHINE_ENVBLK, GRUB_ENVBLK_RDIR "=");
+ strcpy (kernel_img + GRUB_KERNEL_MACHINE_ENVBLK + sizeof (GRUB_ENVBLK_RDIR), prefix);
/* Fill in the grub_module_info structure. */
modinfo = (struct grub_module_info *) (kernel_img + kernel_size);
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index 535a8d0..2a243e8 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -34,6 +34,7 @@
#include <grub/term.h>
#include <grub/util/raid.h>
#include <grub/util/lvm.h>
+#include <grub/envblk.h>
static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
@@ -235,7 +236,10 @@ setup (const char *prefix, const char *dir,
install_bsd_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE
+ GRUB_KERNEL_MACHINE_INSTALL_BSD_PART);
install_prefix = (core_img + GRUB_DISK_SECTOR_SIZE
- + GRUB_KERNEL_MACHINE_PREFIX);
+ + GRUB_KERNEL_MACHINE_ENVBLK);
+
+ strcpy (install_prefix, GRUB_ENVBLK_RDIR "=");
+ install_prefix += sizeof (GRUB_ENVBLK_RDIR);
/* Open the root device and the destination device. */
root_dev = grub_device_open (root);
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-05-30 20:27 [PATCH] Environment block support for grub2 Bean
@ 2008-05-31 10:10 ` Robert Millan
2008-05-31 10:54 ` Bean
0 siblings, 1 reply; 23+ messages in thread
From: Robert Millan @ 2008-05-31 10:10 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, May 31, 2008 at 04:27:31AM +0800, Bean wrote:
> Hi,
>
> This patch add environment block support, which can be used to locate
> root device using uuid or label.
Nice :-)
> The previous prefix is stored in variable rdir.
Do we need this?
> Different platform use grub_machine_get_envblk to return a pointer to
> the name=value area of environment block. In main.c, it uses
> grub_parse_envblk to walk through the list and assign values to
> variables.
>
> I also replace grub_machine_set_prefix with grub_machine_set_root. As
> it seems strange to compute the prefix in grub_machine_set_prefix, and
> then split it in grub_set_root_dev to get the root device. Now,
> grub_machine_set_root set the root directly, and in grub_set_root_dev,
> it uses root and rdir to generate the prefix.
Note that root and prefix don't necessarily have to point at the same device.
prefix always points at the directory containing GRUB modules etc, and is
needed at initial stage. root is used later on by grub.cfg to access our
payload (I think our current use of root to initialise prefix is gratuitous
and could better be avoided).
Since for initialising root we don't have any problem, as we can use all
the fancy stuff grub.cfg allows, unless I missed something I think it's
better if at this stage we just focus on prefix.
> grub-mkimage will initialize the environment block with one item:
> rdir=/boot/grub
>
> Second, use grub-editenv to set the uuid or label of the root device.
> For example:
Would it be simpler if grub-mkimage embedded an initialised environment
block directly?
--
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] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-05-31 10:10 ` Robert Millan
@ 2008-05-31 10:54 ` Bean
2008-05-31 11:39 ` Robert Millan
0 siblings, 1 reply; 23+ messages in thread
From: Bean @ 2008-05-31 10:54 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, May 31, 2008 at 6:10 PM, Robert Millan <rmh@aybabtu.com> wrote:
>> Different platform use grub_machine_get_envblk to return a pointer to
>> the name=value area of environment block. In main.c, it uses
>> grub_parse_envblk to walk through the list and assign values to
>> variables.
>>
>> I also replace grub_machine_set_prefix with grub_machine_set_root. As
>> it seems strange to compute the prefix in grub_machine_set_prefix, and
>> then split it in grub_set_root_dev to get the root device. Now,
>> grub_machine_set_root set the root directly, and in grub_set_root_dev,
>> it uses root and rdir to generate the prefix.
>
> Note that root and prefix don't necessarily have to point at the same device.
>
> prefix always points at the directory containing GRUB modules etc, and is
> needed at initial stage. root is used later on by grub.cfg to access our
> payload (I think our current use of root to initialise prefix is gratuitous
> and could better be avoided).
>
> Since for initialising root we don't have any problem, as we can use all
> the fancy stuff grub.cfg allows, unless I missed something I think it's
> better if at this stage we just focus on prefix.
>
The root is assigned in the initialization phraze. Currently, it's
done this way:
machine_machine_init -> calculate root device, then set variable
prefix using root and grub_prefix.
modules initialization
grub_set_root_dev -> Use variable prefix to get the root variable.
Load normal.mod
As you can see, it first create prefix, then split it to find root. At
the end of grub_set_root_dev, prefix and root will point to the same
device. This also make it different to change the root setting in
findroot, which is run in modules initialization stage. We must split
prefix to find the root directory, and use the new root to form a new
prefix. The prefix would later be split again to find root, what a
mess.
The new method:
machine_machine_init -> calculate root device, then set root variable directly.
Load variable in the environment block
modules initialization
findroot
more modules initialization
grub_set_root_dev -> Use variable root to get the root prefix.
Load normal.mod
The end result would be the same, but the new method is cleaner, and
allows overwrite of the root and rdir variable using environment block
and findroot.
>> grub-mkimage will initialize the environment block with one item:
>> rdir=/boot/grub
>>
>> Second, use grub-editenv to set the uuid or label of the root device.
>> For example:
>
> Would it be simpler if grub-mkimage embedded an initialised environment
> block directly?
I think it's better to have a seperate tool to do this. Besides,
grub-editenv can also be used to manage external environment block
file, which is used to load/save persistent variable like default.
--
Bean
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-05-31 10:54 ` Bean
@ 2008-05-31 11:39 ` Robert Millan
2008-05-31 12:09 ` Bean
0 siblings, 1 reply; 23+ messages in thread
From: Robert Millan @ 2008-05-31 11:39 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, May 31, 2008 at 06:54:43PM +0800, Bean wrote:
>
> The root is assigned in the initialization phraze. Currently, it's
> done this way:
>
> machine_machine_init -> calculate root device, then set variable
> prefix using root and grub_prefix.
>
> modules initialization
>
> grub_set_root_dev -> Use variable prefix to get the root variable.
>
> Load normal.mod
>
> As you can see, it first create prefix, then split it to find root. At
> the end of grub_set_root_dev, prefix and root will point to the same
> device. This also make it different to change the root setting in
> findroot, which is run in modules initialization stage. We must split
> prefix to find the root directory, and use the new root to form a new
> prefix. The prefix would later be split again to find root, what a
> mess.
>
> The new method:
>
> machine_machine_init -> calculate root device, then set root variable directly.
>
> Load variable in the environment block
>
> modules initialization
>
> findroot
>
> more modules initialization
>
> grub_set_root_dev -> Use variable root to get the root prefix.
>
> Load normal.mod
>
> The end result would be the same, but the new method is cleaner, and
> allows overwrite of the root and rdir variable using environment block
> and findroot.
I think the method is sound; what I'm complaining about (and it's not
something specific to your patch) is that we're referring to two different
things by the same name ("root"), and even put them in the same variable.
In the initialization phase, "root" is the device that contains our GRUB
directory.
Afterwards, "root" is the device we're currently accessing (be it for loading
fonts, backgrounds, Linux images, whatever).
If "root" means "just a placeholder for whatever device we're acessing at the
moment", then it would make sense, but in our code (i.e. in the names we're
giving to commands and functions) it's assumed to mean "the device containing
/boot/grub".
So what do we want to do with this? Should we have different variables for
each thing (and in that case, is "root" for initial stage or for grub.cfg)
or should we use "root" as a placeholder for any path reference, and adjust
our function names etc to reflect that?
--
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] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-05-31 11:39 ` Robert Millan
@ 2008-05-31 12:09 ` Bean
2008-05-31 15:09 ` Bean
2008-05-31 15:21 ` [PATCH] Environment block support for grub2 Robert Millan
0 siblings, 2 replies; 23+ messages in thread
From: Bean @ 2008-05-31 12:09 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, May 31, 2008 at 7:39 PM, Robert Millan <rmh@aybabtu.com> wrote:
>
> I think the method is sound; what I'm complaining about (and it's not
> something specific to your patch) is that we're referring to two different
> things by the same name ("root"), and even put them in the same variable.
>
> In the initialization phase, "root" is the device that contains our GRUB
> directory.
>
> Afterwards, "root" is the device we're currently accessing (be it for loading
> fonts, backgrounds, Linux images, whatever).
>
> If "root" means "just a placeholder for whatever device we're acessing at the
> moment", then it would make sense, but in our code (i.e. in the names we're
> giving to commands and functions) it's assumed to mean "the device containing
> /boot/grub".
>
> So what do we want to do with this? Should we have different variables for
> each thing (and in that case, is "root" for initial stage or for grub.cfg)
> or should we use "root" as a placeholder for any path reference, and adjust
> our function names etc to reflect that?
root is used in loaders as well, we shouldn't change its name. We
could use another variable to store the root device at initial stage,
it could actually be useful as it always points to the boot media.
Perhaps we can name it "boot". What's your idea ?
--
Bean
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-05-31 12:09 ` Bean
@ 2008-05-31 15:09 ` Bean
2008-06-03 21:09 ` Robert Millan
2008-05-31 15:21 ` [PATCH] Environment block support for grub2 Robert Millan
1 sibling, 1 reply; 23+ messages in thread
From: Bean @ 2008-05-31 15:09 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 1234 bytes --]
Hi,
This is the new patch, it contain the following changes:
1. command edit -> set in grub-editenv, as it seems more natural.
grub-editenv FILE set name=value ...
2. findroot can locate the root device using filename. To use it, just
set idfile to any file inside the directory, For example:
idfile=normal.mod
Scan preference: uuid > label > idfile
3. Change the order device are reported in biosdisk, so that floppy appear last.
4. Add new command loadenv, which can be used to load/save environment variable.
load_env [-f FILE]
Load environment variable from external environment block file. The
default file is $prefix/grubenv, but you can overwrite it with -f
parameter.
list_env [-f FILE]
List the variables in external environment block file.
save_env [-f FILE] variable_name ..
Save the value of variable_name to external environment block file
So, to archive the effect of savedefault command in grub legacy, you can use:
load_env
..
menuentry aa {
..
save_env default
}
You can also use save_env to save the variable directly to core.img,
but it's not recommended. The environment block inside core.img is
quite small, it's mainly used to store critical variable like rdir,
uuid, label and idfile.
--
Bean
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: envblk_2.diff --]
[-- Type: text/x-diff; name=envblk_2.diff, Size: 34863 bytes --]
diff --git a/boot/i386/pc/lnxboot.S b/boot/i386/pc/lnxboot.S
index 955cc41..380ef08 100644
--- a/boot/i386/pc/lnxboot.S
+++ b/boot/i386/pc/lnxboot.S
@@ -185,7 +185,7 @@ real_code_2:
call move_memory
/* Check for multiboot signature. */
- cmpl $MULTIBOOT_MAGIC, %ss:(DATA_ADDR + 0x50)
+ cmpl $MULTIBOOT_MAGIC, %ss:(DATA_ADDR + GRUB_KERNEL_MACHINE_DATA_END)
jz 1f
movl (ramdisk_image - start), %esi
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/disk/i386/pc/biosdisk.c b/disk/i386/pc/biosdisk.c
index 094bde0..6e5292f 100644
--- a/disk/i386/pc/biosdisk.c
+++ b/disk/i386/pc/biosdisk.c
@@ -66,12 +66,6 @@ grub_biosdisk_iterate (int (*hook) (const char *name))
int drive;
int num_floppies;
- /* For floppy disks, we can get the number safely. */
- num_floppies = grub_biosdisk_get_num_floppies ();
- for (drive = 0; drive < num_floppies; drive++)
- if (grub_biosdisk_call_hook (hook, drive))
- return 1;
-
/* For hard disks, attempt to read the MBR. */
for (drive = 0x80; drive < 0x90; drive++)
{
@@ -92,6 +86,12 @@ grub_biosdisk_iterate (int (*hook) (const char *name))
return 1;
}
+ /* For floppy disks, we can get the number safely. */
+ num_floppies = grub_biosdisk_get_num_floppies ();
+ for (drive = 0; drive < num_floppies; drive++)
+ if (grub_biosdisk_call_hook (hook, drive))
+ return 1;
+
return 0;
}
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/include/grub/i386/pc/kernel.h b/include/grub/i386/pc/kernel.h
index 43a8d5b..13548c5 100644
--- a/include/grub/i386/pc/kernel.h
+++ b/include/grub/i386/pc/kernel.h
@@ -37,14 +37,14 @@
/* The offset of GRUB_MEMDISK_IMAGE_SIZE. */
#define GRUB_KERNEL_MACHINE_MEMDISK_IMAGE_SIZE 0x1c
-/* The offset of GRUB_PREFIX. */
-#define GRUB_KERNEL_MACHINE_PREFIX 0x20
+/* The offset of GRUB_ENVBLK. */
+#define GRUB_KERNEL_MACHINE_ENVBLK 0x26
/* End of the data section. */
-#define GRUB_KERNEL_MACHINE_DATA_END 0x50
+#define GRUB_KERNEL_MACHINE_DATA_END 0x70
/* The size of the first region which won't be compressed. */
-#define GRUB_KERNEL_MACHINE_RAW_SIZE 0x4A0
+#define GRUB_KERNEL_MACHINE_RAW_SIZE 0x4C0
#ifndef ASM_FILE
@@ -66,9 +66,9 @@ extern grub_int32_t grub_install_bsd_part;
/* The size of memory disk image, if present. */
extern grub_int32_t grub_memdisk_image_size;
-/* The prefix which points to the directory where GRUB modules and its
- configuration file are located. */
-extern char grub_prefix[];
+/* The envblk contains variable which can be used to locate the directory where
+ GRUB modules and its configuration file. */
+extern char grub_envblk[];
/* The boot BIOS drive number. */
extern grub_int32_t EXPORT_VAR(grub_boot_drive);
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index 4a4e2cc..49f3516 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -55,8 +55,10 @@ void grub_machine_init (void);
/* The machine-specific finalization. */
void grub_machine_fini (void);
-/* The machine-specific prefix initialization. */
-void grub_machine_set_prefix (void);
+/* The machine-specific root initialization. */
+void grub_machine_set_root (void);
+
+char *grub_machine_get_envblk (void);
/* Register all the exported symbols. This is automatically generated. */
void grub_register_exported_symbols (void);
diff --git a/kern/findroot.c b/kern/findroot.c
new file mode 100755
index 0000000..44d5eb8
--- /dev/null
+++ b/kern/findroot.c
@@ -0,0 +1,110 @@
+/* findroot.c - search for root device */
+/*
+ * 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/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/device.h>
+#include <grub/file.h>
+#include <grub/env.h>
+#include <grub/machine/kernel.h>
+#include <grub/envblk.h>
+
+static void
+findroot (void)
+{
+ char *label, *uuid, *idfile, *rdir;
+ int found = 0;
+
+ auto int iterate_rdir (const char *filename, int dir);
+ int iterate_rdir (const char *filename, int dir)
+ {
+ (void) dir;
+
+ found = (! grub_strcmp (filename, idfile));
+ return found;
+ }
+
+ auto int iterate_device (const char *name);
+ int iterate_device (const char *name)
+ {
+ grub_device_t dev;
+ grub_fs_t fs;
+
+ dev = grub_device_open (name);
+ if (dev)
+ {
+ fs = grub_fs_probe (dev);
+ if (fs)
+ {
+ if ((uuid) && (fs->uuid))
+ {
+ char *cur;
+
+ fs->uuid (dev, &cur);
+ if (cur)
+ {
+ found = (! grub_strcmp (uuid, cur));
+ grub_free (cur);
+ }
+ }
+ else if ((label) && (fs->label))
+ {
+ char *cur;
+
+ fs->label (dev, &cur);
+ if (cur)
+ {
+ found = (! grub_strcmp (label, cur));
+ grub_free (cur);
+ }
+ }
+ else if (idfile)
+ fs->dir (dev, rdir, iterate_rdir);
+
+ if (found)
+ grub_env_set ("root", name);
+ }
+
+ grub_device_close (dev);
+ }
+
+ grub_errno = GRUB_ERR_NONE;
+ return found;
+ }
+
+ uuid = grub_env_get (GRUB_ENVBLK_UUID);
+ label = grub_env_get (GRUB_ENVBLK_LABEL);
+ idfile = grub_env_get (GRUB_ENVBLK_IDFILE);
+ rdir = grub_env_get (GRUB_ENVBLK_RDIR);
+ if (! rdir)
+ rdir = "/";
+
+ if ((! label) && (! uuid) && (! idfile))
+ return;
+
+ grub_device_iterate (iterate_device);
+}
+
+GRUB_MOD_INIT(findroot)
+{
+ findroot ();
+}
diff --git a/kern/i386/pc/init.c b/kern/i386/pc/init.c
index 757f5d5..aabdff2 100644
--- a/kern/i386/pc/init.c
+++ b/kern/i386/pc/init.c
@@ -58,40 +58,6 @@ grub_arch_sync_caches (void *address __attribute__ ((unused)),
{
}
-static char *
-make_install_device (void)
-{
- /* XXX: This should be enough. */
- char dev[100];
-
- if (grub_memdisk_image_size)
- {
- grub_sprintf (dev, "(memdisk)%s", grub_prefix);
- grub_strcpy (grub_prefix, dev);
- }
- else if (grub_install_dos_part != -2)
- {
- /* If the root drive is not set explicitly, assume that it is identical
- to the boot drive. */
- if (grub_root_drive == 0xFF)
- grub_root_drive = grub_boot_drive;
-
- grub_sprintf (dev, "(%cd%u", (grub_root_drive & 0x80) ? 'h' : 'f',
- grub_root_drive & 0x7f);
-
- if (grub_install_dos_part >= 0)
- grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1);
-
- if (grub_install_bsd_part >= 0)
- grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a');
-
- grub_sprintf (dev + grub_strlen (dev), ")%s", grub_prefix);
- grub_strcpy (grub_prefix, dev);
- }
-
- return grub_prefix;
-}
-
/* Add a memory region. */
static void
add_mem_region (grub_addr_t addr, grub_size_t size)
@@ -238,11 +204,40 @@ grub_machine_init (void)
grub_fatal ("no upper memory");
}
+char *
+grub_machine_get_envblk (void)
+{
+ return grub_envblk;
+}
+
void
-grub_machine_set_prefix (void)
+grub_machine_set_root (void)
{
- /* Initialize the prefix. */
- grub_env_set ("prefix", make_install_device ());
+ /* XXX: This should be enough. */
+ char dev[100];
+
+ if (grub_memdisk_image_size)
+ {
+ grub_env_set ("root", "memdisk");
+ }
+ else if (grub_install_dos_part != -2)
+ {
+ /* If the root drive is not set explicitly, assume that it is identical
+ to the boot drive. */
+ if (grub_root_drive == 0xFF)
+ grub_root_drive = grub_boot_drive;
+
+ grub_sprintf (dev, "%cd%u", (grub_root_drive & 0x80) ? 'h' : 'f',
+ grub_root_drive & 0x7f);
+
+ if (grub_install_dos_part >= 0)
+ grub_sprintf (dev + grub_strlen (dev), ",%u", grub_install_dos_part + 1);
+
+ if (grub_install_bsd_part >= 0)
+ grub_sprintf (dev + grub_strlen (dev), ",%c", grub_install_bsd_part + 'a');
+
+ grub_env_set ("root", dev);
+ }
}
void
diff --git a/kern/i386/pc/startup.S b/kern/i386/pc/startup.S
index ebb98fe..cba710a 100644
--- a/kern/i386/pc/startup.S
+++ b/kern/i386/pc/startup.S
@@ -52,6 +52,7 @@
#include <grub/term.h>
#include <multiboot.h>
#include <multiboot2.h>
+#include <grub/envblk.h>
#define ABS(x) ((x) - EXT_C(start) + GRUB_BOOT_MACHINE_KERNEL_ADDR + 0x200)
@@ -98,14 +99,19 @@ VARIABLE(grub_install_bsd_part)
.long 0xFFFFFFFF
VARIABLE(grub_memdisk_image_size)
.long 0
-VARIABLE(grub_prefix)
+ .long GRUB_ENVBLK_SIGNATURE
+ .word envblk_end - grub_envblk
+VARIABLE(grub_envblk)
+ .byte 0
/* to be filled by grub-mkimage */
/*
* Leave some breathing room for the prefix.
*/
- . = EXT_C(start) + 0x50
+ . = EXT_C(start) + 0x70
+
+envblk_end:
/*
* Support for booting GRUB from a Multiboot boot loader (e.g. GRUB itself).
diff --git a/kern/main.c b/kern/main.c
index 09de03a..729dd78 100644
--- a/kern/main.c
+++ b/kern/main.c
@@ -28,6 +28,33 @@
#include <grub/device.h>
#include <grub/env.h>
+static void
+grub_parse_envblk (void)
+{
+ char *env;
+
+ env = grub_machine_get_envblk ();
+ if (! env)
+ return;
+
+ while (*env)
+ {
+ char *value;
+
+ value = grub_strchr (env, '=');
+ if (value)
+ {
+ *(value++) = 0;
+ grub_env_set (env, value);
+ env = value;
+ }
+ else
+ grub_env_set (env, "");
+
+ env += grub_strlen (env) + 1;
+ }
+}
+
/* Load all modules in core. */
static void
grub_load_modules (void)
@@ -75,24 +102,28 @@ grub_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
static void
grub_set_root_dev (void)
{
- const char *prefix;
+ char *root, *rdir, *prefix;
+
+ if (! grub_env_get ("root"))
+ grub_machine_set_root ();
grub_register_variable_hook ("root", 0, grub_env_write_root);
grub_env_export ("root");
- prefix = grub_env_get ("prefix");
+ root = grub_env_get ("root");
+ if (! *root)
+ return;
- if (prefix)
- {
- char *dev;
-
- dev = grub_file_get_device_name (prefix);
- if (dev)
- {
- grub_env_set ("root", dev);
- grub_free (dev);
- }
- }
+ rdir = grub_env_get ("rdir");
+ if (! rdir)
+ rdir = "/";
+
+ prefix = grub_malloc (grub_strlen (root) + grub_strlen (rdir) + 3);
+ grub_sprintf (prefix, "(%s)%s", root, rdir);
+
+ grub_env_set ("prefix", prefix);
+
+ grub_free (prefix);
}
/* Load the normal mode module and execute the normal mode if possible. */
@@ -118,13 +149,15 @@ grub_main (void)
grub_printf ("Welcome to GRUB!\n\n");
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+ /* Parse the environment block. */
+ grub_parse_envblk ();
+
/* Load pre-loaded modules and free the space. */
grub_register_exported_symbols ();
grub_load_modules ();
/* It is better to set the root device as soon as possible,
for convenience. */
- grub_machine_set_prefix ();
grub_set_root_dev ();
/* Load the normal mode module. */
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;
+}
diff --git a/util/grub-emu.c b/util/grub-emu.c
index 00a2c49..aa7ceb9 100644
--- a/util/grub-emu.c
+++ b/util/grub-emu.c
@@ -36,15 +36,13 @@
#include <grub/util/getroot.h>
#include <grub/env.h>
#include <grub/partition.h>
+#include <grub/envblk.h>
#include <grub_emu_init.h>
/* Used for going back to the main function. */
jmp_buf main_env;
-/* Store the prefix specified by an argument. */
-static char *prefix = 0;
-
grub_addr_t
grub_arch_modules_addr (void)
{
@@ -76,11 +74,15 @@ grub_machine_init (void)
}
void
-grub_machine_set_prefix (void)
+grub_machine_set_root (void)
{
- grub_env_set ("prefix", prefix);
- free (prefix);
- prefix = 0;
+ /* Do nothing, as root is already set. */
+}
+
+char *
+grub_machine_get_envblk (void)
+{
+ return 0;
}
void
@@ -205,8 +207,8 @@ main (int argc, char *argv[])
}
dir = grub_get_prefix (dir);
- prefix = xmalloc (strlen (root_dev) + 2 + strlen (dir) + 1);
- sprintf (prefix, "(%s)%s", root_dev, dir);
+ grub_env_set (GRUB_ENVBLK_RDIR, dir);
+ grub_env_set ("root", root_dev);
free (dir);
/* Start GRUB! */
diff --git a/util/i386/pc/grub-mkimage.c b/util/i386/pc/grub-mkimage.c
index 48d6dfc..f71924b 100644
--- a/util/i386/pc/grub-mkimage.c
+++ b/util/i386/pc/grub-mkimage.c
@@ -27,6 +27,7 @@
#include <grub/util/misc.h>
#include <grub/util/resolve.h>
#include <grub/misc.h>
+#include <grub/envblk.h>
#include <stdio.h>
#include <unistd.h>
@@ -109,9 +110,10 @@ generate_image (const char *dir, char *prefix, FILE *out, char *mods[], char *me
kernel_img = xmalloc (kernel_size + total_module_size + memdisk_size);
grub_util_load_image (kernel_path, kernel_img);
- if (GRUB_KERNEL_MACHINE_PREFIX + strlen (prefix) + 1 > GRUB_KERNEL_MACHINE_DATA_END)
+ if (GRUB_KERNEL_MACHINE_ENVBLK + sizeof (GRUB_ENVBLK_RDIR) + 2 + strlen (prefix) > GRUB_KERNEL_MACHINE_DATA_END)
grub_util_error ("prefix too long");
- strcpy (kernel_img + GRUB_KERNEL_MACHINE_PREFIX, prefix);
+ strcpy (kernel_img + GRUB_KERNEL_MACHINE_ENVBLK, GRUB_ENVBLK_RDIR "=");
+ strcpy (kernel_img + GRUB_KERNEL_MACHINE_ENVBLK + sizeof (GRUB_ENVBLK_RDIR), prefix);
/* Fill in the grub_module_info structure. */
modinfo = (struct grub_module_info *) (kernel_img + kernel_size);
diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c
index 535a8d0..2a243e8 100644
--- a/util/i386/pc/grub-setup.c
+++ b/util/i386/pc/grub-setup.c
@@ -34,6 +34,7 @@
#include <grub/term.h>
#include <grub/util/raid.h>
#include <grub/util/lvm.h>
+#include <grub/envblk.h>
static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
@@ -235,7 +236,10 @@ setup (const char *prefix, const char *dir,
install_bsd_part = (grub_int32_t *) (core_img + GRUB_DISK_SECTOR_SIZE
+ GRUB_KERNEL_MACHINE_INSTALL_BSD_PART);
install_prefix = (core_img + GRUB_DISK_SECTOR_SIZE
- + GRUB_KERNEL_MACHINE_PREFIX);
+ + GRUB_KERNEL_MACHINE_ENVBLK);
+
+ strcpy (install_prefix, GRUB_ENVBLK_RDIR "=");
+ install_prefix += sizeof (GRUB_ENVBLK_RDIR);
/* Open the root device and the destination device. */
root_dev = grub_device_open (root);
^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-05-31 12:09 ` Bean
2008-05-31 15:09 ` Bean
@ 2008-05-31 15:21 ` Robert Millan
2008-06-13 22:48 ` Yoshinori K. Okuji
1 sibling, 1 reply; 23+ messages in thread
From: Robert Millan @ 2008-05-31 15:21 UTC (permalink / raw)
To: The development of GRUB 2; +Cc: Yoshinori K. Okuji
On Sat, May 31, 2008 at 08:09:50PM +0800, Bean wrote:
> On Sat, May 31, 2008 at 7:39 PM, Robert Millan <rmh@aybabtu.com> wrote:
> >
> > I think the method is sound; what I'm complaining about (and it's not
> > something specific to your patch) is that we're referring to two different
> > things by the same name ("root"), and even put them in the same variable.
> >
> > In the initialization phase, "root" is the device that contains our GRUB
> > directory.
> >
> > Afterwards, "root" is the device we're currently accessing (be it for loading
> > fonts, backgrounds, Linux images, whatever).
> >
> > If "root" means "just a placeholder for whatever device we're acessing at the
> > moment", then it would make sense, but in our code (i.e. in the names we're
> > giving to commands and functions) it's assumed to mean "the device containing
> > /boot/grub".
> >
> > So what do we want to do with this? Should we have different variables for
> > each thing (and in that case, is "root" for initial stage or for grub.cfg)
> > or should we use "root" as a placeholder for any path reference, and adjust
> > our function names etc to reflect that?
>
> root is used in loaders as well, we shouldn't change its name. We
> could use another variable to store the root device at initial stage,
> it could actually be useful as it always points to the boot media.
> Perhaps we can name it "boot". What's your idea ?
I'm fine with "boot". I'm CCing Okuji; would like to make sure he doesn't
have any objections (I think it was he who gave it this layout).
--
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] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-05-31 15:09 ` Bean
@ 2008-06-03 21:09 ` Robert Millan
2008-06-04 3:49 ` Bean
0 siblings, 1 reply; 23+ messages in thread
From: Robert Millan @ 2008-06-03 21:09 UTC (permalink / raw)
To: The development of GRUB 2
I've been thinking a bit more about this, and I think it should be
possible to solve the problem at hand without extending the existing
framework. I'm concerned about finding a solution that is as simple
(and small) as possible.
Do you mind waiting a few days? I'll send a proposal tomorrow or so.
--
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] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-06-03 21:09 ` Robert Millan
@ 2008-06-04 3:49 ` Bean
2008-06-06 16:43 ` UUID-based boot (Re: [PATCH] Environment block support for grub2) Robert Millan
0 siblings, 1 reply; 23+ messages in thread
From: Bean @ 2008-06-04 3:49 UTC (permalink / raw)
To: The development of GRUB 2
On Wed, Jun 4, 2008 at 5:09 AM, Robert Millan <rmh@aybabtu.com> wrote:
>
> I've been thinking a bit more about this, and I think it should be
> possible to solve the problem at hand without extending the existing
> framework. I'm concerned about finding a solution that is as simple
> (and small) as possible.
>
> Do you mind waiting a few days? I'll send a proposal tomorrow or so.
Ok, no hurry.
--
Bean
^ permalink raw reply [flat|nested] 23+ messages in thread
* UUID-based boot (Re: [PATCH] Environment block support for grub2)
2008-06-04 3:49 ` Bean
@ 2008-06-06 16:43 ` Robert Millan
2008-06-06 17:22 ` Bean
0 siblings, 1 reply; 23+ messages in thread
From: Robert Millan @ 2008-06-06 16:43 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 1519 bytes --]
On Wed, Jun 04, 2008 at 11:49:14AM +0800, Bean wrote:
> On Wed, Jun 4, 2008 at 5:09 AM, Robert Millan <rmh@aybabtu.com> wrote:
> >
> > I've been thinking a bit more about this, and I think it should be
> > possible to solve the problem at hand without extending the existing
> > framework. I'm concerned about finding a solution that is as simple
> > (and small) as possible.
> >
> > Do you mind waiting a few days? I'll send a proposal tomorrow or so.
>
> Ok, no hurry.
Sorry for the delay; it was quite a bit of work as I got hit by a number of
bugs here and there :-)
Considering that the problem was quite similar to the "boot from LVM" issue
we already knew about, I thought it'd be a good idea to start with that.
Although not directly related, the patch at in "boot from LVM / RAID" mail I
just sent would allow to easily boot via UUID as well.
If we add a UUID-based disk driver (see "disk/fs_uuid.c" mail), then it's just
a matter of increasing the grub_prefix size so that an UUID can fit in it, and
adjusting the install scripts to do it.
Here's a sample (untested) patch to illustrate it.
Then for the Vista use case, I suppose the remaining questions are if NTFS
supports UUIDs (or otherwise we have to ressort to labels?), and if we can
extract filesystem metadata from Windows (if possible without requiring that
a Cygwin installation is present).
--
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 /.)
[-- Attachment #2: uuid_boot.diff --]
[-- Type: text/x-diff, Size: 2359 bytes --]
diff -x ChangeLog -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../tmp.old/include/grub/i386/pc/kernel.h ./include/grub/i386/pc/kernel.h
--- ../tmp.old/include/grub/i386/pc/kernel.h 2008-06-06 18:29:28.000000000 +0200
+++ ./include/grub/i386/pc/kernel.h 2008-06-06 18:32:27.000000000 +0200
@@ -41,7 +41,7 @@
#define GRUB_KERNEL_MACHINE_PREFIX 0x20
/* End of the data section. */
-#define GRUB_KERNEL_MACHINE_DATA_END 0x50
+#define GRUB_KERNEL_MACHINE_DATA_END 0x60
/* The size of the first region which won't be compressed. */
#define GRUB_KERNEL_MACHINE_RAW_SIZE (GRUB_KERNEL_MACHINE_DATA_END + 0x450)
diff -x ChangeLog -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../tmp.old/util/i386/pc/grub-install.in ./util/i386/pc/grub-install.in
--- ../tmp.old/util/i386/pc/grub-install.in 2008-06-06 18:30:02.000000000 +0200
+++ ./util/i386/pc/grub-install.in 2008-06-06 18:33:26.000000000 +0200
@@ -232,13 +232,13 @@ partmap_module=`$grub_probe --target=par
devabstraction_module=`$grub_probe --target=abstraction --device ${grub_device}`
if [ "x${devabstraction_module}" = "x" ] ; then
- prefix_drive=
+ prefix_drive=\(UUID=`$grub_probe --target=fs_uuid --device ${grub_device}`\)
else
prefix_drive=`$grub_probe --target=drive --device ${grub_device}`
fi
# _chain is often useful
-modules="$modules $fs_module $partmap_module biosdisk $devabstraction_module _chain"
+modules="$modules $fs_module $partmap_module biosdisk $devabstraction_module _chain fs_uuid"
$grub_mkimage --output=${grubdir}/core.img \
--prefix=${prefix_drive}`make_system_path_relative_to_its_root ${grubdir}`/ \
diff -x ChangeLog -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../tmp.old/util/i386/pc/grub-setup.c ./util/i386/pc/grub-setup.c
--- ../tmp.old/util/i386/pc/grub-setup.c 2008-06-06 18:30:02.000000000 +0200
+++ ./util/i386/pc/grub-setup.c 2008-06-06 18:32:27.000000000 +0200
@@ -300,7 +300,9 @@ setup (const char *prefix, const char *d
block->segment = 0;
/* Embed information about the installed location. */
- if (must_embed)
+ if (install_prefix[0] == '(')
+ /* If we included a drive explicitly in prefix, force GRUB to use that instead
+ of root_drive. */
*install_dos_part = *install_bsd_part = grub_cpu_to_le32 (-2);
else if (root_dev->disk->partition)
{
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)
2008-06-06 16:43 ` UUID-based boot (Re: [PATCH] Environment block support for grub2) Robert Millan
@ 2008-06-06 17:22 ` Bean
2008-06-06 22:03 ` Robert Millan
2008-06-06 23:31 ` [PATCH] ntfs UUIDs (Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)) Robert Millan
0 siblings, 2 replies; 23+ messages in thread
From: Bean @ 2008-06-06 17:22 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Jun 7, 2008 at 12:43 AM, Robert Millan <rmh@aybabtu.com> wrote:
> Sorry for the delay; it was quite a bit of work as I got hit by a number of
> bugs here and there :-)
>
> Considering that the problem was quite similar to the "boot from LVM" issue
> we already knew about, I thought it'd be a good idea to start with that.
>
> Although not directly related, the patch at in "boot from LVM / RAID" mail I
> just sent would allow to easily boot via UUID as well.
>
> If we add a UUID-based disk driver (see "disk/fs_uuid.c" mail), then it's just
> a matter of increasing the grub_prefix size so that an UUID can fit in it, and
> adjusting the install scripts to do it.
>
> Here's a sample (untested) patch to illustrate it.
I take a quick look at your patch, the method should work, but i
remember okuji oppose embedding device name in prefix, don't know how
he look at it now.
>
> Then for the Vista use case, I suppose the remaining questions are if NTFS
> supports UUIDs (or otherwise we have to ressort to labels?), and if we can
> extract filesystem metadata from Windows (if possible without requiring that
> a Cygwin installation is present).
ntfs has a 64-bit serial number, it's not quite the same as uuid, but
it can be used to identify the partition.
--
Bean
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)
2008-06-06 17:22 ` Bean
@ 2008-06-06 22:03 ` Robert Millan
2008-06-07 4:33 ` Bean
2008-06-07 7:24 ` Vesa Jääskeläinen
2008-06-06 23:31 ` [PATCH] ntfs UUIDs (Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)) Robert Millan
1 sibling, 2 replies; 23+ messages in thread
From: Robert Millan @ 2008-06-06 22:03 UTC (permalink / raw)
To: The development of GRUB 2; +Cc: Yoshinori K. Okuji
On Sat, Jun 07, 2008 at 01:22:23AM +0800, Bean wrote:
> On Sat, Jun 7, 2008 at 12:43 AM, Robert Millan <rmh@aybabtu.com> wrote:
> > Sorry for the delay; it was quite a bit of work as I got hit by a number of
> > bugs here and there :-)
> >
> > Considering that the problem was quite similar to the "boot from LVM" issue
> > we already knew about, I thought it'd be a good idea to start with that.
> >
> > Although not directly related, the patch at in "boot from LVM / RAID" mail I
> > just sent would allow to easily boot via UUID as well.
> >
> > If we add a UUID-based disk driver (see "disk/fs_uuid.c" mail), then it's just
> > a matter of increasing the grub_prefix size so that an UUID can fit in it, and
> > adjusting the install scripts to do it.
> >
> > Here's a sample (untested) patch to illustrate it.
>
> I take a quick look at your patch, the method should work, but i
> remember okuji oppose embedding device name in prefix, don't know how
> he look at it now.
Do you remember why? (or where it was discussed)
Anyway, CCing him. Okuji, please say something! :-)
--
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] 23+ messages in thread
* [PATCH] ntfs UUIDs (Re: UUID-based boot (Re: [PATCH] Environment block support for grub2))
2008-06-06 17:22 ` Bean
2008-06-06 22:03 ` Robert Millan
@ 2008-06-06 23:31 ` Robert Millan
2008-06-07 5:44 ` Tomáš Ebenlendr
1 sibling, 1 reply; 23+ messages in thread
From: Robert Millan @ 2008-06-06 23:31 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 787 bytes --]
On Sat, Jun 07, 2008 at 01:22:23AM +0800, Bean wrote:
> > Then for the Vista use case, I suppose the remaining questions are if NTFS
> > supports UUIDs (or otherwise we have to ressort to labels?), and if we can
> > extract filesystem metadata from Windows (if possible without requiring that
> > a Cygwin installation is present).
>
> ntfs has a 64-bit serial number, it's not quite the same as uuid, but
> it can be used to identify the partition.
This patch adds the 64-bit serial number as UUID. But I'm not sure what is the
"standard" method to stringify this number. Apparently, Windows only prints
half of it in the dir command.
--
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 /.)
[-- Attachment #2: ntfs_uuid.diff --]
[-- Type: text/x-diff, Size: 2181 bytes --]
diff -x ChangeLog -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/fs/ntfs.c ./fs/ntfs.c
--- ../grub2/fs/ntfs.c 2008-05-29 15:02:13.000000000 +0200
+++ ./fs/ntfs.c 2008-06-07 01:28:13.000000000 +0200
@@ -830,6 +830,8 @@ grub_ntfs_mount (grub_disk_t disk)
(disk, data->mft_start, 0, data->mft_size << BLK_SHR, data->mmft.buf))
goto fail;
+ *((grub_uint64_t *) &data->uuid) = bpb.num_serial;
+
if (fixup (data, data->mmft.buf, data->mft_size, "FILE"))
goto fail;
@@ -1078,6 +1080,36 @@ fail:
return grub_errno;
}
+static grub_err_t
+grub_ntfs_uuid (grub_device_t device, char **uuid)
+{
+ struct grub_ntfs_data *data;
+ grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+ grub_dl_ref (my_mod);
+#endif
+
+ data = grub_ntfs_mount (disk);
+ if (data)
+ {
+ *uuid = grub_malloc (sizeof ("xxxx-xxxx-xxxx-xxxx"));
+ grub_sprintf (*uuid, "%04x-%04x-%04x-%04x",
+ grub_le_to_cpu16 (data->uuid[0]), grub_le_to_cpu16 (data->uuid[1]),
+ grub_le_to_cpu16 (data->uuid[2]), grub_le_to_cpu16 (data->uuid[3]));
+ }
+ else
+ *uuid = NULL;
+
+#ifndef GRUB_UTIL
+ grub_dl_unref (my_mod);
+#endif
+
+ grub_free (data);
+
+ return grub_errno;
+}
+
static struct grub_fs grub_ntfs_fs = {
.name = "ntfs",
.dir = grub_ntfs_dir,
@@ -1085,6 +1117,7 @@ static struct grub_fs grub_ntfs_fs = {
.read = grub_ntfs_read,
.close = grub_ntfs_close,
.label = grub_ntfs_label,
+ .uuid = grub_ntfs_uuid,
.next = 0
};
diff -x ChangeLog -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/include/grub/ntfs.h ./include/grub/ntfs.h
--- ../grub2/include/grub/ntfs.h 2008-04-07 16:34:45.000000000 +0200
+++ ./include/grub/ntfs.h 2008-06-07 01:17:44.000000000 +0200
@@ -115,7 +115,7 @@ struct grub_ntfs_bpb
grub_int8_t reserved_4[3];
grub_int8_t clusters_per_index;
grub_int8_t reserved_5[3];
- grub_uint64_t serial_number;
+ grub_uint64_t num_serial;
grub_uint32_t checksum;
} __attribute__ ((packed));
@@ -151,6 +151,7 @@ struct grub_ntfs_data
grub_uint32_t spc;
grub_uint32_t blocksize;
grub_uint32_t mft_start;
+ grub_uint16_t uuid[4];
};
struct grub_ntfs_comp
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)
2008-06-06 22:03 ` Robert Millan
@ 2008-06-07 4:33 ` Bean
2008-06-08 19:26 ` Robert Millan
2008-06-07 7:24 ` Vesa Jääskeläinen
1 sibling, 1 reply; 23+ messages in thread
From: Bean @ 2008-06-07 4:33 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Jun 7, 2008 at 6:03 AM, Robert Millan <rmh@aybabtu.com> wrote:
> On Sat, Jun 07, 2008 at 01:22:23AM +0800, Bean wrote:
>> On Sat, Jun 7, 2008 at 12:43 AM, Robert Millan <rmh@aybabtu.com> wrote:
>> > Sorry for the delay; it was quite a bit of work as I got hit by a number of
>> > bugs here and there :-)
>> >
>> > Considering that the problem was quite similar to the "boot from LVM" issue
>> > we already knew about, I thought it'd be a good idea to start with that.
>> >
>> > Although not directly related, the patch at in "boot from LVM / RAID" mail I
>> > just sent would allow to easily boot via UUID as well.
>> >
>> > If we add a UUID-based disk driver (see "disk/fs_uuid.c" mail), then it's just
>> > a matter of increasing the grub_prefix size so that an UUID can fit in it, and
>> > adjusting the install scripts to do it.
>> >
>> > Here's a sample (untested) patch to illustrate it.
>>
>> I take a quick look at your patch, the method should work, but i
>> remember okuji oppose embedding device name in prefix, don't know how
>> he look at it now.
>
> Do you remember why? (or where it was discussed)
>
> Anyway, CCing him. Okuji, please say something! :-)
Hi,
I find the post:
http://lists.gnu.org/archive/html/grub-devel/2008-02/msg00542.html
--
Bean
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ntfs UUIDs (Re: UUID-based boot (Re: [PATCH] Environment block support for grub2))
2008-06-06 23:31 ` [PATCH] ntfs UUIDs (Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)) Robert Millan
@ 2008-06-07 5:44 ` Tomáš Ebenlendr
2008-06-08 3:34 ` Pavel Roskin
0 siblings, 1 reply; 23+ messages in thread
From: Tomáš Ebenlendr @ 2008-06-07 5:44 UTC (permalink / raw)
To: The development of GRUB 2
Dne 7 Červen 2008, 01:31, Robert Millan napsal(a):
> This patch adds the 64-bit serial number as UUID. But I'm not sure what
> is the "standard" method to stringify this number. Apparently, Windows
> only prints half of it in the dir command.
That seems to me as some backward (pronounce: awkward) compatibility of
M$ Volume ID. Volume ID in M$ windows is (as you say) 'xxxx-xxxx' two
16 bit hexadecimal numbers. And all programs I tested report the number
this way. So if we want user to enter these numbers manually we should
ignore the remaining four bits. Alternatively we can provide utility that
prints out whole serial number.
--
Tomas Ebenlendr
http://drak.ucw.cz/~ebik
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)
2008-06-06 22:03 ` Robert Millan
2008-06-07 4:33 ` Bean
@ 2008-06-07 7:24 ` Vesa Jääskeläinen
1 sibling, 0 replies; 23+ messages in thread
From: Vesa Jääskeläinen @ 2008-06-07 7:24 UTC (permalink / raw)
To: The development of GRUB 2
Robert Millan wrote:
> On Sat, Jun 07, 2008 at 01:22:23AM +0800, Bean wrote:
>> On Sat, Jun 7, 2008 at 12:43 AM, Robert Millan <rmh@aybabtu.com> wrote:
>>> Sorry for the delay; it was quite a bit of work as I got hit by a number of
>>> bugs here and there :-)
>>>
>>> Considering that the problem was quite similar to the "boot from LVM" issue
>>> we already knew about, I thought it'd be a good idea to start with that.
>>>
>>> Although not directly related, the patch at in "boot from LVM / RAID" mail I
>>> just sent would allow to easily boot via UUID as well.
>>>
>>> If we add a UUID-based disk driver (see "disk/fs_uuid.c" mail), then it's just
>>> a matter of increasing the grub_prefix size so that an UUID can fit in it, and
>>> adjusting the install scripts to do it.
>>>
>>> Here's a sample (untested) patch to illustrate it.
>> I take a quick look at your patch, the method should work, but i
>> remember okuji oppose embedding device name in prefix, don't know how
>> he look at it now.
>
> Do you remember why? (or where it was discussed)
>
> Anyway, CCing him. Okuji, please say something! :-)
>
I thinks its related to recovery for server platforms. Anyway... Should
we start creating use cases to wiki in what failure situations grub can
face and then we can see how it can perform those situations.
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ntfs UUIDs (Re: UUID-based boot (Re: [PATCH] Environment block support for grub2))
2008-06-07 5:44 ` Tomáš Ebenlendr
@ 2008-06-08 3:34 ` Pavel Roskin
2008-06-08 19:19 ` Robert Millan
0 siblings, 1 reply; 23+ messages in thread
From: Pavel Roskin @ 2008-06-08 3:34 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, 2008-06-07 at 07:44 +0200, Tomáš Ebenlendr wrote:
> Dne 7 Červen 2008, 01:31, Robert Millan napsal(a):
> > This patch adds the 64-bit serial number as UUID. But I'm not sure what
> > is the "standard" method to stringify this number. Apparently, Windows
> > only prints half of it in the dir command.
>
> That seems to me as some backward (pronounce: awkward) compatibility of
> M$ Volume ID. Volume ID in M$ windows is (as you say) 'xxxx-xxxx' two
> 16 bit hexadecimal numbers. And all programs I tested report the number
> this way. So if we want user to enter these numbers manually we should
> ignore the remaining four bits. Alternatively we can provide utility that
> prints out whole serial number.
I suggest that you check udev sources:
http://www.us.kernel.org/pub/linux/utils/kernel/hotplug/
It calculates UUID for many filesystems (see extras/lib/volime_id/lib).
It would be nice to stay compatible with udev.
--
Regards,
Pavel Roskin
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] ntfs UUIDs (Re: UUID-based boot (Re: [PATCH] Environment block support for grub2))
2008-06-08 3:34 ` Pavel Roskin
@ 2008-06-08 19:19 ` Robert Millan
0 siblings, 0 replies; 23+ messages in thread
From: Robert Millan @ 2008-06-08 19:19 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Jun 07, 2008 at 11:34:39PM -0400, Pavel Roskin wrote:
> On Sat, 2008-06-07 at 07:44 +0200, Tomáš Ebenlendr wrote:
> > Dne 7 Červen 2008, 01:31, Robert Millan napsal(a):
> > > This patch adds the 64-bit serial number as UUID. But I'm not sure what
> > > is the "standard" method to stringify this number. Apparently, Windows
> > > only prints half of it in the dir command.
> >
> > That seems to me as some backward (pronounce: awkward) compatibility of
> > M$ Volume ID. Volume ID in M$ windows is (as you say) 'xxxx-xxxx' two
> > 16 bit hexadecimal numbers. And all programs I tested report the number
> > this way. So if we want user to enter these numbers manually we should
> > ignore the remaining four bits. Alternatively we can provide utility that
> > prints out whole serial number.
>
> I suggest that you check udev sources:
> http://www.us.kernel.org/pub/linux/utils/kernel/hotplug/
>
> It calculates UUID for many filesystems (see extras/lib/volime_id/lib).
> It would be nice to stay compatible with udev.
Ok. I adjusted it to output the same format as vol_id and committed. Turns
out this was the simplest to implement (get a 64-bit LE and print right away).
--
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] 23+ messages in thread
* Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)
2008-06-07 4:33 ` Bean
@ 2008-06-08 19:26 ` Robert Millan
0 siblings, 0 replies; 23+ messages in thread
From: Robert Millan @ 2008-06-08 19:26 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Jun 07, 2008 at 12:33:47PM +0800, Bean wrote:
>
> Hi,
>
> I find the post:
>
> http://lists.gnu.org/archive/html/grub-devel/2008-02/msg00542.html
I completely agree. The patch I sent makes it rely on UUIDs unconditionaly
because it was just a proof of concept, but my intention is to only use UUIDs
when at grub-install time we determined that there's no reliable way to find
the root drive.
I would handle the following cases in the installer:
- If the boot drive is the same as the root drive, the BIOS will tell us
about it at boot time, so we don't use UUIDs.
- If the root drive is LVM or RAID, we can reliably identify it by its
LVM or RAID name, so there's no need to ressort to UUIDs.
- If the boot drive is different than the root drive, often a device.map
guess will work, but not always. So we use UUIDs whenever they're
available.
What do you think?
--
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] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-05-31 15:21 ` [PATCH] Environment block support for grub2 Robert Millan
@ 2008-06-13 22:48 ` Yoshinori K. Okuji
2008-06-14 3:41 ` Bean
0 siblings, 1 reply; 23+ messages in thread
From: Yoshinori K. Okuji @ 2008-06-13 22:48 UTC (permalink / raw)
To: grub-devel; +Cc: Robert Millan
On Saturday 31 May 2008 17:21:25 Robert Millan wrote:
> On Sat, May 31, 2008 at 08:09:50PM +0800, Bean wrote:
> > On Sat, May 31, 2008 at 7:39 PM, Robert Millan <rmh@aybabtu.com> wrote:
> > > I think the method is sound; what I'm complaining about (and it's not
> > > something specific to your patch) is that we're referring to two
> > > different things by the same name ("root"), and even put them in the
> > > same variable.
> > >
> > > In the initialization phase, "root" is the device that contains our
> > > GRUB directory.
> > >
> > > Afterwards, "root" is the device we're currently accessing (be it for
> > > loading fonts, backgrounds, Linux images, whatever).
> > >
> > > If "root" means "just a placeholder for whatever device we're acessing
> > > at the moment", then it would make sense, but in our code (i.e. in the
> > > names we're giving to commands and functions) it's assumed to mean "the
> > > device containing /boot/grub".
> > >
> > > So what do we want to do with this? Should we have different variables
> > > for each thing (and in that case, is "root" for initial stage or for
> > > grub.cfg) or should we use "root" as a placeholder for any path
> > > reference, and adjust our function names etc to reflect that?
> >
> > root is used in loaders as well, we shouldn't change its name. We
> > could use another variable to store the root device at initial stage,
> > it could actually be useful as it always points to the boot media.
> > Perhaps we can name it "boot". What's your idea ?
>
> I'm fine with "boot". I'm CCing Okuji; would like to make sure he doesn't
> have any objections (I think it was he who gave it this layout).
"boot" is used for a command, so it is very confusing to use the same name for
a variable. If you want to have this kind of variable, please find another
name. I myself have no idea.
Okuji
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-06-13 22:48 ` Yoshinori K. Okuji
@ 2008-06-14 3:41 ` Bean
2008-06-14 18:32 ` Robert Millan
0 siblings, 1 reply; 23+ messages in thread
From: Bean @ 2008-06-14 3:41 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Jun 14, 2008 at 6:48 AM, Yoshinori K. Okuji <okuji@enbug.org> wrote:
> On Saturday 31 May 2008 17:21:25 Robert Millan wrote:
>> On Sat, May 31, 2008 at 08:09:50PM +0800, Bean wrote:
>> > On Sat, May 31, 2008 at 7:39 PM, Robert Millan <rmh@aybabtu.com> wrote:
>> > > I think the method is sound; what I'm complaining about (and it's not
>> > > something specific to your patch) is that we're referring to two
>> > > different things by the same name ("root"), and even put them in the
>> > > same variable.
>> > >
>> > > In the initialization phase, "root" is the device that contains our
>> > > GRUB directory.
>> > >
>> > > Afterwards, "root" is the device we're currently accessing (be it for
>> > > loading fonts, backgrounds, Linux images, whatever).
>> > >
>> > > If "root" means "just a placeholder for whatever device we're acessing
>> > > at the moment", then it would make sense, but in our code (i.e. in the
>> > > names we're giving to commands and functions) it's assumed to mean "the
>> > > device containing /boot/grub".
>> > >
>> > > So what do we want to do with this? Should we have different variables
>> > > for each thing (and in that case, is "root" for initial stage or for
>> > > grub.cfg) or should we use "root" as a placeholder for any path
>> > > reference, and adjust our function names etc to reflect that?
>> >
>> > root is used in loaders as well, we shouldn't change its name. We
>> > could use another variable to store the root device at initial stage,
>> > it could actually be useful as it always points to the boot media.
>> > Perhaps we can name it "boot". What's your idea ?
>>
>> I'm fine with "boot". I'm CCing Okuji; would like to make sure he doesn't
>> have any objections (I think it was he who gave it this layout).
>
> "boot" is used for a command, so it is very confusing to use the same name for
> a variable. If you want to have this kind of variable, please find another
> name. I myself have no idea.
Hi,
No problem, I can find another name.
BTW, there are now two schemes for locating device at boot, the
environment block and robert's uuid device, which one do you favor, or
is there other scheme you prefer ?
--
Bean
^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-06-14 3:41 ` Bean
@ 2008-06-14 18:32 ` Robert Millan
2008-06-14 19:22 ` Bean
0 siblings, 1 reply; 23+ messages in thread
From: Robert Millan @ 2008-06-14 18:32 UTC (permalink / raw)
To: The development of GRUB 2
On Sat, Jun 14, 2008 at 11:41:18AM +0800, Bean wrote:
>
> Hi,
>
> No problem, I can find another name.
Sorry, my mistake. I complained about $root being inappropiate for early
stage use, but after that I noticed that $root is used in every stage to
refer to "whatever drive we're currently accessing"; even before $prefix
is initialised!
I'm fine with $root if nobody objects.
> BTW, there are now two schemes for locating device at boot, the
> environment block and robert's uuid device, which one do you favor, or
> is there other scheme you prefer ?
I think there's no problem with having two schemes as long as they don't
take extra core.img space (except for the rare use cases they're intended
to) and don't conflict with each other.
As for the "findroot" approach, I have two comments/ideas:
- Since findroot.mod is basicaly an heuristic, and it's possible we may
want different kinds of methods that work similarly, how about
calling it "findroot_by_file" or something like that? Then we could
have a separate module for "findroot_by_uuid", etc.
- I think your idea has the potential of obsoleting some parts of our
init routines, maybe (if we're lucky) making kernel.img smaller. For
example, we currently make grub_prefix a static length string (could it
be dynamic? -> less space); then try to extract $root from it, since we
embedded it in the same place (if we had a scheme to specify it
separately -> less code to parse it).
--
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] 23+ messages in thread
* Re: [PATCH] Environment block support for grub2
2008-06-14 18:32 ` Robert Millan
@ 2008-06-14 19:22 ` Bean
0 siblings, 0 replies; 23+ messages in thread
From: Bean @ 2008-06-14 19:22 UTC (permalink / raw)
To: The development of GRUB 2
On Sun, Jun 15, 2008 at 2:32 AM, Robert Millan <rmh@aybabtu.com> wrote:
> On Sat, Jun 14, 2008 at 11:41:18AM +0800, Bean wrote:
>>
>> Hi,
>>
>> No problem, I can find another name.
>
> Sorry, my mistake. I complained about $root being inappropiate for early
> stage use, but after that I noticed that $root is used in every stage to
> refer to "whatever drive we're currently accessing"; even before $prefix
> is initialised!
>
> I'm fine with $root if nobody objects.
>
>> BTW, there are now two schemes for locating device at boot, the
>> environment block and robert's uuid device, which one do you favor, or
>> is there other scheme you prefer ?
>
> I think there's no problem with having two schemes as long as they don't
> take extra core.img space (except for the rare use cases they're intended
> to) and don't conflict with each other.
Yes, they can coexist easily. The environment block can overwrite root
variable, so to use uuid fs, just set the root variable, and to use
findroot, set uuid/lable/idfile.
>
> As for the "findroot" approach, I have two comments/ideas:
>
> - Since findroot.mod is basicaly an heuristic, and it's possible we may
> want different kinds of methods that work similarly, how about
> calling it "findroot_by_file" or something like that? Then we could
> have a separate module for "findroot_by_uuid", etc.
Seems fine to me.
>
> - I think your idea has the potential of obsoleting some parts of our
> init routines, maybe (if we're lucky) making kernel.img smaller. For
> example, we currently make grub_prefix a static length string (could it
> be dynamic? -> less space); then try to extract $root from it, since we
> embedded it in the same place (if we had a scheme to specify it
> separately -> less code to parse it).
I think it can be dynamic, we can store it right after the modules.
Although the area is compressed, so we can't use grub-editenv to
change it easily.
--
Bean
^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2008-06-14 19:22 UTC | newest]
Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-05-30 20:27 [PATCH] Environment block support for grub2 Bean
2008-05-31 10:10 ` Robert Millan
2008-05-31 10:54 ` Bean
2008-05-31 11:39 ` Robert Millan
2008-05-31 12:09 ` Bean
2008-05-31 15:09 ` Bean
2008-06-03 21:09 ` Robert Millan
2008-06-04 3:49 ` Bean
2008-06-06 16:43 ` UUID-based boot (Re: [PATCH] Environment block support for grub2) Robert Millan
2008-06-06 17:22 ` Bean
2008-06-06 22:03 ` Robert Millan
2008-06-07 4:33 ` Bean
2008-06-08 19:26 ` Robert Millan
2008-06-07 7:24 ` Vesa Jääskeläinen
2008-06-06 23:31 ` [PATCH] ntfs UUIDs (Re: UUID-based boot (Re: [PATCH] Environment block support for grub2)) Robert Millan
2008-06-07 5:44 ` Tomáš Ebenlendr
2008-06-08 3:34 ` Pavel Roskin
2008-06-08 19:19 ` Robert Millan
2008-05-31 15:21 ` [PATCH] Environment block support for grub2 Robert Millan
2008-06-13 22:48 ` Yoshinori K. Okuji
2008-06-14 3:41 ` Bean
2008-06-14 18:32 ` Robert Millan
2008-06-14 19:22 ` 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.