summaryrefslogtreecommitdiff
path: root/sys-boot/grub/files
diff options
context:
space:
mode:
Diffstat (limited to 'sys-boot/grub/files')
-rwxr-xr-xsys-boot/grub/files/00_fonts14
-rwxr-xr-xsys-boot/grub/files/05_distro_theme51
-rw-r--r--sys-boot/grub/files/grub-0.97-gfxmenu-v8.patch1003
-rw-r--r--sys-boot/grub/files/grub-0.97-uuid.patch5406
-rw-r--r--sys-boot/grub/files/grub-0.97-uuid_doc.patch38
-rw-r--r--sys-boot/grub/files/grub-1.96-genkernel.patch19
-rw-r--r--sys-boot/grub/files/grub-1.97-genkernel.patch28
-rw-r--r--sys-boot/grub/files/grub-1.97-hostdisk.patch60
-rw-r--r--sys-boot/grub/files/grub-1.97-vga-deprecated.patch12
-rw-r--r--sys-boot/grub/files/grub-1.97-wallpaper-settings-support.patch15
-rw-r--r--sys-boot/grub/files/grub-1.98-add-legacy-rootfs-detection.patch83
-rw-r--r--sys-boot/grub/files/grub-1.98-follow-dev-mapper-symlinks.patch25
-rw-r--r--sys-boot/grub/files/grub-1.98-genkernel-initramfs-single.patch11
-rw-r--r--sys-boot/grub/files/grub-1.98-genkernel.patch28
-rw-r--r--sys-boot/grub/files/grub-1.98-wallpaper-settings-support.patch15
-rw-r--r--sys-boot/grub/files/grub-1.99-disable-floppies.patch28
-rw-r--r--sys-boot/grub/files/grub-1.99-genkernel.patch11
-rw-r--r--sys-boot/grub/files/grub-1.99-vga-deprecated-not-yet.patch14
-rw-r--r--sys-boot/grub/files/grub-1.99-vga-deprecated.patch12
-rw-r--r--sys-boot/grub/files/grub-1.99-wallpaper-settings-support.patch15
-rw-r--r--sys-boot/grub/files/grub-1.99-workaround-raid-bios-bug.patch17
-rw-r--r--sys-boot/grub/files/grub-2.00-20_linux_xen.patch14
-rw-r--r--sys-boot/grub/files/grub-2.00-compression.patch84
-rw-r--r--sys-boot/grub/files/grub-2.00-config-quoting.patch113
-rw-r--r--sys-boot/grub/files/grub-2.00-dmraid.patch28
-rw-r--r--sys-boot/grub/files/grub-2.00-freebsd.patch382
-rw-r--r--sys-boot/grub/files/grub-2.00-genkernel-initramfs-single.patch11
-rw-r--r--sys-boot/grub/files/grub-2.00-hardcoded-awk.patch15
-rw-r--r--sys-boot/grub/files/grub-2.00-no-gets.patch22
-rw-r--r--sys-boot/grub/files/grub-2.00-os-prober-efi-system.patch27
-rw-r--r--sys-boot/grub/files/grub-2.00-parallel-make.patch46
-rw-r--r--sys-boot/grub/files/grub-2.00-rogentos-patch.patch10
-rw-r--r--sys-boot/grub/files/grub-2.00-secureboot-user-sign-2.patch64
-rw-r--r--sys-boot/grub/files/grub-2.00-secureboot-user-sign.patch42
-rw-r--r--sys-boot/grub/files/grub-2.00-texinfo.patch16
-rw-r--r--sys-boot/grub/files/grub-2.00-tftp-endian.patch24
-rw-r--r--sys-boot/grub/files/grub-2.00-vga-deprecated-not-yet.patch13
-rw-r--r--sys-boot/grub/files/grub-2.00-wallpaper-settings-support.patch14
-rw-r--r--sys-boot/grub/files/grub-2.00-zfs-feature-flag-support-r1.patch893
-rw-r--r--sys-boot/grub/files/grub-2.00-zfs-feature-flag-support.patch1017
-rw-r--r--sys-boot/grub/files/grub.conf.gentoo16
-rw-r--r--sys-boot/grub/files/grub.default-257
-rw-r--r--sys-boot/grub/files/grub2-default62
-rw-r--r--sys-boot/grub/files/grub2-default-1.9949
-rw-r--r--sys-boot/grub/files/splash.xpm.gzbin0 -> 6251 bytes
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/01_uuids_and_lvm_dont_play_along_nicely.diff14
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/902_boot_blocklist_hack.diff20
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/904_disable_floppies.diff28
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/956_loopback_root.diff139
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/957_handle_loopback.diff45
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/958_linux_no_loopmount.diff20
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/960_raid_virtio.diff158
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/961_dmraid_probe.diff650
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/962_no_device_map.diff112
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/968_hostdisk_speedup.diff310
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/969_lvm_raid_probe.diff227
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/970_fix_locale_installation.diff55
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/971_langpacks.diff30
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/974_drive_probe.diff23
-rw-r--r--sys-boot/grub/files/ubuntu-upstream-1.98/975_hostdisk_hd.diff114
-rw-r--r--sys-boot/grub/files/ubuntu-upstream/01_uuids_and_lvm_dont_play_along_nicely.diff14
-rw-r--r--sys-boot/grub/files/ubuntu-upstream/904_disable_floppies.diff28
62 files changed, 11911 insertions, 0 deletions
diff --git a/sys-boot/grub/files/00_fonts b/sys-boot/grub/files/00_fonts
new file mode 100755
index 00000000..6f5d98b5
--- /dev/null
+++ b/sys-boot/grub/files/00_fonts
@@ -0,0 +1,14 @@
+# Create required fonts, otherwise graphic mode won't be loaded
+if [ -x "/usr/bin/grub2-mkfont" ]; then
+ # This is the bare minimum
+ /usr/bin/grub2-mkfont --output=/boot/grub/unifont.pf2 \
+ /usr/share/fonts/unifont/unifont.pcf.gz
+
+ # let's load DejaVu if exists, no deps against it
+ # to avoid crazy deps on critical pkg
+ if [ -x "/usr/share/fonts/dejavu/DejaVuSans.ttf" ]; then
+ /usr/bin/grub2-mkfont --output=/boot/grub/dejavu.pf2 \
+ /usr/share/fonts/dejavu/DejaVuSans.ttf
+ fi
+
+fi
diff --git a/sys-boot/grub/files/05_distro_theme b/sys-boot/grub/files/05_distro_theme
new file mode 100755
index 00000000..cb4c197c
--- /dev/null
+++ b/sys-boot/grub/files/05_distro_theme
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+
+. /lib/grub/grub-mkconfig_lib
+
+set_blue_theme()
+{
+ cat << EOF
+set menu_color_normal=cyan/blue
+set menu_color_highlight=white/blue
+EOF
+}
+
+# check for usable backgrounds
+use_bg=false
+if [ "$GRUB_TERMINAL_OUTPUT" = "gfxterm" ] && [ -n "${GRUB_WALLPAPER}" ]; then
+ for i in /boot/grub/`basename ${GRUB_WALLPAPER}` ${GRUB_WALLPAPER} ; do
+ if is_path_readable_by_grub $i ; then
+ bg=$i
+ case ${bg} in
+ *.png) reader=png ;;
+ *.tga) reader=tga ;;
+ *.jpg|*.jpeg) reader=jpeg ;;
+ esac
+ if test -e /boot/grub/${reader}.mod ; then
+ echo "Found background image: `basename ${bg}`" >&2
+ use_bg=true
+ break
+ fi
+ fi
+ done
+fi
+
+# set the background if possible
+if ${use_bg} ; then
+ prepare_grub_to_access_device `${grub_probe} --target=device ${bg}`
+ cat << EOF
+insmod ${reader}
+if background_image `make_system_path_relative_to_its_root ${bg}` ; then
+ set color_normal=${GRUB_COLOR_NORMAL}
+ set color_highlight=${GRUB_COLOR_HIGHLIGHT}
+else
+EOF
+fi
+
+# otherwise, set the traditional Debian blue theme
+if ${use_bg} ; then
+ set_blue_theme | sed -e "s/^/ /g"
+ echo "fi"
+else
+ set_blue_theme
+fi
diff --git a/sys-boot/grub/files/grub-0.97-gfxmenu-v8.patch b/sys-boot/grub/files/grub-0.97-gfxmenu-v8.patch
new file mode 100644
index 00000000..7921fc82
--- /dev/null
+++ b/sys-boot/grub/files/grub-0.97-gfxmenu-v8.patch
@@ -0,0 +1,1003 @@
+diff -Nurp grub-0.97.orig/docs/grub.texi grub-0.97/docs/grub.texi
+--- grub-0.97.orig/docs/grub.texi 2009-08-03 16:25:36.636294219 +0200
++++ grub-0.97/docs/grub.texi 2009-08-03 16:25:52.207398764 +0200
+@@ -2118,6 +2118,7 @@ These commands can only be used in the m
+ * default:: Set the default entry
+ * fallback:: Set the fallback entry
+ * hiddenmenu:: Hide the menu interface
++* gfxmenu:: Use graphical menu interface
+ * timeout:: Set the timeout
+ * title:: Start a menu entry
+ @end menu
+@@ -2150,6 +2151,15 @@ fallback entry numbers.
+ @end deffn
+
+
++@node gfxmenu
++@subsection gfxmenu
++
++@deffn Command gfxmenu file
++Use the graphical menu interface. The graphics data are taken from
++@var{file} and must be created using 'mkbootmsg' from the gfxboot package.
++@end deffn
++
++
+ @node hiddenmenu
+ @subsection hiddenmenu
+
+diff -Nurp grub-0.97.orig/grub/asmstub.c grub-0.97/grub/asmstub.c
+--- grub-0.97.orig/grub/asmstub.c 2009-08-03 16:25:36.483169221 +0200
++++ grub-0.97/grub/asmstub.c 2009-08-03 16:25:52.217342924 +0200
+@@ -480,6 +480,32 @@ set_vbe_mode (int mode_number)
+ return 0;
+ }
+
++/* graphical menu functions . */
++int
++gfx_init (gfx_data_t *gfx_data)
++{
++ return 0;
++}
++
++int
++gfx_done (gfx_data_t *gfx_data)
++{
++ return 0;
++}
++
++int
++gfx_input (gfx_data_t *gfx_data, int *menu_entry)
++{
++ return 0;
++}
++
++int
++gfx_setup_menu (gfx_data_t *gfx_data)
++{
++ return 0;
++}
++
++
+ /* low-level timing info */
+ int
+ getrtsecs (void)
+diff -Nurp grub-0.97.orig/stage2/asm.S grub-0.97/stage2/asm.S
+--- grub-0.97.orig/stage2/asm.S 2004-06-19 18:55:22.000000000 +0200
++++ grub-0.97/stage2/asm.S 2009-08-03 16:25:52.218406926 +0200
+@@ -1610,6 +1610,286 @@ ENTRY(set_vbe_mode)
+ popl %ebp
+ ret
+
++
++/*
++ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
++ *
++ * graphical menu functions
++ *
++ */
++
++/*
++ * int gfx_init (gfx_data_t *gfx_data)
++ *
++ * init gfx things
++ *
++ * return vales:
++ * 0: ok
++ * 1: failed
++ * sets gfx_data->ok
++ */
++
++ENTRY(gfx_init)
++ pushl %ebp
++ movl %esp, %ebp
++
++ pushl %edi
++ pushl %esi
++ pushl %ebx
++
++ movl 8(%ebp),%edx
++ movl %edx,%edi
++ leal gfx_ofs_sys_cfg(%edx),%esi
++ andl $0xf,%edi
++ shrl $4,%edx
++
++ pushl %ebp
++
++ call EXT_C(prot_to_real)
++ .code16
++
++ pushw %ds
++ movw %dx,%ds
++
++ lcall *gfx_ofs_jmp_table + 4 * 0 (%di)
++
++ sbbl %ebx,%ebx
++ negl %ebx
++
++ popw %ds
++
++ DATA32 call EXT_C(real_to_prot)
++ .code32
++
++ popl %ebp
++
++ movl %ebx,%eax
++ xorl $1,%ebx
++ movl 8(%ebp),%edx
++ movl %ebx,gfx_ofs_ok(%edx)
++
++ popl %ebx
++ popl %esi
++ popl %edi
++
++ popl %ebp
++ ret
++
++
++/*
++ * int gfx_done (gfx_data_t *gfx_data)
++ *
++ * shut down gfx things
++ *
++ * return vales:
++ * always 0
++ * sets gfx_data->ok
++ */
++
++ENTRY(gfx_done)
++ pushl %ebp
++ movl %esp, %ebp
++
++ pushl %edi
++ pushl %esi
++ pushl %ebx
++
++ movl 8(%ebp),%edx
++ movl %edx,%ebx
++ andl $0xf,%ebx
++ shrl $4,%edx
++
++ pushl %ebp
++
++ call EXT_C(prot_to_real)
++ .code16
++
++ pushw %ds
++
++ movw %dx,%ds
++
++ lcall *gfx_ofs_jmp_table + 4 * 1 (%bx)
++
++ popw %ds
++
++ DATA32 call EXT_C(real_to_prot)
++ .code32
++
++ popl %ebp
++
++ xorl %eax,%eax
++ movl 8(%ebp),%edx
++ movl %eax,gfx_ofs_ok(%edx)
++
++ popl %ebx
++ popl %esi
++ popl %edi
++
++ popl %ebp
++ ret
++
++
++/*
++ * int gfx_input (gfx_data_t *gfx_data, int *menu_entry)
++ *
++ * let user enter a command line
++ *
++ * uses gfx_data->cmdline as buffer
++ *
++ * return values:
++ * 1: abort
++ * 2: boot
++ * menu_entry: selected entry
++ */
++
++ENTRY(gfx_input)
++ pushl %ebp
++ movl %esp, %ebp
++
++ pushl %edi
++ pushl %esi
++ pushl %ebx
++
++ movl 8(%ebp),%edx
++ movl %edx,%ebx
++ leal gfx_ofs_sys_cfg(%edx),%esi
++ andl $0xf,%ebx
++ shrl $4,%edx
++
++ pushl %ebp
++
++ call EXT_C(prot_to_real)
++ .code16
++
++ pushw %ds
++
++ movw %dx,%ds
++
++ movl gfx_ofs_cmdline(%bx),%edi
++ movl gfx_ofs_cmdline_len(%bx),%ecx
++ movl gfx_ofs_timeout(%bx),%eax
++ imull $18,%eax
++
++ lcall *gfx_ofs_jmp_table + 4 * 2 (%bx)
++
++ movl %eax,%ecx
++
++ popw %ds
++
++ DATA32 call EXT_C(real_to_prot)
++ .code32
++
++ popl %ebp
++
++ movl 12(%ebp),%edx
++ movl %ebx,(%edx)
++
++ movl %ecx,%eax
++
++ popl %ebx
++ popl %esi
++ popl %edi
++
++ popl %ebp
++ ret
++
++
++/*
++ * int gfx_setup_menu (gfx_data_t *gfx_data)
++ *
++ * draw boot menu
++ *
++ * return values:
++ * always 0
++ */
++
++/* menu entry descriptor */
++#define menu_entries 0
++#define menu_default 2 /* seg:ofs */
++#define menu_ent_list 6 /* seg:ofs */
++#define menu_ent_size 10
++#define menu_arg_list 12 /* seg:ofs */
++#define menu_arg_size 16
++#define sizeof_menu_desc 18
++
++ENTRY(gfx_setup_menu)
++ pushl %ebp
++ movl %esp, %ebp
++
++ pushl %edi
++ pushl %esi
++ pushl %ebx
++
++ movl 8(%ebp),%edx
++ movl %edx,%ebx
++ andl $0xf,%ebx
++ shrl $4,%edx
++
++ call EXT_C(prot_to_real)
++ .code16
++
++ pushw %ds
++
++ movw %dx,%ds
++ shll $4,%edx
++
++ subw $sizeof_menu_desc,%sp
++ movw %esp,%ebp
++
++ movl gfx_ofs_menu_entries(%bx),%eax
++ movw %ax,menu_entries(%bp)
++
++ movl gfx_ofs_menu_default_entry(%bx),%eax
++ subl %edx,%eax
++ movw %ax,menu_default(%bp)
++ movw %ds,menu_default+2(%bp)
++
++ movl gfx_ofs_menu_list(%bx),%eax
++ subl %edx,%eax
++ movw %ax,menu_ent_list(%bp)
++ movw %ds,menu_ent_list+2(%bp)
++
++ movl gfx_ofs_menu_entry_len(%bx),%eax
++ movw %ax,menu_ent_size(%bp)
++
++ movl gfx_ofs_args_list(%bx),%eax
++ subl %edx,%eax
++ movw %ax,menu_arg_list(%bp)
++ movw %ds,menu_arg_list+2(%bp)
++
++ movl gfx_ofs_args_entry_len(%bx),%eax
++ movw %ax,menu_arg_size(%bp)
++
++ movl %ss,%esi
++ shll $4,%esi
++ addl %ebp,%esi
++
++ lcall %ds: *gfx_ofs_jmp_table + 4 * 3 (%bx)
++
++ addw $sizeof_menu_desc,%sp
++
++ popw %ds
++
++ DATA32 call EXT_C(real_to_prot)
++ .code32
++
++ xorl %eax,%eax
++
++ popl %ebx
++ popl %esi
++ popl %edi
++
++ popl %ebp
++ ret
++
++
++/*
++ *
++ * end graphics stuff
++ *
++ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
++ */
++
+
+ /*
+ * gateA20(int linear)
+diff -Nurp grub-0.97.orig/stage2/builtins.c grub-0.97/stage2/builtins.c
+--- grub-0.97.orig/stage2/builtins.c 2009-08-03 16:25:36.601273171 +0200
++++ grub-0.97/stage2/builtins.c 2009-08-03 16:25:52.219523396 +0200
+@@ -67,6 +67,8 @@ int fallback_entryno;
+ int fallback_entries[MAX_FALLBACK_ENTRIES];
+ /* The number of current entry. */
+ int current_entryno;
++/* graphics file */
++char graphics_file[64];
+ /* The address for Multiboot command-line buffer. */
+ static char *mb_cmdline;
+ /* The password. */
+@@ -1335,6 +1337,26 @@ static struct builtin builtin_fstest =
+ };
+
+
++/* graphics */
++static int
++gfxmenu_func (char *arg, int flags)
++{
++ memmove(graphics_file, arg, sizeof graphics_file - 1);
++ graphics_file[sizeof graphics_file - 1] = 0;
++
++ return 0;
++}
++
++static struct builtin builtin_gfxmenu =
++{
++ "gfxmenu",
++ gfxmenu_func,
++ BUILTIN_MENU | BUILTIN_HELP_LIST,
++ "gfxmenu FILE",
++ "Use the graphical menu from FILE."
++};
++
++
+ /* geometry */
+ static int
+ geometry_func (char *arg, int flags)
+@@ -4989,6 +5011,7 @@ struct builtin *builtin_table[] =
+ &builtin_find,
+ &builtin_fstest,
+ &builtin_geometry,
++ &builtin_gfxmenu,
+ &builtin_halt,
+ &builtin_help,
+ &builtin_hiddenmenu,
+diff -Nurp grub-0.97.orig/stage2/shared.h grub-0.97/stage2/shared.h
+--- grub-0.97.orig/stage2/shared.h 2004-06-19 18:40:09.000000000 +0200
++++ grub-0.97/stage2/shared.h 2009-08-03 16:25:52.219523396 +0200
+@@ -374,6 +374,22 @@ extern char *grub_scratch_mem;
+ #endif /* WITHOUT_LIBC_STUBS */
+
+
++/* see typedef gfx_data_t below */
++#define gfx_ofs_ok 0x00
++#define gfx_ofs_code_seg 0x04
++#define gfx_ofs_jmp_table 0x08
++#define gfx_ofs_sys_cfg 0x38
++#define gfx_ofs_cmdline 0x6c
++#define gfx_ofs_cmdline_len 0x70
++#define gfx_ofs_menu_list 0x74
++#define gfx_ofs_menu_default_entry 0x78
++#define gfx_ofs_menu_entries 0x7c
++#define gfx_ofs_menu_entry_len 0x80
++#define gfx_ofs_args_list 0x84
++#define gfx_ofs_args_entry_len 0x88
++#define gfx_ofs_timeout 0x8c
++
++
+ #ifndef ASM_FILE
+ /*
+ * Below this should be ONLY defines and other constructs for C code.
+@@ -595,6 +611,38 @@ extern int fallback_entryno;
+ extern int default_entry;
+ extern int current_entryno;
+
++
++/*
++ * graphics menu stuff
++ *
++ * Note: gfx_data and all data referred to in it must lie within a 64k area.
++ */
++typedef struct {
++ unsigned ok; /* set while we're in graphics mode */
++ unsigned code_seg; /* code segment of binary graphics code */
++ unsigned jmp_table[12]; /* link to graphics functions */
++ unsigned char sys_cfg[52]; /* sys_cfg[0]: identifies boot loader (grub == 2) */
++ char *cmdline; /* command line returned by gfx_input() */
++ unsigned cmdline_len; /* length of the above */
++ char *menu_list; /* list of menu entries, each of fixed length (menu_entry_len) */
++ char *menu_default_entry; /* the default entry */
++ unsigned menu_entries; /* number of entries in menu_list */
++ unsigned menu_entry_len; /* one entry */
++ char *args_list; /* same structure as menu_list, menu_entries entries */
++ unsigned args_entry_len; /* one entry */
++ unsigned timeout; /* in seconds (0: no timeout) */
++} __attribute__ ((packed)) gfx_data_t;
++
++extern gfx_data_t *graphics_data;
++
++/* pointer to graphics image data */
++extern char graphics_file[64];
++
++int gfx_init(gfx_data_t *gfx_data);
++int gfx_done(gfx_data_t *gfx_data);
++int gfx_input(gfx_data_t *gfx_data, int *menu_entry);
++int gfx_setup_menu(gfx_data_t *gfx_data);
++
+ /* The constants for password types. */
+ typedef enum
+ {
+diff -Nurp grub-0.97.orig/stage2/stage2.c grub-0.97/stage2/stage2.c
+--- grub-0.97.orig/stage2/stage2.c 2005-03-19 18:51:57.000000000 +0100
++++ grub-0.97/stage2/stage2.c 2009-08-03 16:25:52.220523160 +0200
+@@ -22,6 +22,8 @@
+
+ grub_jmp_buf restart_env;
+
++gfx_data_t *graphics_data;
++
+ #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS)
+
+ # if defined(PRESET_MENU_STRING)
+@@ -310,6 +312,12 @@ restart:
+
+ if (! auth && password)
+ {
++ if (*graphics_file)
++ {
++ printf ("\
++ WARNING: graphical menu doesn\'t work\
++ in conjunction with the password feature\n" );
++ }
+ printf ("\
+ Press enter to boot the selected OS or \'p\' to enter a\n\
+ password to unlock the next set of features.");
+@@ -753,6 +761,496 @@ restart:
+ }
+
+
++
++#if 0
++/* for debugging */
++static void hexdump(unsigned char *buf, unsigned len)
++{
++ int i, j = 0;
++ char s[17];
++ unsigned addr = (unsigned) buf;
++
++ s[16] = 0;
++ while(len--) {
++ i = buf[j];
++ i = i & 0xff;
++ s[j & 15] = (i >= 0x20 && i <= 0x7e) ? i : '.';
++ if(!(j & 15)) {
++ printf("%x ", j + addr);
++ }
++ if(!(j & 7) && (j & 15)) printf(" ");
++ /* stupid grub_printf */
++ printf("%x", (i >> 4) & 0x0f);
++ printf("%x ", i & 0x0f);
++ if(!(++j & 15)) {
++ printf(" %s\n", s);
++ }
++ }
++
++ if(j & 15) {
++ s[j & 15] = 0;
++ if(!(j & 8)) printf(" ");
++ i = 1 + 3 * (16 - (j & 15));
++ while(i--) printf(" ");
++ printf("%s\n", s);
++ }
++}
++#endif
++
++
++/* kernel + (grub-)module options */
++#define GFX_CMD_BUF_SIZE 512
++
++/* command line separator char */
++#define GFX_CMD_SEP 1
++
++/*
++ * Go through config entry and find kernel args, if any.
++ * Put things into buf and return it.
++ */
++static char *get_kernel_args(char *cfg, char *buf)
++{
++ int i, j;
++ char *s, *t = "", *p, *t2;
++
++ *(p = buf) = 0;
++
++ for(j = 0; ; j++) {
++ s = get_entry(cfg, j, 0);
++ if(!*s) break;
++ if(
++ (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) &&
++ (s[6] == ' ' || s[6] == '\t')
++ ) {
++ t = skip_to(0, s);
++ t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL;
++ if(*t) t = skip_to(0, t);
++ if(t2 && t2 < t) break; /* module is likely a normal initrd -> skip */
++ i = strlen(t);
++ if(p - buf + i > GFX_CMD_BUF_SIZE - 2) break;
++ *p++ = GFX_CMD_SEP;
++ strcpy(p, t);
++ p += i;
++
++ continue;
++ }
++ }
++
++ if(*buf) buf++; /* skip initial separator char */
++
++ return buf;
++}
++
++
++/*
++ * Check header and return code start offset.
++ */
++static unsigned magic_ok(unsigned char *buf)
++{
++ if(
++ *(unsigned *) buf == 0x0b2d97f00 && /* magic id */
++ (buf[4] == 8) /* version 8 */
++ ) {
++ return *(unsigned *) (buf + 8);
++ }
++
++ return 0;
++}
++
++
++/*
++ * Search cpio archive for gfx file.
++ */
++static unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len)
++{
++ unsigned i, fname_len, code_start = 0;
++
++ *gfx_file_start = 0;
++
++ for(i = 0; i < len;) {
++ if((len - i) >= 0x1a && (buf[i] + (buf[i + 1] << 8)) == 0x71c7) {
++ fname_len = *(unsigned short *) (buf + i + 20);
++ *file_len = *(unsigned short *) (buf + i + 24) + (*(unsigned short *) (buf + i + 22) << 16);
++ i += 26 + fname_len;
++ i = ((i + 1) & ~1);
++ if((code_start = magic_ok(buf + i))) {
++ *gfx_file_start = i;
++ return code_start;
++ }
++ i += *file_len;
++ i = ((i + 1) & ~1);
++ }
++ else {
++ break;
++ }
++ }
++
++ return code_start;
++}
++
++static inline unsigned char * stack_ptr(void)
++{
++ unsigned char * u;
++
++ asm("movl %%esp, %0" : "=r" (u));
++
++ return u;
++}
++
++static void sleep(int delay)
++{
++ int tick, last_tick = currticks();
++
++ delay *= 18;
++
++ while(delay--) {
++ while((tick = currticks()) == last_tick) { }
++ last_tick = tick;
++ }
++}
++
++static void wait_for_key()
++{
++ printf("Press a key to continue...");
++ getkey();
++ printf("\r \r");
++}
++
++
++/*
++ * Leave that much space on the heap. Everything else goes to the graphics
++ * functions.
++ *
++ * 0x2000 is _not_ enough
++ */
++#define MIN_HEAP_SIZE 0x4000
++#define MIN_GFX_FREE 0x1000
++
++#define SC_BOOTLOADER 0
++#define SC_FAILSAFE 3
++#define SC_SYSCONFIG_SIZE 4
++#define SC_BOOTLOADER_SEG 8
++#define SC_XMEM_0 24
++#define SC_XMEM_1 26
++#define SC_XMEM_2 28
++#define SC_XMEM_3 30
++#define SC_FILE 32
++#define SC_ARCHIVE_START 36
++#define SC_ARCHIVE_END 40
++#define SC_MEM0_START 44
++#define SC_MEM0_END 48
++
++/*
++ * Does normally not return.
++ */
++static void
++run_graphics_menu (char *menu_entries, char *config_entries, int num_entries,
++ char *heap, int entryno)
++{
++ unsigned char *buf, *buf_ext;
++ unsigned buf_size, buf_ext_size, code_start, file_start;
++ char *s, *t, *t2, *cfg, *new_config, *p;
++ char *saved_heap;
++ int i, j, max_len, gfx_file_size, verbose;
++ int selected_entry;
++ gfx_data_t *gfx_data;
++ char *cmd_buf;
++ unsigned mem0_start, mem0_end, file_len;
++
++ /*
++ * check gfx_data_t struct offsets for consistency; gcc will optimize away
++ * the whole block
++ */
++
++ /* dummy function to make ld fail */
++ {
++ extern void wrong_struct_size(void);
++ #define gfx_ofs_check(a) if(gfx_ofs_##a != (char *) &gfx_data->a - (char *) gfx_data) wrong_struct_size();
++ gfx_ofs_check(ok);
++ gfx_ofs_check(code_seg);
++ gfx_ofs_check(jmp_table);
++ gfx_ofs_check(sys_cfg);
++ gfx_ofs_check(cmdline);
++ gfx_ofs_check(cmdline_len);
++ gfx_ofs_check(menu_list);
++ gfx_ofs_check(menu_default_entry);
++ gfx_ofs_check(menu_entries);
++ gfx_ofs_check(menu_entry_len);
++ gfx_ofs_check(args_list);
++ gfx_ofs_check(args_entry_len);
++ gfx_ofs_check(timeout);
++ #undef gfx_ofs_check
++ }
++
++ if(!num_entries) return;
++
++ graphics_data = gfx_data = (gfx_data_t *) heap;
++ heap += sizeof *gfx_data;
++ memset(gfx_data, 0, sizeof *gfx_data);
++
++ gfx_data->sys_cfg[SC_BOOTLOADER] = 2; /* bootloader: grub */
++ gfx_data->sys_cfg[SC_SYSCONFIG_SIZE] = 52; /* config data size */
++ *(unsigned short *) (gfx_data->sys_cfg + SC_BOOTLOADER_SEG) = (unsigned) gfx_data >> 4; /* segment */
++ gfx_data->sys_cfg[SC_XMEM_0] = 0x28; /* 8MB @ 2MB, see buf_ext below */
++ // gfx_data->sys_cfg[SC_XMEM_1] = 0xYZ; /* Z MB @ Y MB */
++ verbose = (*(unsigned char *) 0x417) & 3 ? 1 : 0; /* SHIFT pressed */
++ gfx_data->sys_cfg[SC_FAILSAFE] = verbose;
++
++ gfx_data->timeout = grub_timeout >= 0 ? grub_timeout : 0;
++
++
++ /* setup command line edit buffer */
++
++ gfx_data->cmdline_len = 256;
++
++ gfx_data->cmdline = heap;
++ heap += gfx_data->cmdline_len;
++ memset(gfx_data->cmdline, 0, gfx_data->cmdline_len);
++
++ cmd_buf = heap;
++ heap += GFX_CMD_BUF_SIZE;
++
++ /* setup menu entries */
++
++ for(i = max_len = 0; i < num_entries; i++) {
++ j = strlen(get_entry(menu_entries, i, 0));
++ if(j > max_len) max_len = j;
++ }
++
++ if(!max_len) return;
++
++ gfx_data->menu_entry_len = max_len + 1;
++ gfx_data->menu_entries = num_entries;
++
++ gfx_data->menu_list = heap;
++ heap += gfx_data->menu_entry_len * gfx_data->menu_entries;
++
++ memset(gfx_data->menu_list, 0, gfx_data->menu_entry_len * gfx_data->menu_entries);
++
++ for(i = 0; i < (int) gfx_data->menu_entries; i++) {
++ strcpy(gfx_data->menu_list + i * gfx_data->menu_entry_len, get_entry(menu_entries, i, 0));
++ }
++
++ gfx_data->menu_default_entry = gfx_data->menu_list + entryno * gfx_data->menu_entry_len;
++
++
++ /* setup list of kernel args */
++
++ for(i = max_len = 0; i < num_entries; i++) {
++ s = get_kernel_args(get_entry(config_entries, i, 1), cmd_buf);
++ j = strlen(s);
++ if(j > max_len) max_len = j;
++ }
++
++ gfx_data->args_entry_len = max_len + 1;
++
++ gfx_data->args_list = heap;
++ heap += gfx_data->args_entry_len * gfx_data->menu_entries;
++
++ memset(gfx_data->args_list, 0, gfx_data->args_entry_len * gfx_data->menu_entries);
++
++ for(i = 0; i < (int) gfx_data->menu_entries; i++) {
++ strcpy(gfx_data->args_list + i* gfx_data->args_entry_len, get_kernel_args(get_entry(config_entries, i, 1), cmd_buf));
++ }
++
++
++ /* go back here when we no longer need the graphics data */
++ saved_heap = heap;
++
++
++ /* get memory area to be used by graphics functions */
++
++ /* use 8MB starting at 2MB as file buffer; see SC_XMEM_0 above (A20 is enabled anyway) */
++ buf_ext = (unsigned char *) (2 << 20);
++ buf_ext_size = 8 << 20;
++
++ /* must be 16-byte aligned */
++ buf = (unsigned char *) (((unsigned) heap + 0xf) & ~0xf);
++
++ buf_size = stack_ptr() - buf - MIN_HEAP_SIZE;
++ buf_size &= ~0xf;
++
++ mem0_start = (unsigned) buf;
++ mem0_end = mem0_start + buf_size;
++
++ if(verbose) {
++ printf("low memory 0x%x - 0x%x (%d bytes)\n", mem0_start, mem0_end, buf_size);
++ wait_for_key();
++ }
++
++ heap += buf_size;
++
++ /* read the file */
++
++ if(!grub_open(graphics_file)) {
++ printf("%s: file not found\n", graphics_file);
++ sleep(5);
++ heap = saved_heap;
++ return;
++ }
++
++ gfx_file_size = grub_read(buf_ext, buf_ext_size);
++
++ grub_close();
++
++ if(gfx_file_size <= 0) {
++ printf("%s: read error\n", graphics_file);
++ sleep(5);
++ heap = saved_heap;
++ return;
++ }
++
++ if(verbose) {
++ printf("%s: %d bytes (%d bytes left)\n", graphics_file, gfx_file_size, buf_ext_size - gfx_file_size);
++ wait_for_key();
++ }
++
++ /* locate file inside cpio archive */
++ if(!(code_start = find_file(buf_ext, gfx_file_size, &file_start, &file_len))) {
++ printf("%s: invalid file format\n", graphics_file);
++ sleep(5);
++ heap = saved_heap;
++ return;
++ }
++
++ if(verbose) {
++ printf("init: start 0x%x, len %d; code offset 0x%x\n", file_start, file_len, code_start);
++ wait_for_key();
++ }
++
++ if(file_len - code_start + MIN_GFX_FREE > buf_size) {
++ printf("not enough free memory: %d extra bytes need\n", file_len - code_start + MIN_GFX_FREE - buf_size);
++ sleep(5);
++ heap = saved_heap;
++ return;
++ }
++
++ memcpy((void *) buf, (void *) (buf_ext + file_start + code_start), file_len - code_start);
++
++ mem0_start += file_len - code_start;
++ mem0_start = (mem0_start + 3) & ~3; /* align */
++
++ /* init interface to graphics functions */
++
++ *(unsigned *) (gfx_data->sys_cfg + SC_FILE) = (unsigned) buf_ext + file_start;
++ *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_START) = (unsigned) buf_ext;
++ *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_END) = (unsigned) buf_ext + gfx_file_size;
++ *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_START) = mem0_start;
++ *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_END) = mem0_end;
++
++ gfx_data->code_seg = (unsigned) buf >> 4;
++
++ if(verbose) {
++ printf("init 0x%x, archive 0x%x - 0x%x, low mem 0x%x - 0x%x\ncode seg 0x%x\n",
++ (unsigned) buf_ext + file_start,
++ (unsigned) buf_ext, (unsigned) buf_ext + gfx_file_size,
++ mem0_start, mem0_end, gfx_data->code_seg
++ );
++ wait_for_key();
++ }
++
++ for(i = 0; (unsigned) i < sizeof gfx_data->jmp_table / sizeof *gfx_data->jmp_table; i++) {
++ gfx_data->jmp_table[i] = (gfx_data->code_seg << 16) + ((unsigned short *) buf)[i];
++ }
++
++ if(verbose) {
++ for(i = 0; i < 12; i++) {
++ printf("%d: 0x%x\n", i, gfx_data->jmp_table[i]);
++ }
++
++ for(i = 0; i < gfx_data->menu_entries; i++) {
++ printf("\"%s\" -- \"%s\"\n",
++ gfx_data->menu_list + i * gfx_data->menu_entry_len,
++ gfx_data->args_list + i * gfx_data->args_entry_len
++ );
++ }
++
++ printf("default: \"%s\"\n", gfx_data->menu_default_entry);
++ wait_for_key();
++ }
++
++ /* switch to graphics mode */
++
++ if(gfx_init(gfx_data)) {
++ printf("graphics initialization failed\n");
++ sleep(5);
++ heap = saved_heap;
++ return;
++ }
++
++ gfx_setup_menu(gfx_data);
++
++ i = gfx_input(gfx_data, &selected_entry);
++
++ /* ESC -> show text menu */
++ if(i == 1) {
++ gfx_done(gfx_data);
++ grub_timeout = -1;
++
++ heap = saved_heap;
++ return;
++ }
++
++ gfx_done(gfx_data);
++
++ heap = saved_heap; /* free most of the graphics data */
++
++ // printf("cmdline: >%s<, entry = %d\n", gfx_data->cmdline, selected_entry);
++
++ if(selected_entry < 0 || selected_entry > num_entries) return;
++
++ /* for 'savedefault' */
++ current_entryno = selected_entry;
++
++
++ /* create new config with modified kernel option */
++
++ cfg = get_entry(config_entries, selected_entry, 1);
++
++ new_config = heap;
++
++ for(p = gfx_data->cmdline, i = 0; ; i++) {
++ s = get_entry(cfg, i, 0);
++ if(!*s) {
++ if(!i) *heap++ = 0;
++ *heap++ = 0;
++ break;
++ }
++ /* note: must match get_kernel_args() */
++ if(
++ (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) &&
++ (s[6] == ' ' || s[6] == '\t')
++ ) {
++ t = skip_to(0, s);
++ t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL;
++ if(*t) t = skip_to(0, t);
++ if(t2 && t2 < t) { /* module is likely a normal initrd -> skip */
++ strcpy(heap, s);
++ heap += strlen(s) + 1;
++ continue;
++ }
++ memmove(heap, s, t - s);
++ heap += t - s;
++ *heap++ = ' ';
++ while(*p && *p != GFX_CMD_SEP) *heap++ = *p++;
++ *heap++ = 0;
++ if(*p == GFX_CMD_SEP) p++;
++ }
++ else {
++ strcpy(heap, s);
++ heap += strlen(s) + 1;
++ }
++ }
++
++ *heap++ = 0;
++
++ // hexdump(new_config, heap - new_config);
++ // getkey();
++
++ run_script(new_config, heap);
++}
++
++
+ static int
+ get_line_from_config (char *cmdline, int maxlen, int read_from_file)
+ {
+@@ -1059,9 +1557,12 @@ cmain (void)
+ }
+ else
+ {
+- /* Run menu interface. */
+- run_menu (menu_entries, config_entries, num_entries,
+- menu_entries + menu_len, default_entry);
++ if (*graphics_file && !password && show_menu && grub_timeout)
++ {
++ run_graphics_menu(menu_entries, config_entries, num_entries,menu_entries + menu_len, default_entry);
++ }
++ /* Run menu interface. */
++ run_menu (menu_entries, config_entries, num_entries, menu_entries + menu_len, default_entry);
+ }
+ }
+ }
diff --git a/sys-boot/grub/files/grub-0.97-uuid.patch b/sys-boot/grub/files/grub-0.97-uuid.patch
new file mode 100644
index 00000000..f99670a8
--- /dev/null
+++ b/sys-boot/grub/files/grub-0.97-uuid.patch
@@ -0,0 +1,5406 @@
+=== modified file 'Makefile.am'
+--- grub-0.97.orig/Makefile.am 2004-04-23 13:39:01 +0000
++++ grub-0.97/Makefile.am 2008-07-09 17:23:44 +0000
+@@ -1,4 +1,9 @@
+ # Do not change this order if you don't know what you are doing.
+ AUTOMAKE_OPTIONS = 1.7 gnu
+-SUBDIRS = netboot stage2 stage1 lib grub util docs
++if UUID_SUPPORT
++SUBDIRS = libvolume_id netboot stage2 stage1 lib grub util docs
++else
++SUBDIRS = netboot stage2 stage1 lib grub util docs
++endif
++
+ EXTRA_DIST = BUGS MAINTENANCE
+
+=== modified file 'configure.ac'
+--- grub-0.97.orig/configure.ac 2008-01-28 18:41:45 +0000
++++ grub-0.97/configure.ac 2008-07-09 17:23:44 +0000
+@@ -605,6 +606,11 @@
+ [ --disable-serial disable serial terminal support])
+ AM_CONDITIONAL(SERIAL_SUPPORT, test "x$enable_serial" != xno)
+
++dnl UUID scanning
++AC_ARG_ENABLE(uuid,
++ [ --disable-uuid disable uuid scanning support])
++AM_CONDITIONAL(UUID_SUPPORT, test "x$enable_uuid" != xno)
++
+ dnl Simulation of the slowness of a serial device.
+ AC_ARG_ENABLE(serial-speed-simulation,
+ [ --enable-serial-speed-simulation
+@@ -666,5 +672,6 @@
+ docs/Makefile lib/Makefile util/Makefile \
+ grub/Makefile netboot/Makefile util/grub-image \
+ util/grub-install util/grub-md5-crypt \
+- util/grub-terminfo util/grub-set-default])
++ util/grub-terminfo util/grub-set-default \
++ libvolume_id/Makefile])
+ AC_OUTPUT
+
+=== modified file 'grub/Makefile.am'
+--- grub-0.97.orig/grub/Makefile.am 2005-02-02 20:40:05 +0000
++++ grub-0.97/grub/Makefile.am 2008-07-09 17:23:44 +0000
+@@ -16,4 +16,9 @@
+ AM_CFLAGS = $(GRUB_CFLAGS)
+
+ grub_SOURCES = main.c asmstub.c
+-grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS)
++
++if UUID_SUPPORT
++grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a ../libvolume_id/libvolume_id.a $(GRUB_LIBS)
++else
++grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS)
++endif
+
+=== added directory 'libvolume_id'
+=== added file 'libvolume_id/Makefile.am'
+--- grub-0.97.orig/libvolume_id/Makefile.am 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/Makefile.am 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,27 @@
++noinst_LIBRARIES = libvolume_id.a
++
++AM_CFLAGS = $(STAGE2_CFLAGS) -I$(top_srcdir)/stage2 -I$(top_srcdir)/stage1
++
++LIBVOLUME_ID_FS_SUPPORTED = ext.c fat.c hfs.c jfs.c \
++ luks.c ntfs.c ocfs.c reiserfs.c \
++ xfs.c
++
++LIBVOLUME_ID_FS_UNSUPPORTED = cramfs.c gfs.c hpfs.c iso9660.c \
++ lvm.c minix.c romfs.c squashfs.c \
++ sysv.c udf.c ufs.c vxfs.c
++
++LIBVOLUME_ID_RAID_SUPPORTED = ddf_raid.c
++
++LIBVOLUME_ID_RAID_UNSUPPORTED = adaptec_raid.c highpoint.c isw_raid.c \
++ jmicron_raid.c linux_raid.c lsi_raid.c \
++ nvidia_raid.c promise_raid.c silicon_raid.c \
++ via_raid.c
++
++LIBVOLUME_ID_MISC_UNSUPPORTED = linux_swap.c netware.c
++
++libvolume_id_a_SOURCES = $(LIBVOLUME_ID_FS_SUPPORTED) \
++ $(LIBVOLUME_ID_RAID_SUPPORTED) \
++ $(LIBVOLUME_ID_FS_UNSUPPORTED) \
++ $(LIBVOLUME_ID_RAID_UNSUPPORTED) \
++ volume_id.h volume_id.c util.c util.h misc.c
++
+
+=== added file 'libvolume_id/adaptec_raid.c'
+--- grub-0.97.orig/libvolume_id/adaptec_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/adaptec_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,107 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct adaptec_meta {
++ uint32_t b0idcode;
++ uint8_t lunsave[8];
++ uint16_t sdtype;
++ uint16_t ssavecyl;
++ uint8_t ssavehed;
++ uint8_t ssavesec;
++ uint8_t sb0flags;
++ uint8_t jbodEnable;
++ uint8_t lundsave;
++ uint8_t svpdirty;
++ uint16_t biosInfo;
++ uint16_t svwbskip;
++ uint16_t svwbcln;
++ uint16_t svwbmax;
++ uint16_t res3;
++ uint16_t svwbmin;
++ uint16_t res4;
++ uint16_t svrcacth;
++ uint16_t svwcacth;
++ uint16_t svwbdly;
++ uint8_t svsdtime;
++ uint8_t res5;
++ uint16_t firmval;
++ uint16_t firmbln;
++ uint32_t firmblk;
++ uint32_t fstrsvrb;
++ uint16_t svBlockStorageTid;
++ uint16_t svtid;
++ uint8_t svseccfl;
++ uint8_t res6;
++ uint8_t svhbanum;
++ uint8_t resver;
++ uint32_t drivemagic;
++ uint8_t reserved[20];
++ uint8_t testnum;
++ uint8_t testflags;
++ uint16_t maxErrorCount;
++ uint32_t count;
++ uint32_t startTime;
++ uint32_t interval;
++ uint8_t tstxt0;
++ uint8_t tstxt1;
++ uint8_t serNum[32];
++ uint8_t res8[102];
++ uint32_t fwTestMagic;
++ uint32_t fwTestSeqNum;
++ uint8_t fwTestRes[8];
++ uint8_t smagic[4];
++ uint32_t raidtbl;
++ uint16_t raidline;
++ uint8_t res9[0xF6];
++} PACKED;
++
++int volume_id_probe_adaptec_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct adaptec_meta *ad;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x10000)
++ return -1;
++
++ meta_off = ((size / 0x200)-1) * 0x200;
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ ad = (struct adaptec_meta *) buf;
++ if (memcmp((char*)ad->smagic, "DPTM", 4) != 0)
++ return -1;
++
++ if (ad->b0idcode != be32_to_cpu(0x37FC4D1E))
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u", ad->resver);
++ id->type = "adaptec_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/cramfs.c'
+--- grub-0.97.orig/libvolume_id/cramfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/cramfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,60 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct cramfs_super {
++ uint8_t magic[4];
++ uint32_t size;
++ uint32_t flags;
++ uint32_t future;
++ uint8_t signature[16];
++ struct cramfs_info {
++ uint32_t crc;
++ uint32_t edition;
++ uint32_t blocks;
++ uint32_t files;
++ } PACKED info;
++ uint8_t name[16];
++} PACKED;
++
++int volume_id_probe_cramfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct cramfs_super *cs;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ cs = (struct cramfs_super *) volume_id_get_buffer(id, off, 0x200);
++ if (cs == NULL)
++ return -1;
++
++ if (memcmp((char*)cs->magic, "\x45\x3d\xcd\x28", 4) == 0 || memcmp((char*)cs->magic, "\x28\xcd\x3d\x45", 4) == 0) {
++ volume_id_set_label_raw(id, cs->name, 16);
++ volume_id_set_label_string(id, cs->name, 16);
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "cramfs";
++ return 0;
++ }
++
++ return -1;
++}
+
+=== added file 'libvolume_id/ddf_raid.c'
+--- grub-0.97.orig/libvolume_id/ddf_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ddf_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,60 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++/* http://www.snia.org/standards/home */
++
++#define DDF_HEADER 0xDE11DE11
++#define DDF_GUID_LENGTH 24
++#define DDF_REV_LENGTH 8
++
++static struct ddf_header {
++ uint32_t signature;
++ uint32_t crc;
++ uint8_t guid[DDF_GUID_LENGTH];
++ uint8_t ddf_rev[DDF_REV_LENGTH];
++} PACKED *ddf;
++
++int volume_id_probe_ddf_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint64_t ddf_off = ((size / 0x200)-1) * 0x200;
++ const uint8_t *buf;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++ if (size < 0x10000)
++ return -1;
++
++ buf = volume_id_get_buffer(id, off + ddf_off, 0x200);
++ if (buf == NULL)
++ return -1;
++ ddf = (struct ddf_header *) buf;
++
++ if (ddf->signature != cpu_to_be32(DDF_HEADER))
++ return -1;
++
++ volume_id_set_uuid(id, ddf->guid, DDF_GUID_LENGTH, UUID_STRING);
++ strcpy(id->type_version, (char*) ddf->ddf_rev);
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "ddf_raid_member";
++ return 0;
++}
+
+=== added file 'libvolume_id/ext.c'
+--- grub-0.97.orig/libvolume_id/ext.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ext.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,129 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct ext2_super_block {
++ uint32_t s_inodes_count;
++ uint32_t s_blocks_count;
++ uint32_t s_r_blocks_count;
++ uint32_t s_free_blocks_count;
++ uint32_t s_free_inodes_count;
++ uint32_t s_first_data_block;
++ uint32_t s_log_block_size;
++ uint32_t s_log_frag_size;
++ uint32_t s_blocks_per_group;
++ uint32_t s_frags_per_group;
++ uint32_t s_inodes_per_group;
++ uint32_t s_mtime;
++ uint32_t s_wtime;
++ uint16_t s_mnt_count;
++ uint16_t s_max_mnt_count;
++ uint16_t s_magic;
++ uint16_t s_state;
++ uint16_t s_errors;
++ uint16_t s_minor_rev_level;
++ uint32_t s_lastcheck;
++ uint32_t s_checkinterval;
++ uint32_t s_creator_os;
++ uint32_t s_rev_level;
++ uint16_t s_def_resuid;
++ uint16_t s_def_resgid;
++ uint32_t s_first_ino;
++ uint16_t s_inode_size;
++ uint16_t s_block_group_nr;
++ uint32_t s_feature_compat;
++ uint32_t s_feature_incompat;
++ uint32_t s_feature_ro_compat;
++ uint8_t s_uuid[16];
++ uint8_t s_volume_name[16];
++} PACKED;
++
++#define EXT_SUPER_MAGIC 0xEF53
++#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
++#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
++#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
++#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
++#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
++
++#define EXT_SUPERBLOCK_OFFSET 0x400
++
++#define EXT3_MIN_BLOCK_SIZE 0x400
++#define EXT3_MAX_BLOCK_SIZE 0x1000
++
++int volume_id_probe_ext(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct ext2_super_block *es;
++ size_t bsize;
++ uint32_t feature_compat;
++ uint32_t feature_incompat;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ es = (struct ext2_super_block *) volume_id_get_buffer(id, off + EXT_SUPERBLOCK_OFFSET, 0x200);
++ if (es == NULL)
++ return -1;
++
++ if (es->s_magic != cpu_to_le16(EXT_SUPER_MAGIC))
++ return -1;
++
++ bsize = 0x400 << le32_to_cpu(es->s_log_block_size);
++ dbg("ext blocksize 0x%zx", bsize);
++ if (bsize < EXT3_MIN_BLOCK_SIZE || bsize > EXT3_MAX_BLOCK_SIZE) {
++ dbg("invalid ext blocksize");
++ return -1;
++ }
++
++ volume_id_set_label_raw(id, es->s_volume_name, 16);
++ volume_id_set_label_string(id, es->s_volume_name, 16);
++ volume_id_set_uuid(id, es->s_uuid, 0, UUID_DCE);
++ sprintf(id->type_version, "%u.%u",
++ le32_to_cpu(es->s_rev_level), le16_to_cpu(es->s_minor_rev_level));
++
++ feature_compat = le32_to_cpu(es->s_feature_compat);
++ feature_incompat = le32_to_cpu(es->s_feature_incompat);
++
++ /* check for external journal device */
++ if ((feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) != 0) {
++ volume_id_set_usage(id, VOLUME_ID_OTHER);
++ id->type = "jbd";
++ goto out;
++ }
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++
++ if ((feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) != 0 ||
++ (feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0 ||
++ (feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) != 0) {
++ id->type = "ext4";
++ goto out;
++ }
++
++ if ((feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) != 0) {
++ id->type = "ext3";
++ goto out;
++ }
++
++ id->type = "ext2";
++
++out:
++ return 0;
++}
+
+=== added file 'libvolume_id/fat.c'
+--- grub-0.97.orig/libvolume_id/fat.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/fat.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,482 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004-2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Copyright (C) 2007 Ryan Lortie <desrt@desrt.ca>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define FAT12_MAX 0xff5
++#define FAT16_MAX 0xfff5
++#define FAT_ATTR_VOLUME_ID 0x08
++#define FAT_ATTR_DIR 0x10
++#define FAT_ATTR_LONG_NAME 0x0f
++#define FAT_ATTR_MASK 0x3f
++#define FAT_ENTRY_FREE 0xe5
++
++#define VFAT_LFN_SEQ_MASK 0x3f
++#define VFAT_LFN_SEQ_LAST 0x40
++#define VFAT_LFN_SEQ_MAX 20
++#define VFAT_LFN_CHARS_PER_ENTRY (5 + 6 + 2)
++#define VFAT_LOWERCASE_NAME 0x10
++#define VFAT_LOWERCASE_EXT 0x08
++
++struct vfat_super_block {
++ uint8_t boot_jump[3];
++ uint8_t sysid[8];
++ uint16_t sector_size;
++ uint8_t sectors_per_cluster;
++ uint16_t reserved;
++ uint8_t fats;
++ uint16_t dir_entries;
++ uint16_t sectors;
++ uint8_t media;
++ uint16_t fat_length;
++ uint16_t secs_track;
++ uint16_t heads;
++ uint32_t hidden;
++ uint32_t total_sect;
++ union {
++ struct fat_super_block {
++ uint8_t unknown[3];
++ uint8_t serno[4];
++ uint8_t label[11];
++ uint8_t magic[8];
++ uint8_t dummy2[192];
++ uint8_t pmagic[2];
++ } PACKED fat;
++ struct fat32_super_block {
++ uint32_t fat32_length;
++ uint16_t flags;
++ uint8_t version[2];
++ uint32_t root_cluster;
++ uint16_t fsinfo_sector;
++ uint16_t backup_boot;
++ uint16_t reserved2[6];
++ uint8_t unknown[3];
++ uint8_t serno[4];
++ uint8_t label[11];
++ uint8_t magic[8];
++ uint8_t dummy2[164];
++ uint8_t pmagic[2];
++ } PACKED fat32;
++ } PACKED type;
++} PACKED;
++
++struct fat32_fsinfo {
++ uint8_t signature1[4];
++ uint32_t reserved1[120];
++ uint8_t signature2[4];
++ uint32_t free_clusters;
++ uint32_t next_cluster;
++ uint32_t reserved2[4];
++} PACKED;
++
++struct vfat_dir_entry {
++ uint8_t name[11];
++ uint8_t attr;
++ uint8_t lowercase;
++ uint8_t fine_time_creat;
++ uint16_t time_creat;
++ uint16_t date_creat;
++ uint16_t date_acc;
++ uint16_t cluster_high;
++ uint16_t time_write;
++ uint16_t date_write;
++ uint16_t cluster_low;
++ uint32_t size;
++} PACKED;
++
++
++struct vfat_lfn_entry {
++ uint8_t seq;
++ uint16_t name0[5];
++ uint8_t attr;
++ uint8_t reserved;
++ uint8_t cksum;
++ uint16_t name1[6];
++ uint16_t cluster;
++ uint16_t name2[2];
++} PACKED;
++
++static uint8_t fat_lfn_checksum(const uint8_t name[11])
++{
++ uint8_t cksum = 0;
++ int i;
++
++ /* http://en.wikipedia.org/wiki/File_Allocation_Table */
++ for (i = 0; i < 11; i++)
++ cksum = ((cksum & 1) ? 0x80 : 0) + (cksum >> 1) + name[i];
++
++ return cksum;
++}
++
++static size_t fat_read_lfn(uint8_t *filename, size_t fnsize,
++ struct vfat_dir_entry *direntry,
++ struct vfat_dir_entry *entry)
++{
++ uint8_t buffer[VFAT_LFN_SEQ_MAX * VFAT_LFN_CHARS_PER_ENTRY * 2];
++ uint8_t expected_seq = 1;
++ uint8_t cksum;
++ size_t len = 0;
++ size_t fnlen = 0;
++
++ cksum = fat_lfn_checksum(entry->name);
++
++ while (--entry >= direntry) {
++ struct vfat_lfn_entry *lfn = (struct vfat_lfn_entry *) entry;
++
++ if (expected_seq > VFAT_LFN_SEQ_MAX)
++ break;
++
++ if ((lfn->attr & FAT_ATTR_MASK) != FAT_ATTR_LONG_NAME)
++ break;
++
++ if (lfn->cksum != cksum)
++ break;
++
++ if ((lfn->seq & VFAT_LFN_SEQ_MASK) != expected_seq++)
++ break;
++
++ if (lfn->cluster != 0)
++ break;
++
++ /* extra paranoia -- should never happen */
++ if (len + sizeof(lfn->name0) + sizeof(lfn->name1) +
++ sizeof(lfn->name2) > sizeof(buffer))
++ break;
++
++ memcpy (&buffer[len], lfn->name0, sizeof(lfn->name0));
++ len += sizeof(lfn->name0);
++ memcpy (&buffer[len], lfn->name1, sizeof(lfn->name1));
++ len += sizeof(lfn->name1);
++ memcpy (&buffer[len], lfn->name2, sizeof(lfn->name2));
++ len += sizeof(lfn->name2);
++
++ if (lfn->seq & VFAT_LFN_SEQ_LAST) {
++ fnlen = volume_id_set_unicode16(filename, fnsize, buffer, LE, len);
++ break;
++ }
++ }
++
++ return fnlen;
++}
++
++static size_t fat_read_filename(uint8_t *filename, size_t fnsize,
++ struct vfat_dir_entry *direntry, struct vfat_dir_entry *entry)
++{
++ size_t len;
++ int i;
++
++ /* check if maybe we have LFN entries */
++ len = fat_read_lfn(filename, fnsize, direntry, entry);
++ if (len > 0)
++ goto out;
++
++ /* else, read the normal 8.3 name */
++ for (i = 0; i < 11; i++) {
++ if (entry->lowercase & ((i < 8) ? VFAT_LOWERCASE_NAME : VFAT_LOWERCASE_EXT))
++ filename[i] = tolower(entry->name[i]);
++ else
++ filename[i] = entry->name[i];
++ }
++ len = 11;
++
++out:
++ filename[len] = '\0';
++ return len;
++}
++
++/* fills filename, returns string length */
++static size_t get_fat_attr_volume_id(uint8_t *filename, size_t fnsize,
++ struct vfat_dir_entry *direntry, unsigned int count)
++{
++ unsigned int i;
++
++ for (i = 0; i < count; i++) {
++ /* end marker */
++ if (direntry[i].name[0] == 0x00) {
++ dbg("end of dir");
++ break;
++ }
++
++ /* empty entry */
++ if (direntry[i].name[0] == FAT_ENTRY_FREE)
++ continue;
++
++ /* long name */
++ if ((direntry[i].attr & FAT_ATTR_MASK) == FAT_ATTR_LONG_NAME)
++ continue;
++
++ if ((direntry[i].attr & (FAT_ATTR_VOLUME_ID | FAT_ATTR_DIR)) == FAT_ATTR_VOLUME_ID) {
++ /* labels do not have file data */
++ if (direntry[i].cluster_high != 0 || direntry[i].cluster_low != 0)
++ continue;
++
++ dbg("found ATTR_VOLUME_ID id in root dir");
++ return fat_read_filename(filename, fnsize, direntry, &direntry[i]);
++ }
++
++ dbg("skip dir entry");
++ }
++
++ return 0;
++}
++
++int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint8_t filename[255 * 3];
++ struct vfat_super_block *vs;
++ struct vfat_dir_entry *direntry;
++ struct fat32_fsinfo *fsinfo;
++ uint16_t sector_size;
++ uint16_t dir_entries;
++ uint32_t sect_count;
++ uint16_t reserved;
++ uint32_t fat_size;
++ uint32_t root_cluster;
++ uint32_t dir_size;
++ uint32_t cluster_count;
++ uint16_t fat_length;
++ uint32_t fat32_length;
++ uint64_t root_start;
++ uint32_t start_data_sect;
++ uint16_t root_dir_entries;
++ uint16_t fsinfo_sect;
++ uint8_t *buf;
++ uint32_t buf_size;
++ uint32_t next;
++ int maxloop;
++ size_t fnlen;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off, 0x400);
++ if (buf == NULL)
++ return -1;
++
++ /* check signature */
++ if (buf[510] != 0x55 || buf[511] != 0xaa)
++ return -1;
++
++ vs = (struct vfat_super_block *) buf;
++ if (memcmp((char*)vs->sysid, "NTFS", 4) == 0)
++ return -1;
++
++ /* believe only that's fat, don't trust the version */
++ if (memcmp((char*)vs->type.fat32.magic, "MSWIN", 5) == 0)
++ goto magic;
++
++ if (memcmp((char*)vs->type.fat32.magic, "FAT32 ", 8) == 0)
++ goto magic;
++
++ if (memcmp((char*)vs->type.fat.magic, "FAT16 ", 8) == 0)
++ goto magic;
++
++ if (memcmp((char*)vs->type.fat.magic, "MSDOS", 5) == 0)
++ goto magic;
++
++ if (memcmp((char*)vs->type.fat.magic, "FAT12 ", 8) == 0)
++ goto magic;
++
++ /* some old floppies don't have a magic, expect the boot jump address to match */
++ if ((vs->boot_jump[0] != 0xeb || vs->boot_jump[2] != 0x90) &&
++ vs->boot_jump[0] != 0xe9)
++ return -1;
++
++magic:
++ /* reserverd sector count */
++ if (!vs->reserved)
++ return -1;
++
++ /* fat count */
++ if (!vs->fats)
++ return -1;
++
++ /* media check */
++ if (vs->media < 0xf8 && vs->media != 0xf0)
++ return -1;
++
++ /* cluster size check */
++ if (vs->sectors_per_cluster == 0 ||
++ (vs->sectors_per_cluster & (vs->sectors_per_cluster-1)))
++ return -1;
++
++ /* sector size check */
++ sector_size = le16_to_cpu(vs->sector_size);
++ if (sector_size == 0 || ((sector_size & (sector_size-1)) != 0))
++ return -1;
++
++ dbg("sector_size 0x%x", sector_size);
++ dbg("sectors_per_cluster 0x%x", vs->sectors_per_cluster);
++
++ dir_entries = le16_to_cpu(vs->dir_entries);
++ reserved = le16_to_cpu(vs->reserved);
++ dbg("reserved 0x%x", reserved);
++
++ sect_count = le16_to_cpu(vs->sectors);
++ if (sect_count == 0)
++ sect_count = le32_to_cpu(vs->total_sect);
++ dbg("sect_count 0x%x", sect_count);
++
++ fat_length = le16_to_cpu(vs->fat_length);
++ dbg("fat_length 0x%x", fat_length);
++ fat32_length = le32_to_cpu(vs->type.fat32.fat32_length);
++ dbg("fat32_length 0x%x", fat32_length);
++
++ if (fat_length)
++ fat_size = fat_length * vs->fats;
++ else if (fat32_length)
++ fat_size = fat32_length * vs->fats;
++ else
++ return -1;
++ dbg("fat_size 0x%x", fat_size);
++
++ dir_size = ((dir_entries * sizeof(struct vfat_dir_entry)) +
++ (sector_size-1)) / sector_size;
++ dbg("dir_size 0x%x", dir_size);
++
++ cluster_count = sect_count - (reserved + fat_size + dir_size);
++ cluster_count /= vs->sectors_per_cluster;
++ dbg("cluster_count 0x%x", cluster_count);
++
++ /* must be FAT32 */
++ if (!fat_length && fat32_length)
++ goto fat32;
++
++ /* cluster_count tells us the format */
++ if (cluster_count < FAT12_MAX)
++ strcpy(id->type_version, "FAT12");
++ else if (cluster_count < FAT16_MAX)
++ strcpy(id->type_version, "FAT16");
++ else
++ goto fat32;
++
++ /* the label may be an attribute in the root directory */
++ root_start = (reserved + fat_size) * sector_size;
++ dbg("root dir start 0x%llx", (unsigned long long) root_start);
++ root_dir_entries = le16_to_cpu(vs->dir_entries);
++ dbg("expected entries 0x%x", root_dir_entries);
++
++ buf_size = root_dir_entries * sizeof(struct vfat_dir_entry);
++ buf = volume_id_get_buffer(id, off + root_start, buf_size);
++ if (buf == NULL)
++ goto found;
++
++ direntry = (struct vfat_dir_entry*) buf;
++
++ fnlen = get_fat_attr_volume_id(filename, sizeof(filename), direntry, root_dir_entries);
++
++ vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
++ if (vs == NULL)
++ return -1;
++
++ if (fnlen > 0 && memcmp((char*)filename, "NO NAME ", 11) != 0) {
++ volume_id_set_label_raw(id, filename, fnlen);
++ volume_id_set_label_string(id, filename, fnlen);
++ } else if (memcmp((char*)vs->type.fat.label, "NO NAME ", 11) != 0) {
++ volume_id_set_label_raw(id, vs->type.fat.label, 11);
++ volume_id_set_label_string(id, vs->type.fat.label, 11);
++ }
++ volume_id_set_uuid(id, vs->type.fat.serno, 0, UUID_DOS);
++ goto found;
++
++fat32:
++ /* FAT32 should have a valid signature in the fsinfo block */
++ fsinfo_sect = le16_to_cpu(vs->type.fat32.fsinfo_sector);
++ buf = volume_id_get_buffer(id, off + (fsinfo_sect * sector_size), 0x200);
++ if (buf == NULL)
++ return -1;
++ fsinfo = (struct fat32_fsinfo *) buf;
++ if (memcmp((char*)fsinfo->signature1, "\x52\x52\x61\x41", 4) != 0)
++ return -1;
++ if (memcmp((char*)fsinfo->signature2, "\x72\x72\x41\x61", 4) != 0)
++ return -1 ;
++
++ vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
++ if (vs == NULL)
++ return -1;
++
++ strcpy(id->type_version, "FAT32");
++
++ /* FAT32 root dir is a cluster chain like any other directory */
++ buf_size = vs->sectors_per_cluster * sector_size;
++ root_cluster = le32_to_cpu(vs->type.fat32.root_cluster);
++ dbg("root dir cluster %u", root_cluster);
++ start_data_sect = reserved + fat_size;
++
++ next = root_cluster;
++ maxloop = 100;
++ while (--maxloop) {
++ uint32_t next_sect_off;
++ uint64_t next_off;
++ uint64_t fat_entry_off;
++ int count;
++
++ dbg("next cluster %u", next);
++ next_sect_off = (next - 2) * vs->sectors_per_cluster;
++ next_off = (start_data_sect + next_sect_off) * sector_size;
++ dbg("cluster offset 0x%llx", (unsigned long long) next_off);
++
++ /* get cluster */
++ buf = volume_id_get_buffer(id, off + next_off, buf_size);
++ if (buf == NULL)
++ goto found;
++
++ direntry = (struct vfat_dir_entry*) buf;
++ count = buf_size / sizeof(struct vfat_dir_entry);
++ dbg("expected entries 0x%x", count);
++
++ fnlen = get_fat_attr_volume_id(filename, sizeof(filename), direntry, count);
++ if (fnlen > 0)
++ break;
++
++ /* get FAT entry */
++ fat_entry_off = (reserved * sector_size) + (next * sizeof(uint32_t));
++ buf = volume_id_get_buffer(id, off + fat_entry_off, buf_size);
++ if (buf == NULL)
++ goto found;
++
++ /* set next cluster */
++ next = le32_to_cpu(*((uint32_t *) buf)) & 0x0fffffff;
++ if (next < 2 || next >= 0x0ffffff0)
++ break;
++ }
++ if (maxloop == 0)
++ dbg("reached maximum follow count of root cluster chain, give up");
++
++ vs = (struct vfat_super_block *) volume_id_get_buffer(id, off, 0x200);
++ if (vs == NULL)
++ return -1;
++
++ if (fnlen > 0 && memcmp((char*)filename, "NO NAME ", 11) != 0) {
++ volume_id_set_label_raw(id, filename, fnlen);
++ volume_id_set_label_string(id, filename, fnlen);
++ } else if (memcmp((char*)vs->type.fat32.label, "NO NAME ", 11) != 0) {
++ volume_id_set_label_raw(id, vs->type.fat32.label, 11);
++ volume_id_set_label_string(id, vs->type.fat32.label, 11);
++ }
++ volume_id_set_uuid(id, vs->type.fat32.serno, 0, UUID_DOS);
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "vfat";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/gfs.c'
+--- grub-0.97.orig/libvolume_id/gfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/gfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,115 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Red Hat, Inc. <redhat.com>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++/* Common gfs/gfs2 constants: */
++#define GFS_MAGIC 0x01161970
++#define GFS_DEFAULT_BSIZE 4096
++#define GFS_SUPERBLOCK_OFFSET (0x10 * GFS_DEFAULT_BSIZE)
++#define GFS_METATYPE_SB 1
++#define GFS_FORMAT_SB 100
++#define GFS_LOCKNAME_LEN 64
++
++/* gfs1 constants: */
++#define GFS_FORMAT_FS 1309
++#define GFS_FORMAT_MULTI 1401
++/* gfs2 constants: */
++#define GFS2_FORMAT_FS 1801
++#define GFS2_FORMAT_MULTI 1900
++
++struct gfs2_meta_header {
++ uint32_t mh_magic;
++ uint32_t mh_type;
++ uint64_t __pad0; /* Was generation number in gfs1 */
++ uint32_t mh_format;
++ uint32_t __pad1; /* Was incarnation number in gfs1 */
++};
++
++struct gfs2_inum {
++ uint64_t no_formal_ino;
++ uint64_t no_addr;
++};
++
++struct gfs2_sb {
++ struct gfs2_meta_header sb_header;
++
++ uint32_t sb_fs_format;
++ uint32_t sb_multihost_format;
++ uint32_t __pad0; /* Was superblock flags in gfs1 */
++
++ uint32_t sb_bsize;
++ uint32_t sb_bsize_shift;
++ uint32_t __pad1; /* Was journal segment size in gfs1 */
++
++ struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
++ struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
++ struct gfs2_inum sb_root_dir;
++
++ char sb_lockproto[GFS_LOCKNAME_LEN];
++ char sb_locktable[GFS_LOCKNAME_LEN];
++ /* In gfs1, quota and license dinodes followed */
++} PACKED;
++
++static int volume_id_probe_gfs_generic(struct volume_id *id, uint64_t off, int vers)
++{
++ struct gfs2_sb *sbd;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ sbd = (struct gfs2_sb *)
++ volume_id_get_buffer(id, off + GFS_SUPERBLOCK_OFFSET, sizeof(struct gfs2_sb));
++ if (sbd == NULL)
++ return -1;
++
++ if (be32_to_cpu(sbd->sb_header.mh_magic) == GFS_MAGIC &&
++ be32_to_cpu(sbd->sb_header.mh_type) == GFS_METATYPE_SB &&
++ be32_to_cpu(sbd->sb_header.mh_format) == GFS_FORMAT_SB) {
++ if (vers == 1) {
++ if (be32_to_cpu(sbd->sb_fs_format) != GFS_FORMAT_FS ||
++ be32_to_cpu(sbd->sb_multihost_format) != GFS_FORMAT_MULTI)
++ return -1; /* not gfs1 */
++ id->type = "gfs";
++ }
++ else if (vers == 2) {
++ if (be32_to_cpu(sbd->sb_fs_format) != GFS2_FORMAT_FS ||
++ be32_to_cpu(sbd->sb_multihost_format) != GFS2_FORMAT_MULTI)
++ return -1; /* not gfs2 */
++ id->type = "gfs2";
++ }
++ else
++ return -1;
++ strcpy(id->type_version, "1");
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ return 0;
++ }
++ return -1;
++}
++
++int volume_id_probe_gfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ return volume_id_probe_gfs_generic(id, off, 1);
++}
++
++int volume_id_probe_gfs2(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ return volume_id_probe_gfs_generic(id, off, 2);
++}
+
+=== added file 'libvolume_id/hfs.c'
+--- grub-0.97.orig/libvolume_id/hfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/hfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,318 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct hfs_finder_info{
++ uint32_t boot_folder;
++ uint32_t start_app;
++ uint32_t open_folder;
++ uint32_t os9_folder;
++ uint32_t reserved;
++ uint32_t osx_folder;
++ uint8_t id[8];
++} PACKED;
++
++static struct hfs_mdb {
++ uint8_t signature[2];
++ uint32_t cr_date;
++ uint32_t ls_Mod;
++ uint16_t atrb;
++ uint16_t nm_fls;
++ uint16_t vbm_st;
++ uint16_t alloc_ptr;
++ uint16_t nm_al_blks;
++ uint32_t al_blk_size;
++ uint32_t clp_size;
++ uint16_t al_bl_st;
++ uint32_t nxt_cnid;
++ uint16_t free_bks;
++ uint8_t label_len;
++ uint8_t label[27];
++ uint32_t vol_bkup;
++ uint16_t vol_seq_num;
++ uint32_t wr_cnt;
++ uint32_t xt_clump_size;
++ uint32_t ct_clump_size;
++ uint16_t num_root_dirs;
++ uint32_t file_count;
++ uint32_t dir_count;
++ struct hfs_finder_info finder_info;
++ uint8_t embed_sig[2];
++ uint16_t embed_startblock;
++ uint16_t embed_blockcount;
++} PACKED *hfs;
++
++struct hfsplus_bnode_descriptor {
++ uint32_t next;
++ uint32_t prev;
++ uint8_t type;
++ uint8_t height;
++ uint16_t num_recs;
++ uint16_t reserved;
++} PACKED;
++
++struct hfsplus_bheader_record {
++ uint16_t depth;
++ uint32_t root;
++ uint32_t leaf_count;
++ uint32_t leaf_head;
++ uint32_t leaf_tail;
++ uint16_t node_size;
++} PACKED;
++
++struct hfsplus_catalog_key {
++ uint16_t key_len;
++ uint32_t parent_id;
++ uint16_t unicode_len;
++ uint8_t unicode[255 * 2];
++} PACKED;
++
++struct hfsplus_extent {
++ uint32_t start_block;
++ uint32_t block_count;
++} PACKED;
++
++#define HFSPLUS_EXTENT_COUNT 8
++struct hfsplus_fork {
++ uint64_t total_size;
++ uint32_t clump_size;
++ uint32_t total_blocks;
++ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
++} PACKED;
++
++static struct hfsplus_vol_header {
++ uint8_t signature[2];
++ uint16_t version;
++ uint32_t attributes;
++ uint32_t last_mount_vers;
++ uint32_t reserved;
++ uint32_t create_date;
++ uint32_t modify_date;
++ uint32_t backup_date;
++ uint32_t checked_date;
++ uint32_t file_count;
++ uint32_t folder_count;
++ uint32_t blocksize;
++ uint32_t total_blocks;
++ uint32_t free_blocks;
++ uint32_t next_alloc;
++ uint32_t rsrc_clump_sz;
++ uint32_t data_clump_sz;
++ uint32_t next_cnid;
++ uint32_t write_count;
++ uint64_t encodings_bmp;
++ struct hfs_finder_info finder_info;
++ struct hfsplus_fork alloc_file;
++ struct hfsplus_fork ext_file;
++ struct hfsplus_fork cat_file;
++ struct hfsplus_fork attr_file;
++ struct hfsplus_fork start_file;
++} PACKED *hfsplus;
++
++#define HFS_SUPERBLOCK_OFFSET 0x400
++#define HFS_NODE_LEAF 0xff
++#define HFSPLUS_POR_CNID 1
++
++static void hfsid_set_uuid(struct volume_id *id, const uint8_t *hfs_id)
++{
++#if 0
++ MD5_CTX md5c;
++ static const uint8_t hash_init[16] = {
++ 0xb3, 0xe2, 0x0f, 0x39, 0xf2, 0x92, 0x11, 0xd6,
++ 0x97, 0xa4, 0x00, 0x30, 0x65, 0x43, 0xec, 0xac
++ };
++ uint8_t uuid[16];
++
++ if (*((uint64_t *)hfs_id) == 0)
++ return;
++
++ MD5_Init(&md5c);
++ MD5_Update(&md5c, &hash_init, 16);
++ MD5_Update(&md5c, hfs_id, 8);
++ MD5_Final(uuid, &md5c);
++
++ uuid[6] = 0x30 | (uuid[6] & 0x0f);
++ uuid[8] = 0x80 | (uuid[8] & 0x3f);
++ volume_id_set_uuid(id, uuid, UUID_DCE);
++#endif
++
++ volume_id_set_uuid(id, hfs_id, 0, UUID_64BIT_BE);
++}
++
++int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ unsigned int blocksize;
++ unsigned int cat_block;
++ unsigned int ext_block_start;
++ unsigned int ext_block_count;
++ int ext;
++ unsigned int leaf_node_head;
++ unsigned int leaf_node_count;
++ unsigned int leaf_node_size;
++ unsigned int leaf_block;
++ uint64_t leaf_off;
++ unsigned int alloc_block_size;
++ unsigned int alloc_first_block;
++ unsigned int embed_first_block;
++ unsigned int record_count;
++ struct hfsplus_bnode_descriptor *descr;
++ struct hfsplus_bheader_record *bnode;
++ struct hfsplus_catalog_key *key;
++ unsigned int label_len;
++ struct hfsplus_extent extents[HFSPLUS_EXTENT_COUNT];
++ const uint8_t *buf;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ hfs = (struct hfs_mdb *) buf;
++ if (memcmp((char *)hfs->signature, "BD", 2) != 0)
++ goto checkplus;
++
++ /* it may be just a hfs wrapper for hfs+ */
++ if (memcmp((char *)hfs->embed_sig, "H+", 2) == 0) {
++ alloc_block_size = be32_to_cpu(hfs->al_blk_size);
++ dbg("alloc_block_size 0x%x", alloc_block_size);
++
++ alloc_first_block = be16_to_cpu(hfs->al_bl_st);
++ dbg("alloc_first_block 0x%x", alloc_first_block);
++
++ embed_first_block = be16_to_cpu(hfs->embed_startblock);
++ dbg("embed_first_block 0x%x", embed_first_block);
++
++ off += (alloc_first_block * 512) +
++ (embed_first_block * alloc_block_size);
++ dbg("hfs wrapped hfs+ found at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off + HFS_SUPERBLOCK_OFFSET, 0x200);
++ if (buf == NULL)
++ return -1;
++ goto checkplus;
++ }
++
++ if (hfs->label_len > 0 && hfs->label_len < 28) {
++ volume_id_set_label_raw(id, hfs->label, hfs->label_len);
++ volume_id_set_label_string(id, hfs->label, hfs->label_len) ;
++ }
++
++ hfsid_set_uuid(id, hfs->finder_info.id);
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "hfs";
++
++ return 0;
++
++checkplus:
++ hfsplus = (struct hfsplus_vol_header *) buf;
++ if (memcmp((char *)hfsplus->signature, "H+", 2) == 0)
++ goto hfsplus;
++ if (memcmp((char *)hfsplus->signature, "HX", 2) == 0)
++ goto hfsplus;
++ return -1;
++
++hfsplus:
++ hfsid_set_uuid(id, hfsplus->finder_info.id);
++
++ blocksize = be32_to_cpu(hfsplus->blocksize);
++ dbg("blocksize %u", blocksize);
++
++ memcpy(extents, hfsplus->cat_file.extents, sizeof(extents));
++ cat_block = be32_to_cpu(extents[0].start_block);
++ dbg("catalog start block 0x%x", cat_block);
++
++ buf = volume_id_get_buffer(id, off + (cat_block * blocksize), 0x2000);
++ if (buf == NULL)
++ goto found;
++
++ bnode = (struct hfsplus_bheader_record *)
++ &buf[sizeof(struct hfsplus_bnode_descriptor)];
++
++ leaf_node_head = be32_to_cpu(bnode->leaf_head);
++ dbg("catalog leaf node 0x%x", leaf_node_head);
++
++ leaf_node_size = be16_to_cpu(bnode->node_size);
++ dbg("leaf node size 0x%x", leaf_node_size);
++
++ leaf_node_count = be32_to_cpu(bnode->leaf_count);
++ dbg("leaf node count 0x%x", leaf_node_count);
++ if (leaf_node_count == 0)
++ goto found;
++
++ leaf_block = (leaf_node_head * leaf_node_size) / blocksize;
++
++ /* get physical location */
++ for (ext = 0; ext < HFSPLUS_EXTENT_COUNT; ext++) {
++ ext_block_start = be32_to_cpu(extents[ext].start_block);
++ ext_block_count = be32_to_cpu(extents[ext].block_count);
++ dbg("extent start block 0x%x, count 0x%x", ext_block_start, ext_block_count);
++
++ if (ext_block_count == 0)
++ goto found;
++
++ /* this is our extent */
++ if (leaf_block < ext_block_count)
++ break;
++
++ leaf_block -= ext_block_count;
++ }
++ if (ext == HFSPLUS_EXTENT_COUNT)
++ goto found;
++ dbg("found block in extent %i", ext);
++
++ leaf_off = (ext_block_start + leaf_block) * blocksize;
++
++ buf = volume_id_get_buffer(id, off + leaf_off, leaf_node_size);
++ if (buf == NULL)
++ goto found;
++
++ descr = (struct hfsplus_bnode_descriptor *) buf;
++ dbg("descriptor type 0x%x", descr->type);
++
++ record_count = be16_to_cpu(descr->num_recs);
++ dbg("number of records %u", record_count);
++ if (record_count == 0)
++ goto found;
++
++ if (descr->type != HFS_NODE_LEAF)
++ goto found;
++
++ key = (struct hfsplus_catalog_key *)
++ &buf[sizeof(struct hfsplus_bnode_descriptor)];
++
++ dbg("parent id 0x%x", be32_to_cpu(key->parent_id));
++ if (be32_to_cpu(key->parent_id) != HFSPLUS_POR_CNID)
++ goto found;
++
++ label_len = be16_to_cpu(key->unicode_len) * 2;
++ dbg("label unicode16 len %i", label_len);
++ volume_id_set_label_raw(id, key->unicode, label_len);
++ volume_id_set_label_unicode16(id, key->unicode, BE, label_len);
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "hfsplus";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/highpoint.c'
+--- grub-0.97.orig/libvolume_id/highpoint.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/highpoint.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,91 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct hpt37x_meta {
++ uint8_t filler1[32];
++ uint32_t magic;
++} PACKED;
++
++struct hpt45x_meta {
++ uint32_t magic;
++} PACKED;
++
++#define HPT37X_CONFIG_OFF 0x1200
++#define HPT37X_MAGIC_OK 0x5a7816f0
++#define HPT37X_MAGIC_BAD 0x5a7816fd
++
++#define HPT45X_MAGIC_OK 0x5a7816f3
++#define HPT45X_MAGIC_BAD 0x5a7816fd
++
++
++int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ struct hpt37x_meta *hpt;
++ uint32_t magic;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off + HPT37X_CONFIG_OFF, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ hpt = (struct hpt37x_meta *) buf;
++ magic = le32_to_cpu(hpt->magic);
++ if (magic != HPT37X_MAGIC_OK && magic != HPT37X_MAGIC_BAD)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "highpoint_raid_member";
++
++ return 0;
++}
++
++int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ struct hpt45x_meta *hpt;
++ uint64_t meta_off;
++ uint32_t magic;
++
++ dbg("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x10000)
++ return -1;
++
++ meta_off = ((size / 0x200)-11) * 0x200;
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ hpt = (struct hpt45x_meta *) buf;
++ magic = le32_to_cpu(hpt->magic);
++ if (magic != HPT45X_MAGIC_OK && magic != HPT45X_MAGIC_BAD)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "highpoint_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/hpfs.c'
+--- grub-0.97.orig/libvolume_id/hpfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/hpfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,51 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct hpfs_super
++{
++ uint8_t magic[4];
++ uint8_t version;
++} PACKED;
++
++#define HPFS_SUPERBLOCK_OFFSET 0x2000
++
++int volume_id_probe_hpfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct hpfs_super *hs;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ hs = (struct hpfs_super *) volume_id_get_buffer(id, off + HPFS_SUPERBLOCK_OFFSET, 0x200);
++ if (hs == NULL)
++ return -1;
++
++ if (memcmp((char *)hs->magic, "\x49\xe8\x95\xf9", 4) == 0) {
++ sprintf(id->type_version, "%u", hs->version);
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "hpfs";
++ return 0;
++ }
++
++ return -1;
++}
+
+=== added file 'libvolume_id/iso9660.c'
+--- grub-0.97.orig/libvolume_id/iso9660.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/iso9660.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,119 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define ISO_SUPERBLOCK_OFFSET 0x8000
++#define ISO_SECTOR_SIZE 0x800
++#define ISO_VD_OFFSET (ISO_SUPERBLOCK_OFFSET + ISO_SECTOR_SIZE)
++#define ISO_VD_PRIMARY 0x1
++#define ISO_VD_SUPPLEMENTARY 0x2
++#define ISO_VD_END 0xff
++#define ISO_VD_MAX 16
++
++struct iso_volume_descriptor {
++ uint8_t type;
++ uint8_t id[5];
++ uint8_t version;
++ uint8_t flags;
++ uint8_t system_id[32];
++ uint8_t volume_id[32];
++ uint8_t unused[8];
++ uint8_t space_size[8];
++ uint8_t escape_sequences[8];
++} PACKED;
++
++struct high_sierra_volume_descriptor {
++ uint8_t foo[8];
++ uint8_t type;
++ uint8_t id[5];
++ uint8_t version;
++} PACKED;
++
++int volume_id_probe_iso9660(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint8_t *buf;
++ struct iso_volume_descriptor *is;
++ struct high_sierra_volume_descriptor *hs;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off + ISO_SUPERBLOCK_OFFSET, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ is = (struct iso_volume_descriptor *) buf;
++
++ if (memcmp((char*)is->id, "CD001", 5) == 0) {
++ int vd_offset;
++ int i;
++
++ dbg("read label from PVD");
++ volume_id_set_label_raw(id, is->volume_id, 32);
++ volume_id_set_label_string(id, is->volume_id, 32);
++
++ dbg("looking for SVDs");
++ vd_offset = ISO_VD_OFFSET;
++ for (i = 0; i < ISO_VD_MAX; i++) {
++ uint8_t svd_label[64];
++
++ is = (struct iso_volume_descriptor *) volume_id_get_buffer(id, off + vd_offset, 0x200);
++ if (is == NULL || is->type == ISO_VD_END)
++ break;
++ if (is->type != ISO_VD_SUPPLEMENTARY)
++ continue;
++
++ dbg("found SVD at offset 0x%llx", (unsigned long long) (off + vd_offset));
++ if (memcmp((char *)is->escape_sequences, "%/@", 3) == 0||
++ memcmp((char *)is->escape_sequences, "%/C", 3) == 0||
++ memcmp((char *)is->escape_sequences, "%/E", 3) == 0) {
++ dbg("Joliet extension found");
++ volume_id_set_unicode16(svd_label, sizeof(svd_label), is->volume_id, BE, 32);
++ if (memcmp((char *)id->label, (char *)svd_label, 16) == 0) {
++ dbg("SVD label is identical, use the possibly longer PVD one");
++ break;
++ }
++
++ volume_id_set_label_raw(id, is->volume_id, 32);
++ volume_id_set_label_string(id, svd_label, 32);
++ strcpy(id->type_version, "Joliet Extension");
++ goto found;
++ }
++ vd_offset += ISO_SECTOR_SIZE;
++ }
++ goto found;
++ }
++
++ hs = (struct high_sierra_volume_descriptor *) buf;
++
++ if (memcmp((char *)hs->id, "CDROM", 5) == 0) {
++ strcpy(id->type_version, "High Sierra");
++ goto found;
++ }
++
++ return -1;
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "iso9660";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/isw_raid.c'
+--- grub-0.97.orig/libvolume_id/isw_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/isw_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,61 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct isw_meta {
++ uint8_t sig[32];
++ uint32_t check_sum;
++ uint32_t mpb_size;
++ uint32_t family_num;
++ uint32_t generation_num;
++} PACKED;
++
++#define ISW_SIGNATURE "Intel Raid ISM Cfg Sig. "
++
++
++int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct isw_meta *isw;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x10000)
++ return -1;
++
++ meta_off = ((size / 0x200)-2) * 0x200;
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ isw = (struct isw_meta *) buf;
++ if (memcmp((char *)isw->sig, ISW_SIGNATURE, sizeof(ISW_SIGNATURE)-1) != 0)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ memcpy(id->type_version, &isw->sig[sizeof(ISW_SIGNATURE)-1], 6);
++ id->type = "isw_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/jfs.c'
+--- grub-0.97.orig/libvolume_id/jfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/jfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,60 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct jfs_super_block {
++ uint8_t magic[4];
++ uint32_t version;
++ uint64_t size;
++ uint32_t bsize;
++ uint32_t dummy1;
++ uint32_t pbsize;
++ uint32_t dummy2[27];
++ uint8_t uuid[16];
++ uint8_t label[16];
++ uint8_t loguuid[16];
++} PACKED;
++
++#define JFS_SUPERBLOCK_OFFSET 0x8000
++
++int volume_id_probe_jfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct jfs_super_block *js;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ js = (struct jfs_super_block *) volume_id_get_buffer(id, off + JFS_SUPERBLOCK_OFFSET, 0x200);
++ if (js == NULL)
++ return -1;
++
++ if (memcmp((char *)js->magic, "JFS1", 4) != 0)
++ return -1;
++
++ volume_id_set_label_raw(id, js->label, 16);
++ volume_id_set_label_string(id, js->label, 16);
++ volume_id_set_uuid(id, js->uuid, 0, UUID_DCE);
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "jfs";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/jmicron_raid.c'
+--- grub-0.97.orig/libvolume_id/jmicron_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/jmicron_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,57 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct jmicron_meta {
++ int8_t signature[2];
++ uint8_t minor_version;
++ uint8_t major_version;
++ uint16_t checksum;
++} PACKED;
++
++int volume_id_probe_jmicron_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct jmicron_meta *jm;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x10000)
++ return -1;
++
++ meta_off = ((size / 0x200)-1) * 0x200;
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ jm = (struct jmicron_meta *) buf;
++ if (memcmp((char *)jm->signature, "JM", 2) != 0)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u.%u", jm->major_version, jm->minor_version);
++ id->type = "jmicron_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/linux_raid.c'
+--- grub-0.97.orig/libvolume_id/linux_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/linux_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,160 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++static struct mdp0_super_block {
++ uint32_t md_magic;
++ uint32_t major_version;
++ uint32_t minor_version;
++ uint32_t patch_version;
++ uint32_t gvalid_words;
++ uint32_t set_uuid0;
++ uint32_t ctime;
++ uint32_t level;
++ uint32_t size;
++ uint32_t nr_disks;
++ uint32_t raid_disks;
++ uint32_t md_minor;
++ uint32_t not_persistent;
++ uint32_t set_uuid1;
++ uint32_t set_uuid2;
++ uint32_t set_uuid3;
++} PACKED *mdp0;
++
++struct mdp1_super_block {
++ uint32_t magic;
++ uint32_t major_version;
++ uint32_t feature_map;
++ uint32_t pad0;
++ uint8_t set_uuid[16];
++ uint8_t set_name[32];
++} PACKED *mdp1;
++
++#define MD_RESERVED_BYTES 0x10000
++#define MD_SB_MAGIC 0xa92b4efc
++
++static int volume_id_probe_linux_raid0(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ union {
++ uint32_t ints[4];
++ uint8_t bytes[16];
++ } uuid;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++ if (size < 0x10000)
++ return -1;
++
++ buf = volume_id_get_buffer(id, off, 0x800);
++ if (buf == NULL)
++ return -1;
++ mdp0 = (struct mdp0_super_block *) buf;
++
++ if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
++ uuid.ints[0] = bswap_32(mdp0->set_uuid0);
++ if (le32_to_cpu(mdp0->minor_version >= 90)) {
++ uuid.ints[1] = bswap_32(mdp0->set_uuid1);
++ uuid.ints[2] = bswap_32(mdp0->set_uuid2);
++ uuid.ints[3] = bswap_32(mdp0->set_uuid3);
++ } else {
++ uuid.ints[1] = 0;
++ uuid.ints[2] = 0;
++ uuid.ints[3] = 0;
++ }
++ volume_id_set_uuid(id, uuid.bytes, 0, UUID_FOURINT);
++ sprintf(id->type_version, "%u.%u.%u",
++ le32_to_cpu(mdp0->major_version),
++ le32_to_cpu(mdp0->minor_version),
++ le32_to_cpu(mdp0->patch_version));
++ } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) {
++ uuid.ints[0] = mdp0->set_uuid0;
++ if (be32_to_cpu(mdp0->minor_version >= 90)) {
++ uuid.ints[1] = mdp0->set_uuid1;
++ uuid.ints[2] = mdp0->set_uuid2;
++ uuid.ints[3] = mdp0->set_uuid3;
++ } else {
++ uuid.ints[1] = 0;
++ uuid.ints[2] = 0;
++ uuid.ints[3] = 0;
++ }
++ volume_id_set_uuid(id, uuid.bytes, 0, UUID_FOURINT);
++ sprintf(id->type_version, "%u.%u.%u",
++ be32_to_cpu(mdp0->major_version),
++ be32_to_cpu(mdp0->minor_version),
++ be32_to_cpu(mdp0->patch_version));
++ } else
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "linux_raid_member";
++ return 0;
++}
++
++static int volume_id_probe_linux_raid1(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ buf = volume_id_get_buffer(id, off, 0x800);
++ if (buf == NULL)
++ return -1;
++ mdp1 = (struct mdp1_super_block *) buf;
++
++ if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC)
++ return -1;
++
++ volume_id_set_uuid(id, mdp1->set_uuid, 0, UUID_FOURINT);
++ volume_id_set_label_raw(id, mdp1->set_name, 32);
++ volume_id_set_label_string(id, mdp1->set_name, 32);
++ sprintf(id->type_version, "%u", le32_to_cpu(mdp1->major_version));
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "linux_raid_member";
++ return 0;
++}
++
++int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint64_t sboff;
++
++ /* version 0 at the end of the device */
++ sboff = (size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES;
++ if (volume_id_probe_linux_raid0(id, off + sboff, size) == 0)
++ return 0;
++
++ /* version 1.0 at the end of the device */
++ sboff = (size & ~(0x1000 - 1)) - 0x2000;
++ if (volume_id_probe_linux_raid1(id, off + sboff, size) == 0)
++ return 0;
++
++ /* version 1.1 at the start of the device */
++ if (volume_id_probe_linux_raid1(id, off, size) == 0)
++ return 0;
++
++ /* version 1.2 at 4k offset from the start */
++ if (volume_id_probe_linux_raid1(id, off + 0x1000, size) == 0)
++ return 0;
++
++ return -1;
++}
+
+=== added file 'libvolume_id/linux_swap.c'
+--- grub-0.97.orig/libvolume_id/linux_swap.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/linux_swap.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,85 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct swap_header_v1_2 {
++ uint8_t bootbits[1024];
++ uint32_t version;
++ uint32_t last_page;
++ uint32_t nr_badpages;
++ uint8_t uuid[16];
++ uint8_t volume_name[16];
++} PACKED;
++
++#define LARGEST_PAGESIZE 0x4000
++
++int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ unsigned int page;
++ struct swap_header_v1_2 *sw;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ /* eek, the swap signature is at the end of the PAGE_SIZE */
++ for (page = 0x1000; page <= LARGEST_PAGESIZE; page <<= 1) {
++ buf = volume_id_get_buffer(id, off + page-10, 10);
++ if (buf == NULL)
++ return -1;
++
++ if (memcmp((char *)buf, "SWAP-SPACE", 10) == 0) {
++ strcpy(id->type_version, "1");
++ goto found;
++ }
++
++ if (memcmp((char *)buf, "SWAPSPACE2", 10) == 0) {
++ id->type = "swap";
++ strcpy(id->type_version, "2");
++ goto found_label;
++ }
++
++ if (memcmp((char *)buf, "S1SUSPEND", 9) == 0) {
++ id->type = "suspend";
++ strcpy(id->type_version, "s1suspend");
++ goto found_label;
++ }
++
++ if (memcmp((char *)buf, "ULSUSPEND", 9) == 0) {
++ id->type = "suspend";
++ strcpy(id->type_version, "ulsuspend");
++ goto found_label;
++ }
++ }
++ return -1;
++
++found_label:
++ sw = (struct swap_header_v1_2 *) volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2));
++ if (sw != NULL) {
++ volume_id_set_label_raw(id, sw->volume_name, 16);
++ volume_id_set_label_string(id, sw->volume_name, 16);
++ volume_id_set_uuid(id, sw->uuid, 0, UUID_DCE);
++ }
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_OTHER);
++ return 0;
++}
+
+=== added file 'libvolume_id/lsi_raid.c'
+--- grub-0.97.orig/libvolume_id/lsi_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/lsi_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,55 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct lsi_meta {
++ uint8_t sig[6];
++} PACKED;
++
++#define LSI_SIGNATURE "$XIDE$"
++
++int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct lsi_meta *lsi;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x10000)
++ return -1;
++
++ meta_off = ((size / 0x200)-1) * 0x200;
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ lsi = (struct lsi_meta *) buf;
++ if (memcmp((char *)lsi->sig, LSI_SIGNATURE, sizeof(LSI_SIGNATURE)-1) != 0)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "lsi_mega_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/luks.c'
+--- grub-0.97.orig/libvolume_id/luks.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/luks.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,76 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 W. Michael Petullo <mike@flyn.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define LUKS_SECTOR_SHIFT 9
++#define LUKS_SECTOR_SIZE (1 << LUKS_SECTOR_SHIFT)
++
++#define LUKS_CIPHERNAME_L 32
++#define LUKS_CIPHERMODE_L 32
++#define LUKS_HASHSPEC_L 32
++#define LUKS_DIGESTSIZE 20
++#define LUKS_SALTSIZE 32
++#define LUKS_NUMKEYS 8
++
++#define LUKS_MAGIC_L 6
++#define LUKS_PHDR_SIZE (sizeof(struct luks_phdr)/LUKS_SECTOR_SIZE+1)
++#define UUID_STRING_L 40
++static const uint8_t LUKS_MAGIC[] = {'L','U','K','S', 0xba, 0xbe};
++
++struct luks_phdr {
++ uint8_t magic[LUKS_MAGIC_L];
++ uint16_t version;
++ uint8_t cipherName[LUKS_CIPHERNAME_L];
++ uint8_t cipherMode[LUKS_CIPHERMODE_L];
++ uint8_t hashSpec[LUKS_HASHSPEC_L];
++ uint32_t payloadOffset;
++ uint32_t keyBytes;
++ uint8_t mkDigest[LUKS_DIGESTSIZE];
++ uint8_t mkDigestSalt[LUKS_SALTSIZE];
++ uint32_t mkDigestIterations;
++ uint8_t uuid[UUID_STRING_L];
++ struct {
++ uint32_t active;
++ uint32_t passwordIterations;
++ uint8_t passwordSalt[LUKS_SALTSIZE];
++ uint32_t keyMaterialOffset;
++ uint32_t stripes;
++ } keyblock[LUKS_NUMKEYS];
++};
++
++int volume_id_probe_luks(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct luks_phdr *header;
++
++ header = (struct luks_phdr*) volume_id_get_buffer(id, off, LUKS_PHDR_SIZE);
++ if (header == NULL)
++ return -1;
++
++ if (memcmp((char *)header->magic, (char *)LUKS_MAGIC, LUKS_MAGIC_L))
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_CRYPTO);
++ volume_id_set_uuid(id, header->uuid, 36, UUID_HEX_STRING);
++ sprintf(id->type_version, "%u", le16_to_cpu(header->version));
++ id->type = "crypto_LUKS";
++ return 0;
++}
+
+=== added file 'libvolume_id/lvm.c'
+--- grub-0.97.orig/libvolume_id/lvm.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/lvm.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,92 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct lvm1_super_block {
++ uint8_t id[2];
++} PACKED;
++
++struct lvm2_super_block {
++ uint8_t id[8];
++ uint64_t sector_xl;
++ uint32_t crc_xl;
++ uint32_t offset_xl;
++ uint8_t type[8];
++} PACKED;
++
++#define LVM1_SB_OFF 0x400
++#define LVM1_MAGIC "HM"
++
++int volume_id_probe_lvm1(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ struct lvm1_super_block *lvm;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off + LVM1_SB_OFF, 0x800);
++ if (buf == NULL)
++ return -1;
++
++ lvm = (struct lvm1_super_block *) buf;
++
++ if (memcmp((char *)lvm->id, LVM1_MAGIC, 2) != 0)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "LVM1_member";
++
++ return 0;
++}
++
++#define LVM2_LABEL_ID "LABELONE"
++#define LVM2LABEL_SCAN_SECTORS 4
++
++int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ unsigned int soff;
++ struct lvm2_super_block *lvm;
++
++ dbg("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off, LVM2LABEL_SCAN_SECTORS * 0x200);
++ if (buf == NULL)
++ return -1;
++
++
++ for (soff = 0; soff < LVM2LABEL_SCAN_SECTORS * 0x200; soff += 0x200) {
++ lvm = (struct lvm2_super_block *) &buf[soff];
++
++ if (memcmp((char *)lvm->id, LVM2_LABEL_ID, 8) == 0)
++ goto found;
++ }
++
++ return -1;
++
++found:
++ memcpy(id->type_version, lvm->type, 8);
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "LVM2_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/minix.c'
+--- grub-0.97.orig/libvolume_id/minix.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/minix.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,112 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define MINIX_SUPERBLOCK_OFFSET 0x400
++
++#define MINIX_SUPER_MAGIC 0x137F
++#define MINIX_SUPER_MAGIC2 0x138F
++#define MINIX2_SUPER_MAGIC 0x2468
++#define MINIX2_SUPER_MAGIC2 0x2478
++#define MINIX3_SUPER_MAGIC 0x4d5a
++
++struct minix_super_block
++{
++ uint16_t s_ninodes;
++ uint16_t s_nzones;
++ uint16_t s_imap_blocks;
++ uint16_t s_zmap_blocks;
++ uint16_t s_firstdatazone;
++ uint16_t s_log_zone_size;
++ uint32_t s_max_size;
++ uint16_t s_magic;
++ uint16_t s_state;
++ uint32_t s_zones;
++} PACKED;
++
++struct minix3_super_block {
++ uint32_t s_ninodes;
++ uint16_t s_pad0;
++ uint16_t s_imap_blocks;
++ uint16_t s_zmap_blocks;
++ uint16_t s_firstdatazone;
++ uint16_t s_log_zone_size;
++ uint16_t s_pad1;
++ uint32_t s_max_size;
++ uint32_t s_zones;
++ uint16_t s_magic;
++ uint16_t s_pad2;
++ uint16_t s_blocksize;
++ uint8_t s_disk_version;
++} PACKED;
++
++int volume_id_probe_minix(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint8_t *buf;
++ struct minix_super_block *ms;
++ struct minix3_super_block *m3s;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off + MINIX_SUPERBLOCK_OFFSET, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ ms = (struct minix_super_block *) buf;
++
++ if (ms->s_magic == MINIX_SUPER_MAGIC ||
++ ms->s_magic == bswap_16(MINIX_SUPER_MAGIC)) {
++ strcpy(id->type_version, "1");
++ goto found;
++ }
++ if (ms->s_magic == MINIX_SUPER_MAGIC2 ||
++ ms->s_magic == bswap_16(MINIX_SUPER_MAGIC2)) {
++ strcpy(id->type_version, "1");
++ goto found;
++ }
++ if (ms->s_magic == MINIX2_SUPER_MAGIC ||
++ ms->s_magic == bswap_16(MINIX2_SUPER_MAGIC)) {
++ strcpy(id->type_version, "2");
++ goto found;
++ }
++ if (ms->s_magic == MINIX2_SUPER_MAGIC2 ||
++ ms->s_magic == bswap_16(MINIX2_SUPER_MAGIC2)) {
++ strcpy(id->type_version, "2");
++ goto found;
++ }
++
++ m3s = (struct minix3_super_block *) buf;
++ if (m3s->s_magic == MINIX3_SUPER_MAGIC ||
++ m3s->s_magic == bswap_16(MINIX3_SUPER_MAGIC)) {
++ strcpy(id->type_version, "3");
++ goto found;
++ }
++ goto exit;
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "minix";
++ return 0;
++
++exit:
++ return -1;
++}
+
+=== added file 'libvolume_id/misc.c'
+--- grub-0.97.orig/libvolume_id/misc.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/misc.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,34 @@
++/*
++ * volume_id/misc.c
++ *
++ * Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++#define _GNU_SOURCE
++#include <string.h>
++
++/*
++ * Misc auxiliary functions required for volume_id inside grub
++ */
++size_t strnlen(const char *s, size_t limit)
++{
++ size_t length = 0;
++ while ( (length < limit) && (*s++) )
++ length++;
++
++ return length;
++}
++
++char *strchr (const char *s, int c)
++{
++ do {
++ if ( *s == c ) {
++ return (char*)s;
++ }
++ } while ( *s++ );
++
++ return 0;
++}
+
+=== added file 'libvolume_id/netware.c'
+--- grub-0.97.orig/libvolume_id/netware.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/netware.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,98 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define NW_SUPERBLOCK_OFFSET 0x1000
++
++struct netware_super_block {
++ uint8_t SBH_Signature[4];
++ uint16_t SBH_VersionMajor;
++ uint16_t SBH_VersionMinor;
++ uint16_t SBH_VersionMediaMajor;
++ uint16_t SBH_VersionMediaMinor;
++ uint32_t SBH_ItemsMoved;
++ uint8_t SBH_InternalID[16];
++ uint32_t SBH_PackedSize;
++ uint32_t SBH_Checksum;
++ uint32_t supersyncid;
++ int64_t superlocation[4];
++ uint32_t physSizeUsed;
++ uint32_t sizeUsed;
++ uint32_t superTimeStamp;
++ uint32_t reserved0[1];
++ int64_t SBH_LoggedPoolDataBlk;
++ int64_t SBH_PoolDataBlk;
++ uint8_t SBH_OldInternalID[16];
++ uint32_t SBH_PoolToLVStartUTC;
++ uint32_t SBH_PoolToLVEndUTC;
++ uint16_t SBH_VersionMediaMajorCreate;
++ uint16_t SBH_VersionMediaMinorCreate;
++ uint32_t SBH_BlocksMoved;
++ uint32_t SBH_TempBTSpBlk;
++ uint32_t SBH_TempFTSpBlk;
++ uint32_t SBH_TempFTSpBlk1;
++ uint32_t SBH_TempFTSpBlk2;
++ uint32_t nssMagicNumber;
++ uint32_t poolClassID;
++ uint32_t poolID;
++ uint32_t createTime;
++ int64_t SBH_LoggedVolumeDataBlk;
++ int64_t SBH_VolumeDataBlk;
++ int64_t SBH_SystemBeastBlkNum;
++ uint64_t totalblocks;
++ uint16_t SBH_Name[64];
++ uint8_t SBH_VolumeID[16];
++ uint8_t SBH_PoolID[16];
++ uint8_t SBH_PoolInternalID[16];
++ uint64_t SBH_Lsn;
++ uint32_t SBH_SS_Enabled;
++ uint32_t SBH_SS_CreateTime;
++ uint8_t SBH_SS_OriginalPoolID[16];
++ uint8_t SBH_SS_OriginalVolumeID[16];
++ uint8_t SBH_SS_Guid[16];
++ uint16_t SBH_SS_OriginalName[64];
++ uint32_t reserved2[64-(2+46)];
++} PACKED;
++
++int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct netware_super_block *nw;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ nw = (struct netware_super_block *) volume_id_get_buffer(id, off + NW_SUPERBLOCK_OFFSET, 0x200);
++ if (nw == NULL)
++ return -1;
++
++ if (memcmp((char *)nw->SBH_Signature, "SPB5", 4) != 0)
++ return -1;
++
++ volume_id_set_uuid(id, nw->SBH_PoolID, 0, UUID_DCE);
++
++ sprintf(id->type_version, "%u.%02u",
++ le16_to_cpu(nw->SBH_VersionMediaMajor), le16_to_cpu(nw->SBH_VersionMediaMinor));
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "nss";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/ntfs.c'
+--- grub-0.97.orig/libvolume_id/ntfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ntfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,192 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++static struct ntfs_super_block {
++ uint8_t jump[3];
++ uint8_t oem_id[8];
++ uint16_t bytes_per_sector;
++ uint8_t sectors_per_cluster;
++ uint16_t reserved_sectors;
++ uint8_t fats;
++ uint16_t root_entries;
++ uint16_t sectors;
++ uint8_t media_type;
++ uint16_t sectors_per_fat;
++ uint16_t sectors_per_track;
++ uint16_t heads;
++ uint32_t hidden_sectors;
++ uint32_t large_sectors;
++ uint16_t unused[2];
++ uint64_t number_of_sectors;
++ uint64_t mft_cluster_location;
++ uint64_t mft_mirror_cluster_location;
++ int8_t cluster_per_mft_record;
++ uint8_t reserved1[3];
++ int8_t cluster_per_index_record;
++ uint8_t reserved2[3];
++ uint8_t volume_serial[8];
++ uint16_t checksum;
++} PACKED *ns;
++
++static struct master_file_table_record {
++ uint8_t magic[4];
++ uint16_t usa_ofs;
++ uint16_t usa_count;
++ uint64_t lsn;
++ uint16_t sequence_number;
++ uint16_t link_count;
++ uint16_t attrs_offset;
++ uint16_t flags;
++ uint32_t bytes_in_use;
++ uint32_t bytes_allocated;
++} PACKED *mftr;
++
++static struct file_attribute {
++ uint32_t type;
++ uint32_t len;
++ uint8_t non_resident;
++ uint8_t name_len;
++ uint16_t name_offset;
++ uint16_t flags;
++ uint16_t instance;
++ uint32_t value_len;
++ uint16_t value_offset;
++} PACKED *attr;
++
++static struct volume_info {
++ uint64_t reserved;
++ uint8_t major_ver;
++ uint8_t minor_ver;
++} PACKED *info;
++
++#define MFT_RECORD_VOLUME 3
++#define MFT_RECORD_ATTR_VOLUME_NAME 0x60
++#define MFT_RECORD_ATTR_VOLUME_INFO 0x70
++#define MFT_RECORD_ATTR_OBJECT_ID 0x40
++#define MFT_RECORD_ATTR_END 0xffffffffu
++
++#undef debug
++#define debug grub_printf
++
++int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ unsigned int sector_size;
++ unsigned int cluster_size;
++ uint64_t mft_cluster;
++ uint64_t mft_off;
++ unsigned int mft_record_size;
++ unsigned int attr_type;
++ unsigned int attr_off;
++ unsigned int attr_len;
++ unsigned int val_off;
++ unsigned int val_len;
++ const uint8_t *buf;
++ const uint8_t *val;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ ns = (struct ntfs_super_block *) volume_id_get_buffer(id, off, 0x200);
++ if (ns == NULL)
++ return -1;
++
++ if (memcmp((char *)ns->oem_id, "NTFS", 4) != 0)
++ return -1;
++
++ volume_id_set_uuid(id, ns->volume_serial, 0, UUID_64BIT_LE);
++
++ sector_size = le16_to_cpu(ns->bytes_per_sector);
++ if (sector_size < 0x200)
++ return -1;
++
++ cluster_size = ns->sectors_per_cluster * sector_size;
++ mft_cluster = le64_to_cpu(ns->mft_cluster_location);
++ mft_off = mft_cluster * cluster_size;
++
++ if (ns->cluster_per_mft_record < 0)
++ /* size = -log2(mft_record_size); normally 1024 Bytes */
++ mft_record_size = 1 << -ns->cluster_per_mft_record;
++ else
++ mft_record_size = ns->cluster_per_mft_record * cluster_size;
++
++ dbg("sectorsize 0x%x", sector_size);
++ dbg("clustersize 0x%x", cluster_size);
++ dbg("mftcluster %llu", (unsigned long long) mft_cluster);
++ dbg("mftoffset 0x%llx", (unsigned long long) mft_off);
++ dbg("cluster per mft_record %i", ns->cluster_per_mft_record);
++ dbg("mft record size %i", mft_record_size);
++
++ buf = volume_id_get_buffer(id, off + mft_off + (MFT_RECORD_VOLUME * mft_record_size),
++ mft_record_size);
++ if (buf == NULL)
++ return -1;
++
++ mftr = (struct master_file_table_record*) buf;
++ dbg("mftr->magic '%c%c%c%c'", mftr->magic[0], mftr->magic[1], mftr->magic[2], mftr->magic[3]);
++ if (memcmp((char *)mftr->magic, "FILE", 4) != 0)
++ return -1;
++
++ attr_off = le16_to_cpu(mftr->attrs_offset);
++ dbg("file $Volume's attributes are at offset %i", attr_off);
++
++ while (1) {
++ attr = (struct file_attribute*) &buf[attr_off];
++ attr_type = le32_to_cpu(attr->type);
++ attr_len = le16_to_cpu(attr->len);
++ val_off = le16_to_cpu(attr->value_offset);
++ val_len = le32_to_cpu(attr->value_len);
++ attr_off += attr_len;
++
++ if (attr_len == 0)
++ break;
++
++ if (attr_off >= mft_record_size)
++ break;
++
++ if (attr_type == MFT_RECORD_ATTR_END)
++ break;
++
++ dbg("found attribute type 0x%x, len %i, at offset %i",
++ attr_type, attr_len, attr_off);
++
++ if (attr_type == MFT_RECORD_ATTR_VOLUME_INFO) {
++ dbg("found info, len %i", val_len);
++ info = (struct volume_info*) (((uint8_t *) attr) + val_off);
++ sprintf(id->type_version, "%u.%u", info->major_ver, info->minor_ver);
++ }
++
++ if (attr_type == MFT_RECORD_ATTR_VOLUME_NAME) {
++ dbg("found label, len %i", val_len);
++ if (val_len > VOLUME_ID_LABEL_SIZE)
++ val_len = VOLUME_ID_LABEL_SIZE;
++
++ val = ((uint8_t *) attr) + val_off;
++ volume_id_set_label_raw(id, val, val_len);
++ volume_id_set_label_unicode16(id, val, LE, val_len);
++ }
++ }
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "ntfs";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/nvidia_raid.c'
+--- grub-0.97.orig/libvolume_id/nvidia_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/nvidia_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,59 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct nvidia_meta {
++ uint8_t vendor[8];
++ uint32_t size;
++ uint32_t chksum;
++ uint16_t version;
++} PACKED;
++
++#define NVIDIA_SIGNATURE "NVIDIA"
++
++int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct nvidia_meta *nv;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x10000)
++ return -1;
++
++ meta_off = ((size / 0x200)-2) * 0x200;
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ nv = (struct nvidia_meta *) buf;
++ if (memcmp((char *)nv->vendor, NVIDIA_SIGNATURE, sizeof(NVIDIA_SIGNATURE)-1) != 0)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u", le16_to_cpu(nv->version));
++ id->type = "nvidia_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/ocfs.c'
+--- grub-0.97.orig/libvolume_id/ocfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ocfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,186 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Andre Masella <andre@masella.no-ip.org>
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct ocfs1_super_block_header {
++ uint32_t minor_version;
++ uint32_t major_version;
++ uint8_t signature[128];
++ uint8_t mount_point[128];
++ uint64_t serial_num;
++ uint64_t device_size;
++ uint64_t start_off;
++ uint64_t bitmap_off;
++ uint64_t publ_off;
++ uint64_t vote_off;
++ uint64_t root_bitmap_off;
++ uint64_t data_start_off;
++ uint64_t root_bitmap_size;
++ uint64_t root_off;
++ uint64_t root_size;
++ uint64_t cluster_size;
++ uint64_t num_nodes;
++ uint64_t num_clusters;
++ uint64_t dir_node_size;
++ uint64_t file_node_size;
++ uint64_t internal_off;
++ uint64_t node_cfg_off;
++ uint64_t node_cfg_size;
++ uint64_t new_cfg_off;
++ uint32_t prot_bits;
++ int32_t excl_mount;
++} PACKED;
++
++struct ocfs1_super_block_label {
++ struct ocfs1_disk_lock {
++ uint32_t curr_master;
++ uint8_t file_lock;
++ uint8_t compat_pad[3];
++ uint64_t last_write_time;
++ uint64_t last_read_time;
++ uint32_t writer_node_num;
++ uint32_t reader_node_num;
++ uint64_t oin_node_map;
++ uint64_t dlock_seq_num;
++ } PACKED disk_lock;
++ uint8_t label[64];
++ uint16_t label_len;
++ uint8_t vol_id[16];
++ uint16_t vol_id_len;
++ uint8_t cluster_name[64];
++ uint16_t cluster_name_len;
++} PACKED;
++
++struct ocfs2_super_block {
++ uint8_t i_signature[8];
++ uint32_t i_generation;
++ int16_t i_suballoc_slot;
++ uint16_t i_suballoc_bit;
++ uint32_t i_reserved0;
++ uint32_t i_clusters;
++ uint32_t i_uid;
++ uint32_t i_gid;
++ uint64_t i_size;
++ uint16_t i_mode;
++ uint16_t i_links_count;
++ uint32_t i_flags;
++ uint64_t i_atime;
++ uint64_t i_ctime;
++ uint64_t i_mtime;
++ uint64_t i_dtime;
++ uint64_t i_blkno;
++ uint64_t i_last_eb_blk;
++ uint32_t i_fs_generation;
++ uint32_t i_atime_nsec;
++ uint32_t i_ctime_nsec;
++ uint32_t i_mtime_nsec;
++ uint64_t i_reserved1[9];
++ uint64_t i_pad1;
++ uint16_t s_major_rev_level;
++ uint16_t s_minor_rev_level;
++ uint16_t s_mnt_count;
++ int16_t s_max_mnt_count;
++ uint16_t s_state;
++ uint16_t s_errors;
++ uint32_t s_checkinterval;
++ uint64_t s_lastcheck;
++ uint32_t s_creator_os;
++ uint32_t s_feature_compat;
++ uint32_t s_feature_incompat;
++ uint32_t s_feature_ro_compat;
++ uint64_t s_root_blkno;
++ uint64_t s_system_dir_blkno;
++ uint32_t s_blocksize_bits;
++ uint32_t s_clustersize_bits;
++ uint16_t s_max_slots;
++ uint16_t s_reserved1;
++ uint32_t s_reserved2;
++ uint64_t s_first_cluster_group;
++ uint8_t s_label[64];
++ uint8_t s_uuid[16];
++} PACKED;
++
++int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ struct ocfs1_super_block_header *osh;
++ struct ocfs1_super_block_label *osl;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ osh = (struct ocfs1_super_block_header *) buf;
++ if (memcmp((char *)osh->signature, "OracleCFS", 9) != 0)
++ return -1;
++ sprintf(id->type_version, "%u.%u", osh->major_version, osh->minor_version);
++
++ dbg("found OracleCFS signature, now reading label");
++ buf = volume_id_get_buffer(id, off + 0x200, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ osl = (struct ocfs1_super_block_label *) buf;
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ if (osl->label_len <= 64) {
++ volume_id_set_label_raw(id, osl->label, 64);
++ volume_id_set_label_string(id, osl->label, 64);
++ }
++ if (osl->vol_id_len == 16)
++ volume_id_set_uuid(id, osl->vol_id, 0, UUID_DCE);
++ id->type = "ocfs";
++ return 0;
++}
++
++#define OCFS2_MAX_BLOCKSIZE 0x1000
++#define OCFS2_SUPER_BLOCK_BLKNO 2
++
++int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ struct ocfs2_super_block *os;
++ size_t blksize;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ for (blksize = 0x200; blksize <= OCFS2_MAX_BLOCKSIZE; blksize <<= 1) {
++ buf = volume_id_get_buffer(id, off + OCFS2_SUPER_BLOCK_BLKNO * blksize, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ os = (struct ocfs2_super_block *) buf;
++ if (memcmp((char *)os->i_signature, "OCFSV2", 6) != 0)
++ continue;
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ volume_id_set_label_raw(id, os->s_label, 64);
++ volume_id_set_label_string(id, os->s_label, 64);
++ volume_id_set_uuid(id, os->s_uuid, 0, UUID_DCE);
++ sprintf(id->type_version, "%u.%u", os->s_major_rev_level, os->s_minor_rev_level);
++ id->type = "ocfs2";
++ return 0;
++ }
++ return -1;
++}
+
+=== added file 'libvolume_id/promise_raid.c'
+--- grub-0.97.orig/libvolume_id/promise_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/promise_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,65 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct promise_meta {
++ uint8_t sig[24];
++} PACKED;
++
++#define PDC_CONFIG_OFF 0x1200
++#define PDC_SIGNATURE "Promise Technology, Inc."
++
++int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ struct promise_meta *pdc;
++ unsigned int i;
++ static unsigned int sectors[] = {
++ 63, 255, 256, 16, 399, 0
++ };
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x40000)
++ return -1;
++
++ for (i = 0; sectors[i] != 0; i++) {
++ uint64_t meta_off;
++
++ meta_off = ((size / 0x200) - sectors[i]) * 0x200;
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ pdc = (struct promise_meta *) buf;
++ if (memcmp((char *)pdc->sig, PDC_SIGNATURE, sizeof(PDC_SIGNATURE)-1) == 0)
++ goto found;
++ }
++ return -1;
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ id->type = "promise_fasttrack_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/reiserfs.c'
+--- grub-0.97.orig/libvolume_id/reiserfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/reiserfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,113 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Copyright (C) 2005 Tobias Klauser <tklauser@access.unizh.ch>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct reiserfs_super_block {
++ uint32_t blocks_count;
++ uint32_t free_blocks;
++ uint32_t root_block;
++ uint32_t journal_block;
++ uint32_t journal_dev;
++ uint32_t orig_journal_size;
++ uint32_t dummy2[5];
++ uint16_t blocksize;
++ uint16_t dummy3[3];
++ uint8_t magic[12];
++ uint32_t dummy4[5];
++ uint8_t uuid[16];
++ uint8_t label[16];
++} PACKED;
++
++struct reiser4_super_block {
++ uint8_t magic[16];
++ uint16_t dummy[2];
++ uint8_t uuid[16];
++ uint8_t label[16];
++ uint64_t dummy2;
++} PACKED;
++
++#define REISERFS1_SUPERBLOCK_OFFSET 0x2000
++#define REISERFS_SUPERBLOCK_OFFSET 0x10000
++
++int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct reiserfs_super_block *rs;
++ struct reiser4_super_block *rs4;
++ uint8_t *buf;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ buf = volume_id_get_buffer(id, off + REISERFS_SUPERBLOCK_OFFSET, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ rs = (struct reiserfs_super_block *) buf;
++ if (memcmp((char *)rs->magic, "ReIsErFs", 8) == 0) {
++ strcpy(id->type_version, "3.5");
++ id->type = "reiserfs";
++ goto found;
++ }
++ if (memcmp((char *)rs->magic, "ReIsEr2Fs", 9) == 0) {
++ strcpy(id->type_version, "3.6");
++ id->type = "reiserfs";
++ goto found_label;
++ }
++ if (memcmp((char *)rs->magic, "ReIsEr3Fs", 9) == 0) {
++ strcpy(id->type_version, "JR");
++ id->type = "reiserfs";
++ goto found_label;
++ }
++
++ rs4 = (struct reiser4_super_block *) buf;
++ if (memcmp((char *)rs4->magic, "ReIsEr4", 7) == 0) {
++ strcpy(id->type_version, "4");
++ volume_id_set_label_raw(id, rs4->label, 16);
++ volume_id_set_label_string(id, rs4->label, 16);
++ volume_id_set_uuid(id, rs4->uuid, 0, UUID_DCE);
++ id->type = "reiser4";
++ goto found;
++ }
++
++ buf = volume_id_get_buffer(id, off + REISERFS1_SUPERBLOCK_OFFSET, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ rs = (struct reiserfs_super_block *) buf;
++ if (memcmp((char *)rs->magic, "ReIsErFs", 8) == 0) {
++ strcpy(id->type_version, "3.5");
++ id->type = "reiserfs";
++ goto found;
++ }
++
++ return -1;
++
++found_label:
++ volume_id_set_label_raw(id, rs->label, 16);
++ volume_id_set_label_string(id, rs->label, 16);
++ volume_id_set_uuid(id, rs->uuid, 0, UUID_DCE);
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++
++ return 0;
++}
+
+=== added file 'libvolume_id/romfs.c'
+--- grub-0.97.orig/libvolume_id/romfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/romfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,55 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct romfs_super {
++ uint8_t magic[8];
++ uint32_t size;
++ uint32_t checksum;
++ uint8_t name[0];
++} PACKED;
++
++int volume_id_probe_romfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct romfs_super *rfs;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ rfs = (struct romfs_super *) volume_id_get_buffer(id, off, 0x200);
++ if (rfs == NULL)
++ return -1;
++
++ if (memcmp((char *)rfs->magic, "-rom1fs-", 4) == 0) {
++ size_t len = strlen((char *)rfs->name);
++
++ if (len) {
++ volume_id_set_label_raw(id, rfs->name, len);
++ volume_id_set_label_string(id, rfs->name, len);
++ }
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "romfs";
++ return 0;
++ }
++
++ return -1;
++}
+
+=== added file 'libvolume_id/silicon_raid.c'
+--- grub-0.97.orig/libvolume_id/silicon_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/silicon_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,71 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct silicon_meta {
++ uint8_t unknown0[0x2E];
++ uint8_t ascii_version[0x36 - 0x2E];
++ uint8_t diskname[0x56 - 0x36];
++ uint8_t unknown1[0x60 - 0x56];
++ uint32_t magic;
++ uint32_t unknown1a[0x6C - 0x64];
++ uint32_t array_sectors_low;
++ uint32_t array_sectors_high;
++ uint8_t unknown2[0x78 - 0x74];
++ uint32_t thisdisk_sectors;
++ uint8_t unknown3[0x100 - 0x7C];
++ uint8_t unknown4[0x104 - 0x100];
++ uint16_t product_id;
++ uint16_t vendor_id;
++ uint16_t minor_ver;
++ uint16_t major_ver;
++} PACKED;
++
++#define SILICON_MAGIC 0x2F000000
++
++int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct silicon_meta *sil;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x10000)
++ return -1;
++
++ meta_off = ((size / 0x200)-1) * 0x200;
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ sil = (struct silicon_meta *) buf;
++ if (le32_to_cpu(sil->magic) != SILICON_MAGIC)
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u.%u", le16_to_cpu(sil->major_ver), le16_to_cpu(sil->minor_ver));
++ id->type = "silicon_medley_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/squashfs.c'
+--- grub-0.97.orig/libvolume_id/squashfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/squashfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,63 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2006 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define SQUASHFS_MAGIC 0x73717368
++
++struct squashfs_super {
++ uint32_t s_magic;
++ uint32_t inodes;
++ uint32_t bytes_used_2;
++ uint32_t uid_start_2;
++ uint32_t guid_start_2;
++ uint32_t inode_table_start_2;
++ uint32_t directory_table_start_2;
++ uint16_t s_major;
++ uint16_t s_minor;
++} PACKED;
++
++int volume_id_probe_squashfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct squashfs_super *sqs;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ sqs = (struct squashfs_super *) volume_id_get_buffer(id, off, 0x200);
++ if (sqs == NULL)
++ return -1;
++
++ if (sqs->s_magic == SQUASHFS_MAGIC) {
++ sprintf(id->type_version, "%u.%u", sqs->s_major, sqs->s_minor);
++ goto found;
++ }
++ if (sqs->s_magic == bswap_32(SQUASHFS_MAGIC)) {
++ sprintf(id->type_version, "%u.%u", bswap_16(sqs->s_major), bswap_16(sqs->s_minor));
++ goto found;
++ }
++
++ return -1;
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "squashfs";
++ return 0;
++}
+
+=== added file 'libvolume_id/strfuncs.h'
+--- grub-0.97.orig/libvolume_id/strfuncs.h 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/strfuncs.h 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,5 @@
++
++#include <stdlib.h>
++
++size_t strnlen(const char *s, size_t limit);
++char *strchr (const char *s, int c);
+
+=== added file 'libvolume_id/sysv.c'
+--- grub-0.97.orig/libvolume_id/sysv.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/sysv.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,128 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define SYSV_NICINOD 100
++#define SYSV_NICFREE 50
++
++struct sysv_super
++{
++ uint16_t s_isize;
++ uint16_t s_pad0;
++ uint32_t s_fsize;
++ uint16_t s_nfree;
++ uint16_t s_pad1;
++ uint32_t s_free[SYSV_NICFREE];
++ uint16_t s_ninode;
++ uint16_t s_pad2;
++ uint16_t s_inode[SYSV_NICINOD];
++ uint8_t s_flock;
++ uint8_t s_ilock;
++ uint8_t s_fmod;
++ uint8_t s_ronly;
++ uint32_t s_time;
++ uint16_t s_dinfo[4];
++ uint32_t s_tfree;
++ uint16_t s_tinode;
++ uint16_t s_pad3;
++ uint8_t s_fname[6];
++ uint8_t s_fpack[6];
++ uint32_t s_fill[12];
++ uint32_t s_state;
++ uint32_t s_magic;
++ uint32_t s_type;
++} PACKED;
++
++#define XENIX_NICINOD 100
++#define XENIX_NICFREE 100
++
++struct xenix_super {
++ uint16_t s_isize;
++ uint32_t s_fsize;
++ uint16_t s_nfree;
++ uint32_t s_free[XENIX_NICFREE];
++ uint16_t s_ninode;
++ uint16_t s_inode[XENIX_NICINOD];
++ uint8_t s_flock;
++ uint8_t s_ilock;
++ uint8_t s_fmod;
++ uint8_t s_ronly;
++ uint32_t s_time;
++ uint32_t s_tfree;
++ uint16_t s_tinode;
++ uint16_t s_dinfo[4];
++ uint8_t s_fname[6];
++ uint8_t s_fpack[6];
++ uint8_t s_clean;
++ uint8_t s_fill[371];
++ uint32_t s_magic;
++ uint32_t s_type;
++} PACKED;
++
++#define SYSV_SUPERBLOCK_BLOCK 0x01
++#define SYSV_MAGIC 0xfd187e20
++#define XENIX_SUPERBLOCK_BLOCK 0x18
++#define XENIX_MAGIC 0x2b5544
++#define SYSV_MAX_BLOCKSIZE 0x800
++
++int volume_id_probe_sysv(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct sysv_super *vs;
++ struct xenix_super *xs;
++ unsigned int boff;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) {
++ vs = (struct sysv_super *)
++ volume_id_get_buffer(id, off + (boff * SYSV_SUPERBLOCK_BLOCK), 0x200);
++ if (vs == NULL)
++ return -1;
++
++ if (vs->s_magic == cpu_to_le32(SYSV_MAGIC) || vs->s_magic == cpu_to_be32(SYSV_MAGIC)) {
++ volume_id_set_label_raw(id, vs->s_fname, 6);
++ volume_id_set_label_string(id, vs->s_fname, 6);
++ id->type = "sysv";
++ goto found;
++ }
++ }
++
++ for (boff = 0x200; boff <= SYSV_MAX_BLOCKSIZE; boff <<= 1) {
++ xs = (struct xenix_super *)
++ volume_id_get_buffer(id, off + (boff + XENIX_SUPERBLOCK_BLOCK), 0x200);
++ if (xs == NULL)
++ return -1;
++
++ if (xs->s_magic == cpu_to_le32(XENIX_MAGIC) || xs->s_magic == cpu_to_be32(XENIX_MAGIC)) {
++ volume_id_set_label_raw(id, xs->s_fname, 6);
++ volume_id_set_label_string(id, xs->s_fname, 6);
++ id->type = "xenix";
++ goto found;
++ }
++ }
++
++ return -1;
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ return 0;
++}
+
+=== added file 'libvolume_id/udf.c'
+--- grub-0.97.orig/libvolume_id/udf.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/udf.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,173 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct volume_descriptor {
++ struct descriptor_tag {
++ uint16_t id;
++ uint16_t version;
++ uint8_t checksum;
++ uint8_t reserved;
++ uint16_t serial;
++ uint16_t crc;
++ uint16_t crc_len;
++ uint32_t location;
++ } PACKED tag;
++ union {
++ struct anchor_descriptor {
++ uint32_t length;
++ uint32_t location;
++ } PACKED anchor;
++ struct primary_descriptor {
++ uint32_t seq_num;
++ uint32_t desc_num;
++ struct dstring {
++ uint8_t clen;
++ uint8_t c[31];
++ } PACKED ident;
++ } PACKED primary;
++ } PACKED type;
++} PACKED;
++
++struct volume_structure_descriptor {
++ uint8_t type;
++ uint8_t id[5];
++ uint8_t version;
++} PACKED;
++
++#define UDF_VSD_OFFSET 0x8000
++
++int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct volume_descriptor *vd;
++ struct volume_structure_descriptor *vsd;
++ unsigned int bs;
++ unsigned int b;
++ unsigned int type;
++ unsigned int count;
++ unsigned int loc;
++ unsigned int clen;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET, 0x200);
++ if (vsd == NULL)
++ return -1;
++
++ if (memcmp((char *)vsd->id, "NSR02", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "NSR03", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "BEA01", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "BOOT2", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "CD001", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "CDW02", 5) == 0)
++ goto blocksize;
++ if (memcmp((char *)vsd->id, "TEA03", 5) == 0)
++ goto blocksize;
++ return -1;
++
++blocksize:
++ /* search the next VSD to get the logical block size of the volume */
++ for (bs = 0x800; bs < 0x8000; bs += 0x800) {
++ vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + bs, 0x800);
++ if (vsd == NULL)
++ return -1;
++ dbg("test for blocksize: 0x%x", bs);
++ if (vsd->id[0] != '\0')
++ goto nsr;
++ }
++ return -1;
++
++nsr:
++ /* search the list of VSDs for a NSR descriptor */
++ for (b = 0; b < 64; b++) {
++ vsd = (struct volume_structure_descriptor *) volume_id_get_buffer(id, off + UDF_VSD_OFFSET + (b * bs), 0x800);
++ if (vsd == NULL)
++ return -1;
++
++ dbg("vsd: %c%c%c%c%c",
++ vsd->id[0], vsd->id[1], vsd->id[2], vsd->id[3], vsd->id[4]);
++
++ if (vsd->id[0] == '\0')
++ return -1;
++ if (memcmp((char *)vsd->id, "NSR02", 5) == 0)
++ goto anchor;
++ if (memcmp((char *)vsd->id, "NSR03", 5) == 0)
++ goto anchor;
++ }
++ return -1;
++
++anchor:
++ /* read anchor volume descriptor */
++ vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + (256 * bs), 0x200);
++ if (vd == NULL)
++ return -1;
++
++ type = le16_to_cpu(vd->tag.id);
++ if (type != 2) /* TAG_ID_AVDP */
++ goto found;
++
++ /* get desriptor list address and block count */
++ count = le32_to_cpu(vd->type.anchor.length) / bs;
++ loc = le32_to_cpu(vd->type.anchor.location);
++ dbg("0x%x descriptors starting at logical secor 0x%x", count, loc);
++
++ /* pick the primary descriptor from the list */
++ for (b = 0; b < count; b++) {
++ vd = (struct volume_descriptor *) volume_id_get_buffer(id, off + ((loc + b) * bs), 0x200);
++ if (vd == NULL)
++ return -1;
++
++ type = le16_to_cpu(vd->tag.id);
++ dbg("descriptor type %i", type);
++
++ /* check validity */
++ if (type == 0)
++ goto found;
++ if (le32_to_cpu(vd->tag.location) != loc + b)
++ goto found;
++
++ if (type == 1) /* TAG_ID_PVD */
++ goto pvd;
++ }
++ goto found;
++
++pvd:
++ volume_id_set_label_raw(id, &(vd->type.primary.ident.clen), 32);
++
++ clen = vd->type.primary.ident.clen;
++ dbg("label string charsize=%i bit", clen);
++ if (clen == 8)
++ volume_id_set_label_string(id, vd->type.primary.ident.c, 31);
++ else if (clen == 16)
++ volume_id_set_label_unicode16(id, vd->type.primary.ident.c, BE,31);
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "udf";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/ufs.c'
+--- grub-0.97.orig/libvolume_id/ufs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/ufs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,217 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct ufs_super_block {
++ uint32_t fs_link;
++ uint32_t fs_rlink;
++ uint32_t fs_sblkno;
++ uint32_t fs_cblkno;
++ uint32_t fs_iblkno;
++ uint32_t fs_dblkno;
++ uint32_t fs_cgoffset;
++ uint32_t fs_cgmask;
++ uint32_t fs_time;
++ uint32_t fs_size;
++ uint32_t fs_dsize;
++ uint32_t fs_ncg;
++ uint32_t fs_bsize;
++ uint32_t fs_fsize;
++ uint32_t fs_frag;
++ uint32_t fs_minfree;
++ uint32_t fs_rotdelay;
++ uint32_t fs_rps;
++ uint32_t fs_bmask;
++ uint32_t fs_fmask;
++ uint32_t fs_bshift;
++ uint32_t fs_fshift;
++ uint32_t fs_maxcontig;
++ uint32_t fs_maxbpg;
++ uint32_t fs_fragshift;
++ uint32_t fs_fsbtodb;
++ uint32_t fs_sbsize;
++ uint32_t fs_csmask;
++ uint32_t fs_csshift;
++ uint32_t fs_nindir;
++ uint32_t fs_inopb;
++ uint32_t fs_nspf;
++ uint32_t fs_optim;
++ uint32_t fs_npsect_state;
++ uint32_t fs_interleave;
++ uint32_t fs_trackskew;
++ uint32_t fs_id[2];
++ uint32_t fs_csaddr;
++ uint32_t fs_cssize;
++ uint32_t fs_cgsize;
++ uint32_t fs_ntrak;
++ uint32_t fs_nsect;
++ uint32_t fs_spc;
++ uint32_t fs_ncyl;
++ uint32_t fs_cpg;
++ uint32_t fs_ipg;
++ uint32_t fs_fpg;
++ struct ufs_csum {
++ uint32_t cs_ndir;
++ uint32_t cs_nbfree;
++ uint32_t cs_nifree;
++ uint32_t cs_nffree;
++ } PACKED fs_cstotal;
++ int8_t fs_fmod;
++ int8_t fs_clean;
++ int8_t fs_ronly;
++ int8_t fs_flags;
++ union {
++ struct {
++ int8_t fs_fsmnt[512];
++ uint32_t fs_cgrotor;
++ uint32_t fs_csp[31];
++ uint32_t fs_maxcluster;
++ uint32_t fs_cpc;
++ uint16_t fs_opostbl[16][8];
++ } PACKED fs_u1;
++ struct {
++ int8_t fs_fsmnt[468];
++ uint8_t fs_volname[32];
++ uint64_t fs_swuid;
++ int32_t fs_pad;
++ uint32_t fs_cgrotor;
++ uint32_t fs_ocsp[28];
++ uint32_t fs_contigdirs;
++ uint32_t fs_csp;
++ uint32_t fs_maxcluster;
++ uint32_t fs_active;
++ int32_t fs_old_cpc;
++ int32_t fs_maxbsize;
++ int64_t fs_sparecon64[17];
++ int64_t fs_sblockloc;
++ struct ufs2_csum_total {
++ uint64_t cs_ndir;
++ uint64_t cs_nbfree;
++ uint64_t cs_nifree;
++ uint64_t cs_nffree;
++ uint64_t cs_numclusters;
++ uint64_t cs_spare[3];
++ } PACKED fs_cstotal;
++ struct ufs_timeval {
++ int32_t tv_sec;
++ int32_t tv_usec;
++ } PACKED fs_time;
++ int64_t fs_size;
++ int64_t fs_dsize;
++ uint64_t fs_csaddr;
++ int64_t fs_pendingblocks;
++ int32_t fs_pendinginodes;
++ } PACKED fs_u2;
++ } fs_u11;
++ union {
++ struct {
++ int32_t fs_sparecon[53];
++ int32_t fs_reclaim;
++ int32_t fs_sparecon2[1];
++ int32_t fs_state;
++ uint32_t fs_qbmask[2];
++ uint32_t fs_qfmask[2];
++ } PACKED fs_sun;
++ struct {
++ int32_t fs_sparecon[53];
++ int32_t fs_reclaim;
++ int32_t fs_sparecon2[1];
++ uint32_t fs_npsect;
++ uint32_t fs_qbmask[2];
++ uint32_t fs_qfmask[2];
++ } PACKED fs_sunx86;
++ struct {
++ int32_t fs_sparecon[50];
++ int32_t fs_contigsumsize;
++ int32_t fs_maxsymlinklen;
++ int32_t fs_inodefmt;
++ uint32_t fs_maxfilesize[2];
++ uint32_t fs_qbmask[2];
++ uint32_t fs_qfmask[2];
++ int32_t fs_state;
++ } PACKED fs_44;
++ } fs_u2;
++ int32_t fs_postblformat;
++ int32_t fs_nrpos;
++ int32_t fs_postbloff;
++ int32_t fs_rotbloff;
++ uint32_t fs_magic;
++ uint8_t fs_space[1];
++} PACKED;
++
++#define UFS_MAGIC 0x00011954
++#define UFS2_MAGIC 0x19540119
++#define UFS_MAGIC_FEA 0x00195612
++#define UFS_MAGIC_LFN 0x00095014
++
++int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ uint32_t magic;
++ int i;
++ struct ufs_super_block *ufs;
++ int offsets[] = {0, 8, 64, 256, -1};
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ for (i = 0; offsets[i] >= 0; i++) {
++ ufs = (struct ufs_super_block *) volume_id_get_buffer(id, off + (offsets[i] * 0x400), 0x800);
++ if (ufs == NULL)
++ return -1;
++
++ dbg("offset 0x%x", offsets[i] * 0x400);
++ magic = be32_to_cpu(ufs->fs_magic);
++ if ((magic == UFS_MAGIC) ||
++ (magic == UFS2_MAGIC) ||
++ (magic == UFS_MAGIC_FEA) ||
++ (magic == UFS_MAGIC_LFN)) {
++ dbg("magic 0x%08x(be)", magic);
++ goto found;
++ }
++ magic = le32_to_cpu(ufs->fs_magic);
++ if ((magic == UFS_MAGIC) ||
++ (magic == UFS2_MAGIC) ||
++ (magic == UFS_MAGIC_FEA) ||
++ (magic == UFS_MAGIC_LFN)) {
++ dbg("magic 0x%08x(le)", magic);
++ goto found;
++ }
++ }
++ return -1;
++
++found:
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "ufs";
++ switch (magic) {
++ case UFS_MAGIC:
++ strcpy(id->type_version, "1");
++ break;
++ case UFS2_MAGIC:
++ strcpy(id->type_version, "2");
++ volume_id_set_label_raw(id, ufs->fs_u11.fs_u2.fs_volname, 32);
++ volume_id_set_label_string(id, ufs->fs_u11.fs_u2.fs_volname, 32);
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
+
+=== added file 'libvolume_id/util.c'
+--- grub-0.97.orig/libvolume_id/util.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/util.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,472 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <stdlib.h>
++
++#include "strfuncs.h"
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++static char hex[] = "0123456789abcdef";
++
++#define hexhi(val) hex[val >> 4]
++#define hexlo(val) hex[val & 0xf]
++
++/* count of characters used to encode one unicode char */
++static int utf8_encoded_expected_len(const char *str)
++{
++ unsigned char c = (unsigned char)str[0];
++
++ if (c < 0x80)
++ return 1;
++ if ((c & 0xe0) == 0xc0)
++ return 2;
++ if ((c & 0xf0) == 0xe0)
++ return 3;
++ if ((c & 0xf8) == 0xf0)
++ return 4;
++ if ((c & 0xfc) == 0xf8)
++ return 5;
++ if ((c & 0xfe) == 0xfc)
++ return 6;
++ return 0;
++}
++
++/* decode one unicode char */
++static int utf8_encoded_to_unichar(const char *str)
++{
++ int unichar;
++ int len;
++ int i;
++
++ len = utf8_encoded_expected_len(str);
++ switch (len) {
++ case 1:
++ return (int)str[0];
++ case 2:
++ unichar = str[0] & 0x1f;
++ break;
++ case 3:
++ unichar = (int)str[0] & 0x0f;
++ break;
++ case 4:
++ unichar = (int)str[0] & 0x07;
++ break;
++ case 5:
++ unichar = (int)str[0] & 0x03;
++ break;
++ case 6:
++ unichar = (int)str[0] & 0x01;
++ break;
++ default:
++ return -1;
++ }
++
++ for (i = 1; i < len; i++) {
++ if (((int)str[i] & 0xc0) != 0x80)
++ return -1;
++ unichar <<= 6;
++ unichar |= (int)str[i] & 0x3f;
++ }
++
++ return unichar;
++}
++
++/* expected size used to encode one unicode char */
++static int utf8_unichar_to_encoded_len(int unichar)
++{
++ if (unichar < 0x80)
++ return 1;
++ if (unichar < 0x800)
++ return 2;
++ if (unichar < 0x10000)
++ return 3;
++ if (unichar < 0x200000)
++ return 4;
++ if (unichar < 0x4000000)
++ return 5;
++ return 6;
++}
++
++/* check if unicode char has a valid numeric range */
++static int utf8_unichar_valid_range(int unichar)
++{
++ if (unichar > 0x10ffff)
++ return 0;
++ if ((unichar & 0xfffff800) == 0xd800)
++ return 0;
++ if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
++ return 0;
++ if ((unichar & 0xffff) == 0xffff)
++ return 0;
++ return 1;
++}
++
++/* validate one encoded unicode char and return its length */
++int volume_id_utf8_encoded_valid_unichar(const char *str)
++{
++ int len;
++ int unichar;
++ int i;
++
++ len = utf8_encoded_expected_len(str);
++ if (len == 0)
++ return -1;
++
++ /* ascii is valid */
++ if (len == 1)
++ return 1;
++
++ /* check if expected encoded chars are available */
++ for (i = 0; i < len; i++)
++ if ((str[i] & 0x80) != 0x80)
++ return -1;
++
++ unichar = utf8_encoded_to_unichar(str);
++
++ /* check if encoded length matches encoded value */
++ if (utf8_unichar_to_encoded_len(unichar) != len)
++ return -1;
++
++ /* check if value has valid range */
++ if (!utf8_unichar_valid_range(unichar))
++ return -1;
++
++ return len;
++}
++
++size_t volume_id_set_unicode16(uint8_t *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count)
++{
++ size_t i, j;
++ uint16_t c;
++
++ j = 0;
++ for (i = 0; i + 2 <= count; i += 2) {
++ if (endianess == LE)
++ c = (buf[i+1] << 8) | buf[i];
++ else
++ c = (buf[i] << 8) | buf[i+1];
++ if (c == 0) {
++ str[j] = '\0';
++ break;
++ } else if (c < 0x80) {
++ if (j+1 >= len)
++ break;
++ str[j++] = (uint8_t) c;
++ } else if (c < 0x800) {
++ if (j+2 >= len)
++ break;
++ str[j++] = (uint8_t) (0xc0 | (c >> 6));
++ str[j++] = (uint8_t) (0x80 | (c & 0x3f));
++ } else {
++ if (j+3 >= len)
++ break;
++ str[j++] = (uint8_t) (0xe0 | (c >> 12));
++ str[j++] = (uint8_t) (0x80 | ((c >> 6) & 0x3f));
++ str[j++] = (uint8_t) (0x80 | (c & 0x3f));
++ }
++ }
++ str[j] = '\0';
++ return j;
++}
++
++static char *usage_to_string(enum volume_id_usage usage_id)
++{
++ switch (usage_id) {
++ case VOLUME_ID_FILESYSTEM:
++ return "filesystem";
++ case VOLUME_ID_OTHER:
++ return "other";
++ case VOLUME_ID_RAID:
++ return "raid";
++ case VOLUME_ID_DISKLABEL:
++ return "disklabel";
++ case VOLUME_ID_CRYPTO:
++ return "crypto";
++ case VOLUME_ID_UNPROBED:
++ return "unprobed";
++ case VOLUME_ID_UNUSED:
++ return "unused";
++ }
++ return NULL;
++}
++
++void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id)
++{
++ id->usage_id = usage_id;
++ id->usage = usage_to_string(usage_id);
++}
++
++void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count)
++{
++ if (count > sizeof(id->label))
++ count = sizeof(id->label);
++
++ memcpy(id->label_raw, buf, count);
++ id->label_raw_len = count;
++}
++
++void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count)
++{
++ size_t i;
++
++ if (count >= sizeof(id->label))
++ count = sizeof(id->label)-1;
++
++ memcpy(id->label, buf, count);
++ id->label[count] = '\0';
++
++ /* remove trailing whitespace */
++ i = strnlen(id->label, count);
++ while (i--) {
++ if (!isspace(id->label[i]))
++ break;
++ }
++ id->label[i+1] = '\0';
++}
++
++void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count)
++{
++ if (count >= sizeof(id->label))
++ count = sizeof(id->label)-1;
++
++ volume_id_set_unicode16((uint8_t *)id->label, sizeof(id->label), buf, endianess, count);
++}
++
++void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, size_t len, enum uuid_format format)
++{
++ unsigned int i;
++ unsigned int count = 0;
++ char *uuid;
++
++ if (len > sizeof(id->uuid_raw))
++ len = sizeof(id->uuid_raw);
++
++ switch(format) {
++ case UUID_STRING:
++ count = len;
++ break;
++ case UUID_HEX_STRING:
++ count = len;
++ break;
++ case UUID_DOS:
++ count = 4;
++ break;
++ case UUID_64BIT_LE:
++ case UUID_64BIT_BE:
++ count = 8;
++ break;
++ case UUID_DCE:
++ count = 16;
++ break;
++ case UUID_FOURINT:
++ count = 35;
++ break;
++ }
++ memcpy(id->uuid_raw, buf, count);
++ id->uuid_raw_len = count;
++
++ /* if set, create string in the same format, the native platform uses */
++ for (i = 0; i < count; i++)
++ if (buf[i] != 0)
++ goto set;
++ return;
++
++set:
++ uuid = id->uuid;
++ switch(format) {
++ case UUID_DOS:
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid = '\0';
++ break;
++ case UUID_64BIT_LE:
++ *uuid++ = hexhi(buf[7]);
++ *uuid++ = hexlo(buf[7]);
++ *uuid++ = hexhi(buf[6]);
++ *uuid++ = hexlo(buf[6]);
++ *uuid++ = hexhi(buf[5]);
++ *uuid++ = hexlo(buf[5]);
++ *uuid++ = hexhi(buf[4]);
++ *uuid++ = hexlo(buf[4]);
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid = '\0';
++ break;
++ case UUID_64BIT_BE:
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = hexhi(buf[4]);
++ *uuid++ = hexlo(buf[4]);
++ *uuid++ = hexhi(buf[5]);
++ *uuid++ = hexlo(buf[5]);
++ *uuid++ = hexhi(buf[6]);
++ *uuid++ = hexlo(buf[6]);
++ *uuid++ = hexhi(buf[7]);
++ *uuid++ = hexlo(buf[7]);
++ *uuid = '\0';
++ break;
++ case UUID_DCE:
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[4]);
++ *uuid++ = hexlo(buf[4]);
++ *uuid++ = hexhi(buf[5]);
++ *uuid++ = hexlo(buf[5]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[6]);
++ *uuid++ = hexlo(buf[6]);
++ *uuid++ = hexhi(buf[7]);
++ *uuid++ = hexlo(buf[7]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[8]);
++ *uuid++ = hexlo(buf[8]);
++ *uuid++ = hexhi(buf[9]);
++ *uuid++ = hexlo(buf[9]);
++ *uuid++ = '-';
++ *uuid++ = hexhi(buf[10]);
++ *uuid++ = hexlo(buf[10]);
++ *uuid++ = hexhi(buf[11]);
++ *uuid++ = hexlo(buf[11]);
++ *uuid++ = hexhi(buf[12]);
++ *uuid++ = hexlo(buf[12]);
++ *uuid++ = hexhi(buf[13]);
++ *uuid++ = hexlo(buf[13]);
++ *uuid++ = hexhi(buf[14]);
++ *uuid++ = hexlo(buf[14]);
++ *uuid++ = hexhi(buf[15]);
++ *uuid++ = hexlo(buf[15]);
++ *uuid = '\0';
++ break;
++ case UUID_HEX_STRING:
++ /* translate A..F to a..f */
++ memcpy(id->uuid, buf, count);
++ for (i = 0; i < count; i++)
++ if (id->uuid[i] >= 'A' && id->uuid[i] <= 'F')
++ id->uuid[i] = (id->uuid[i] - 'A') + 'a';
++ id->uuid[count] = '\0';
++ break;
++ case UUID_STRING:
++ memcpy(id->uuid, buf, count);
++ id->uuid[count] = '\0';
++ break;
++ case UUID_FOURINT:
++ *uuid++ = hexhi(buf[0]);
++ *uuid++ = hexlo(buf[0]);
++ *uuid++ = hexhi(buf[1]);
++ *uuid++ = hexlo(buf[1]);
++ *uuid++ = hexhi(buf[2]);
++ *uuid++ = hexlo(buf[2]);
++ *uuid++ = hexhi(buf[3]);
++ *uuid++ = hexlo(buf[3]);
++ *uuid++ = ':';
++ *uuid++ = hexhi(buf[4]);
++ *uuid++ = hexlo(buf[4]);
++ *uuid++ = hexhi(buf[5]);
++ *uuid++ = hexlo(buf[5]);
++ *uuid++ = hexhi(buf[6]);
++ *uuid++ = hexlo(buf[6]);
++ *uuid++ = hexhi(buf[7]);
++ *uuid++ = hexlo(buf[7]);
++ *uuid++ = ':';
++ *uuid++ = hexhi(buf[8]);
++ *uuid++ = hexlo(buf[8]);
++ *uuid++ = hexhi(buf[9]);
++ *uuid++ = hexlo(buf[9]);
++ *uuid++ = hexhi(buf[10]);
++ *uuid++ = hexlo(buf[10]);
++ *uuid++ = hexhi(buf[11]);
++ *uuid++ = hexlo(buf[11]);
++ *uuid++ = ':';
++ *uuid++ = hexhi(buf[12]);
++ *uuid++ = hexlo(buf[12]);
++ *uuid++ = hexhi(buf[13]);
++ *uuid++ = hexlo(buf[13]);
++ *uuid++ = hexhi(buf[14]);
++ *uuid++ = hexlo(buf[14]);
++ *uuid++ = hexhi(buf[15]);
++ *uuid++ = hexlo(buf[15]);
++ *uuid = '\0';
++ break;
++ default:
++ *uuid = '\0';
++ break;
++ }
++}
++
++uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len)
++{
++ info("get buffer off 0x%llx(%llu), len 0x%zx", (unsigned long long) off, (unsigned long long) off, len);
++ /* check if requested area fits in superblock buffer */
++ if (off + len <= SB_BUFFER_SIZE) {
++ /* check if we need to read */
++ if ((off + len) > id->sbbuf_len) {
++ if (devread (0, 0, off + len, (char*)id->sbbuf) == 0)
++ {
++ return NULL;
++ }
++ id->sbbuf_len = off + len;
++ }
++ return &(id->sbbuf[off]);
++ } else {
++ if (len > SEEK_BUFFER_SIZE) {
++ dbg("seek buffer too small %d", SEEK_BUFFER_SIZE);
++ return NULL;
++ }
++
++ /* check if we need to read */
++ if ((off < id->seekbuf_off) || ((off + len) > (id->seekbuf_off + id->seekbuf_len))) {
++ info("read seekbuf off:0x%llx len:0x%zx", (unsigned long long) off, len);
++ if (devread(off >> 9, off & 0x1ff, len, (char*)id->seekbuf) == 0)
++ {
++ return NULL;
++ }
++ id->seekbuf_off = off;
++ id->seekbuf_len = len;
++ }
++ return &(id->seekbuf[off - id->seekbuf_off]);
++ }
++}
+
+=== added file 'libvolume_id/util.h'
+--- grub-0.97.orig/libvolume_id/util.h 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/util.h 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,98 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005-2006 Kay Sievers <kay.sievers@vrfy.org>
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _VOLUME_ID_UTIL_
++#define _VOLUME_ID_UTIL_
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <endian.h>
++#include <byteswap.h>
++#include <syslog.h>
++
++#define ALLOWED_CHARS "#+-.:=@_"
++
++#ifndef PACKED
++#define PACKED __attribute__((packed))
++#endif
++
++#define err(format, arg...) volume_id_log_fn(LOG_ERR, __FILE__, __LINE__, format, ##arg)
++#ifdef INFO
++#define info(format, arg...) volume_id_log_fn(LOG_INFO, __FILE__, __LINE__, format, ##arg)
++#else
++#define info(format, arg...) do { } while (0)
++#endif
++
++#ifdef DEBUG
++#define dbg(format, arg...) volume_id_log_fn(LOG_DEBUG, __FILE__, __LINE__, format, ##arg)
++#else
++#define dbg(format, arg...) do { } while (0)
++#endif
++
++/* size of superblock buffer, reiserfs block is at 64k */
++#define SB_BUFFER_SIZE 0x11000
++/* size of seek buffer, FAT cluster is 32k max */
++#define SEEK_BUFFER_SIZE 0x10000
++
++#ifdef __BYTE_ORDER
++#if (__BYTE_ORDER == __LITTLE_ENDIAN)
++#define le16_to_cpu(x) (x)
++#define le32_to_cpu(x) (x)
++#define le64_to_cpu(x) (x)
++#define be16_to_cpu(x) bswap_16(x)
++#define be32_to_cpu(x) bswap_32(x)
++#define cpu_to_le16(x) (x)
++#define cpu_to_le32(x) (x)
++#define cpu_to_be32(x) bswap_32(x)
++#elif (__BYTE_ORDER == __BIG_ENDIAN)
++#define le16_to_cpu(x) bswap_16(x)
++#define le32_to_cpu(x) bswap_32(x)
++#define le64_to_cpu(x) bswap_64(x)
++#define be16_to_cpu(x) (x)
++#define be32_to_cpu(x) (x)
++#define cpu_to_le16(x) bswap_16(x)
++#define cpu_to_le32(x) bswap_32(x)
++#define cpu_to_be32(x) (x)
++#endif
++#endif /* __BYTE_ORDER */
++
++enum uuid_format {
++ UUID_STRING,
++ UUID_HEX_STRING,
++ UUID_DCE,
++ UUID_DOS,
++ UUID_64BIT_LE,
++ UUID_64BIT_BE,
++ UUID_FOURINT,
++};
++
++enum endian {
++ LE = 0,
++ BE = 1
++};
++
++extern int volume_id_utf8_encoded_valid_unichar(const char *str);
++extern size_t volume_id_set_unicode16(uint8_t *str, size_t len, const uint8_t *buf, enum endian endianess, size_t count);
++extern void volume_id_set_usage(struct volume_id *id, enum volume_id_usage usage_id);
++extern void volume_id_set_label_raw(struct volume_id *id, const uint8_t *buf, size_t count);
++extern void volume_id_set_label_string(struct volume_id *id, const uint8_t *buf, size_t count);
++extern void volume_id_set_label_unicode16(struct volume_id *id, const uint8_t *buf, enum endian endianess, size_t count);
++extern void volume_id_set_uuid(struct volume_id *id, const uint8_t *buf, size_t len, enum uuid_format format);
++extern uint8_t *volume_id_get_buffer(struct volume_id *id, uint64_t off, size_t len);
++extern void volume_id_free_buffer(struct volume_id *id);
++
++#endif /* _VOLUME_ID_UTIL_ */
++
+
+=== added file 'libvolume_id/via_raid.c'
+--- grub-0.97.orig/libvolume_id/via_raid.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/via_raid.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,88 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2005 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * Based on information taken from dmraid:
++ * Copyright (C) 2004-2006 Heinz Mauelshagen, Red Hat GmbH
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct via_meta {
++ uint16_t signature;
++ uint8_t version_number;
++ struct via_array {
++ uint16_t disk_bit_mask;
++ uint8_t disk_array_ex;
++ uint32_t capacity_low;
++ uint32_t capacity_high;
++ uint32_t serial_checksum;
++ } PACKED array;
++ uint32_t serial_checksum[8];
++ uint8_t checksum;
++} PACKED;
++
++#define VIA_SIGNATURE 0xAA55
++
++/* 8 bit checksum on first 50 bytes of metadata. */
++static uint8_t meta_checksum(struct via_meta *via)
++{
++ uint8_t i = 50, sum = 0;
++
++ while (i--)
++ sum += ((uint8_t*) via)[i];
++
++ return sum == via->checksum;
++}
++
++
++int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ const uint8_t *buf;
++ uint64_t meta_off;
++ struct via_meta *via;
++
++ dbg("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ if (size < 0x10000)
++ return -1;
++
++ meta_off = ((size / 0x200)-1) * 0x200;
++
++ buf = volume_id_get_buffer(id, off + meta_off, 0x200);
++ if (buf == NULL)
++ return -1;
++
++ via = (struct via_meta *) buf;
++ if (le16_to_cpu(via->signature) != VIA_SIGNATURE)
++ return -1;
++
++ if (via->version_number > 1)
++ return -1;
++
++ if (!meta_checksum(via))
++ return -1;
++
++ volume_id_set_usage(id, VOLUME_ID_RAID);
++ sprintf(id->type_version, "%u", via->version_number);
++ id->type = "via_raid_member";
++
++ return 0;
++}
+
+=== added file 'libvolume_id/volume_id.c'
+--- grub-0.97.orig/libvolume_id/volume_id.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/volume_id.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,222 @@
++/*
++ * volume_id - reads volume label and uuid
++ *
++ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
++ * Grub Port, Copyright (C) 2008 Canonical Ltd.
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include <fcntl.h>
++#include <sys/stat.h>
++
++#include "volume_id.h"
++#include "util.h"
++#include "strfuncs.h"
++#include "shared.h"
++
++#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
++
++struct prober {
++ volume_id_probe_fn_t prober;
++ const char *name[4];
++};
++
++#define NOT_SUPPORTED(x)
++#define SUPPORTED(x) x
++
++static const struct prober prober_raid[] = {
++ { volume_id_probe_ddf_raid, { "ddf_raid", } },
++
++ /* { volume_id_probe_linux_raid, { "linux_raid", } }, */
++ /* { volume_id_probe_intel_software_raid, { "isw_raid", } }, */
++ /* { volume_id_probe_lsi_mega_raid, { "lsi_mega_raid", } }, */
++ /* { volume_id_probe_via_raid, { "via_raid", } }, */
++ /* { volume_id_probe_silicon_medley_raid, { "silicon_medley_raid", } }, */
++ /* { volume_id_probe_nvidia_raid, { "nvidia_raid", } }, */
++ /* { volume_id_probe_promise_fasttrack_raid, { "promise_fasttrack_raid", } }, */
++ /* { volume_id_probe_highpoint_45x_raid, { "highpoint_raid", } }, */
++ /* { volume_id_probe_adaptec_raid, { "adaptec_raid", } }, */
++ /* { volume_id_probe_jmicron_raid, { "jmicron_raid", } }, */
++ /* { volume_id_probe_lvm1, { "lvm1", } }, */
++ /* { volume_id_probe_lvm2, { "lvm2", } }, */
++ /* { volume_id_probe_highpoint_37x_raid, { "highpoint_raid", } }, */
++};
++
++static const struct prober prober_filesystem[] = {
++ { volume_id_probe_vfat, { "vfat", } },
++ { volume_id_probe_luks, { "luks", } },
++ { volume_id_probe_xfs, { "xfs", } },
++ { volume_id_probe_ext, { "ext2", "ext3", "jbd", } },
++ { volume_id_probe_reiserfs, { "reiserfs", "reiser4", } },
++ { volume_id_probe_jfs, { "jfs", } },
++ { volume_id_probe_hfs_hfsplus, { "hfs", "hfsplus", } },
++ { volume_id_probe_ntfs, { "ntfs", } },
++ { volume_id_probe_ocfs1, { "ocfs1", } },
++ { volume_id_probe_ocfs2, { "ocfs2", } },
++
++ /* { volume_id_probe_linux_swap, { "swap", } }, */
++ /* { volume_id_probe_udf, { "udf", } }, */
++ /* { volume_id_probe_iso9660, { "iso9660", } }, */
++ /* { volume_id_probe_ufs, { "ufs", } }, */
++ /* { volume_id_probe_cramfs, { "cramfs", } }, */
++ /* { volume_id_probe_romfs, { "romfs", } }, */
++ /* { volume_id_probe_hpfs, { "hpfs", } }, */
++ /* { volume_id_probe_sysv, { "sysv", "xenix", } }, */
++ /* { volume_id_probe_minix, { "minix", } }, */
++ /* { volume_id_probe_vxfs, { "vxfs", } }, */
++ /* { volume_id_probe_squashfs, { "squashfs", } }, */
++ /* { volume_id_probe_netware, { "netware", } }, */
++};
++
++/* the user can overwrite this log function */
++static void default_log(int priority, const char *file, int line, const char *format, ...)
++{
++ return;
++}
++
++volume_id_log_fn_t volume_id_log_fn = default_log;
++
++/**
++ * volume_id_get_type:
++ * @id: Probing context
++ * @type: Type string. Must not be freed by the caller.
++ *
++ * Get the type string after a successful probe.
++ *
++ * Returns: 1 if the value was set, 0 otherwise.
++ **/
++int volume_id_get_type(struct volume_id *id, const char **type)
++{
++ if (id == NULL)
++ return 0;
++ if (type == NULL)
++ return 0;
++ if (id->usage_id == VOLUME_ID_UNUSED)
++ return 0;
++
++ *type = id->type;
++ return 1;
++}
++
++
++/**
++ * volume_id_get_uuid:
++ * @id: Probing context.
++ * @uuid: UUID string. Must not be freed by the caller.
++ *
++ * Get the raw UUID string after a successful probe.
++ *
++ * Returns: 1 if the value was set, 0 otherwise.
++ **/
++int volume_id_get_uuid(struct volume_id *id, const char **uuid)
++{
++ if (id == NULL)
++ return 0;
++ if (uuid == NULL)
++ return 0;
++ if (id->usage_id == VOLUME_ID_UNUSED)
++ return 0;
++
++ *uuid = id->uuid;
++ return 1;
++}
++
++/**
++ * volume_id_probe_raid:
++ * @id: Probing context.
++ * @off: Probing offset relative to the start of the device.
++ * @size: Total size of the device.
++ *
++ * Probe device for all known raid signatures.
++ *
++ * Returns: 0 on successful probe, otherwise negative value.
++ **/
++int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ unsigned int i;
++
++ if (id == NULL)
++ return -1;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ for (i = 0; i < ARRAY_SIZE(prober_raid); i++)
++ if (prober_raid[i].prober(id, off, size) == 0)
++ goto found;
++ return -1;
++
++found:
++ return 0;
++}
++
++/**
++ * volume_id_probe_filesystem:
++ * @id: Probing context.
++ * @off: Probing offset relative to the start of the device.
++ * @size: Total size of the device.
++ *
++ * Probe device for all known filesystem signatures.
++ *
++ * Returns: 0 on successful probe, otherwise negative value.
++ **/
++int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ unsigned int i;
++
++ if (id == NULL)
++ return -1;
++
++ info("probing at offset 0x%llx, size 0x%llx",
++ (unsigned long long) off, (unsigned long long) size);
++
++ for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++)
++ if (prober_filesystem[i].prober(id, off, size) == 0)
++ goto found;
++ return -1;
++
++found:
++ return 0;
++}
++
++/**
++ * volume_id_probe_raid:
++ * @all_probers_fn: prober function to called for all known probing routines.
++ * @id: Context passed to prober function.
++ * @off: Offset value passed to prober function.
++ * @size: Size value passed to prober function.
++ * @data: Arbitrary data passed to the prober function.
++ *
++ * Run a custom function for all known probing routines.
++ **/
++void volume_id_all_probers(all_probers_fn_t all_probers_fn,
++ struct volume_id *id, uint64_t off, uint64_t size,
++ void *data)
++{
++ unsigned int i;
++
++ if (all_probers_fn == NULL)
++ return;
++
++ for (i = 0; i < ARRAY_SIZE(prober_raid); i++) {
++ if (all_probers_fn(prober_raid[i].prober, id, off, size, data) != 0)
++ goto out;
++ }
++ for (i = 0; i < ARRAY_SIZE(prober_filesystem); i++) {
++ if (all_probers_fn(prober_filesystem[i].prober, id, off, size, data) != 0)
++ goto out;
++ }
++out:
++ return;
++}
+
+=== added file 'libvolume_id/volume_id.h'
+--- grub-0.97.orig/libvolume_id/volume_id.h 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/volume_id.h 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,137 @@
++/*
++ * volume_id - reads volume label and uuid
++ *
++ * Copyright (C) 2005-2007 Kay Sievers <kay.sievers@vrfy.org>
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _LIBVOLUME_ID_H_
++#define _LIBVOLUME_ID_H_
++
++#include <stdint.h>
++#include <stddef.h>
++
++typedef void (*volume_id_log_fn_t)(int priority, const char *file, int line, const char *format, ...) ;
++
++extern volume_id_log_fn_t volume_id_log_fn;
++
++struct volume_id;
++typedef int (*volume_id_probe_fn_t)(struct volume_id *id, uint64_t off, uint64_t size);
++typedef int (*all_probers_fn_t)(volume_id_probe_fn_t probe_fn,
++ struct volume_id *id, uint64_t off, uint64_t size,
++ void *data);
++
++extern struct volume_id *volume_id_open_fd(int fd);
++extern void volume_id_close(struct volume_id *id);
++extern int volume_id_probe_filesystem(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_all(struct volume_id *id, uint64_t off, uint64_t size);
++extern const volume_id_probe_fn_t *volume_id_get_prober_by_type(const char *type);
++extern void volume_id_all_probers(all_probers_fn_t all_probers_fn,
++ struct volume_id *id, uint64_t off, uint64_t size,
++ void *data);
++extern int volume_id_get_label(struct volume_id *id, const char **label);
++extern int volume_id_get_label_raw(struct volume_id *id, const uint8_t **label, size_t *len);
++extern int volume_id_get_uuid(struct volume_id *id, const char **uuid);
++extern int volume_id_get_uuid_raw(struct volume_id *id, const uint8_t **uuid, size_t *len);
++extern int volume_id_get_usage(struct volume_id *id, const char **usage);
++extern int volume_id_get_type(struct volume_id *id, const char **type);
++extern int volume_id_get_type_version(struct volume_id *id, const char **type_version);
++extern int volume_id_encode_string(const char *str, char *str_enc, size_t len);
++
++/*
++ * Note: everything below will be made private or removed from
++ * a future version, and a new major release of libvolume_id
++ */
++
++extern struct volume_id *volume_id_open_node(const char *path);
++
++#define VOLUME_ID_LABEL_SIZE 64
++#define VOLUME_ID_UUID_SIZE 36
++#define VOLUME_ID_FORMAT_SIZE 32
++#define VOLUME_ID_PATH_MAX 256
++#define VOLUME_ID_PARTITIONS_MAX 256
++
++enum volume_id_usage {
++ VOLUME_ID_UNUSED,
++ VOLUME_ID_UNPROBED,
++ VOLUME_ID_OTHER,
++ VOLUME_ID_FILESYSTEM,
++ VOLUME_ID_RAID,
++ VOLUME_ID_DISKLABEL,
++ VOLUME_ID_CRYPTO,
++};
++
++#include <util.h>
++
++struct volume_id {
++ uint8_t label_raw[VOLUME_ID_LABEL_SIZE];
++ size_t label_raw_len;
++ char label[VOLUME_ID_LABEL_SIZE+1];
++ uint8_t uuid_raw[VOLUME_ID_UUID_SIZE];
++ size_t uuid_raw_len;
++ char uuid[VOLUME_ID_UUID_SIZE+1];
++ enum volume_id_usage usage_id;
++ char *usage;
++ char *type;
++ char type_version[VOLUME_ID_FORMAT_SIZE];
++
++ int fd;
++ uint8_t sbbuf[SB_BUFFER_SIZE];
++ size_t sbbuf_len;
++ uint8_t seekbuf[SEEK_BUFFER_SIZE];
++ uint64_t seekbuf_off;
++ size_t seekbuf_len;
++ int fd_close:1;
++};
++
++/* filesystems */
++extern int volume_id_probe_cramfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ext(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_vfat(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_hfs_hfsplus(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_hpfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_iso9660(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_jfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_minix(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ntfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ocfs1(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ocfs2(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_reiserfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_romfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_sysv(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_udf(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ufs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_vxfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_xfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_squashfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_netware(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_gfs(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_gfs2(struct volume_id *id, uint64_t off, uint64_t size);
++
++/* special formats */
++extern int volume_id_probe_linux_swap(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_luks(struct volume_id *id, uint64_t off, uint64_t size);
++
++/* raid */
++extern int volume_id_probe_linux_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_lvm1(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_lvm2(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_ddf_raid(struct volume_id *id, uint64_t off, uint64_t size);
++
++/* bios raid */
++extern int volume_id_probe_intel_software_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_highpoint_37x_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_highpoint_45x_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_lsi_mega_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_nvidia_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_promise_fasttrack_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_silicon_medley_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_via_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_adaptec_raid(struct volume_id *id, uint64_t off, uint64_t size);
++extern int volume_id_probe_jmicron_raid(struct volume_id *id, uint64_t off, uint64_t size);
++
++#endif
+
+=== added file 'libvolume_id/vxfs.c'
+--- grub-0.97.orig/libvolume_id/vxfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/vxfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,49 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++#define VXFS_SUPER_MAGIC 0xa501FCF5
++
++struct vxfs_super {
++ uint32_t vs_magic;
++ int32_t vs_version;
++} PACKED;
++
++int volume_id_probe_vxfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct vxfs_super *vxs;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ vxs = (struct vxfs_super *) volume_id_get_buffer(id, off + 0x200, 0x200);
++ if (vxs == NULL)
++ return -1;
++
++ if (vxs->vs_magic == cpu_to_le32(VXFS_SUPER_MAGIC)) {
++ sprintf(id->type_version, "%u", (unsigned int) vxs->vs_version);
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "vxfs";
++ return 0;
++ }
++
++ return -1;
++}
+
+=== added file 'libvolume_id/xfs.c'
+--- grub-0.97.orig/libvolume_id/xfs.c 1970-01-01 00:00:00 +0000
++++ grub-0.97/libvolume_id/xfs.c 2008-07-15 12:31:43 +0000
+@@ -0,0 +1,59 @@
++/*
++ * volume_id - reads filesystem label and uuid
++ *
++ * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
++ *
++ * This program 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 version 2 of the License.
++ */
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE 1
++#endif
++
++#ifdef HAVE_CONFIG_H
++# include <config.h>
++#endif
++
++#include "volume_id.h"
++#include "util.h"
++#include "shared.h"
++
++struct xfs_super_block {
++ uint8_t magic[4];
++ uint32_t blocksize;
++ uint64_t dblocks;
++ uint64_t rblocks;
++ uint32_t dummy1[2];
++ uint8_t uuid[16];
++ uint32_t dummy2[15];
++ uint8_t fname[12];
++ uint32_t dummy3[2];
++ uint64_t icount;
++ uint64_t ifree;
++ uint64_t fdblocks;
++} PACKED;
++
++int volume_id_probe_xfs(struct volume_id *id, uint64_t off, uint64_t size)
++{
++ struct xfs_super_block *xs;
++
++ info("probing at offset 0x%llx", (unsigned long long) off);
++
++ xs = (struct xfs_super_block *) volume_id_get_buffer(id, off, 0x200);
++ if (xs == NULL)
++ return -1;
++
++ if (memcmp((char *)xs->magic, "XFSB", 4) != 0)
++ return -1;
++
++ volume_id_set_label_raw(id, xs->fname, 12);
++ volume_id_set_label_string(id, xs->fname, 12);
++ volume_id_set_uuid(id, xs->uuid, 0, UUID_DCE);
++
++ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
++ id->type = "xfs";
++
++ return 0;
++}
+
+=== modified file 'stage2/Makefile.am'
+--- grub-0.97.orig/stage2/Makefile.am 2005-02-02 20:40:05 +0000
++++ grub-0.97/stage2/Makefile.am 2008-07-09 17:23:44 +0000
+@@ -13,6 +13,10 @@
+ # For <stage1.h>.
+ INCLUDES = -I$(top_srcdir)/stage1
+
++if UUID_SUPPORT
++INCLUDES += -I$(top_srcdir)/libvolume_id
++endif
++
+ # The library for /sbin/grub.
+ noinst_LIBRARIES = libgrub.a
+ libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
+@@ -61,6 +65,12 @@
+ PXELOADER_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
+ START_ELTORITO_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
+
++if UUID_SUPPORT
++UUID_FLAGS = -DSUPPORT_UUID=1
++else
++UUID_FLAGS =
++endif
++
+ if NETBOOT_SUPPORT
+ NETBOOT_FLAGS = -I$(top_srcdir)/netboot -DSUPPORT_NETBOOT=1
+ else
+@@ -82,6 +92,8 @@
+ STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
+ $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS)
+
++STAGE2_COMPILE += $(UUID_FLAGS)
++
+ STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
+ STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1
+
+@@ -97,7 +109,12 @@
+
+ if NETBOOT_SUPPORT
+ pre_stage2_exec_LDADD = ../netboot/libdrivers.a
+-endif
++else
++if UUID_SUPPORT
++pre_stage2_exec_LDADD = ../libvolume_id/libvolume_id.a
++endif
++endif
++
+
+ if DISKLESS_SUPPORT
+ BUILT_SOURCES = stage2_size.h diskless_size.h
+
+=== modified file 'stage2/builtins.c'
+--- grub-0.97.orig/stage2/builtins.c 2008-01-28 18:15:31 +0000
++++ grub-0.97/stage2/builtins.c 2008-07-09 17:23:44 +0000
+@@ -49,6 +49,10 @@
+ # include <md5.h>
+ #endif
+
++#ifdef SUPPORT_UUID
++#include <volume_id.h>
++#endif
++
+ /* The type of kernel loaded. */
+ kernel_t kernel_type;
+ /* The boot device. */
+@@ -4790,6 +4794,168 @@
+ "Probe VBE information. If the mode number MODE is specified, show only"
+ " the information about only the mode."
+ };
++
++
++
++#ifdef SUPPORT_UUID
++
++struct uuid_callback_data
++{
++ int found; /* 1 if uuid matches */
++ char *uuid; /* uuid to look for */
++};
++
++static void uuid_info_print(struct volume_id *id, const char *uuid)
++{
++ const char *type;
++ int i;
++
++ volume_id_get_type(id, &type);
++ grub_printf("(hd%d", current_drive - 0x80);
++ if ((current_partition & 0xFF0000) != 0xFF0000)
++ {
++ grub_printf (",%d", (current_partition >> 16) & 0xFF);
++ }
++ if ((current_partition & 0x00FF00) != 0x00FF00)
++ {
++ grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
++ }
++ grub_printf(") %s",type);
++ for (i=0;i<6-strlen(type);i++)
++ {
++ grub_putchar(' ');
++ }
++ grub_printf(" %s\n",uuid);
++}
++
++static int uuid_all_probers(volume_id_probe_fn_t probe_fn,
++ struct volume_id *id,
++ uint64_t off,
++ uint64_t size,
++ void *data)
++{
++ struct uuid_callback_data *uc_data = (struct uuid_callback_data*)data;
++
++ if (probe_fn(id, off, size) == 0)
++ {
++ const char *volume_uuid;
++ if (volume_id_get_uuid(id, &volume_uuid))
++ {
++ if (!*(uc_data->uuid))
++ {
++ uuid_info_print(id, volume_uuid);
++ }
++ else
++ {
++ if (strcmp(volume_uuid, uc_data->uuid) == 0)
++ {
++ grub_printf("Boot from ");
++ uuid_info_print(id, volume_uuid);
++ uc_data->found = 1;
++ return 1;
++ }
++ }
++ }
++ }
++ return 0;
++}
++
++/* uuid find */
++/* Search for the uuid arg in all of partitions. */
++static int
++uuid_func(char *arg, int flag)
++{
++ unsigned long drive;
++ unsigned long tmp_drive = saved_drive;
++ unsigned long tmp_partition = saved_partition;
++ struct uuid_callback_data uc_data;
++
++ uc_data.uuid = arg;
++ uc_data.found = 0;
++
++ /* Just hard disks and USB drives supported by BIOS */
++ for (drive = 0x80; drive < 0x88; drive++)
++ {
++ unsigned long part = 0xFFFFFF;
++ unsigned long start, len, offset, ext_offset, gpt_offset;
++ int type, entry, gpt_count, gpt_size;
++ char *buf = (char *) RAW_ADDR(0x100000);
++ struct volume_id *vol_id = (struct volume_id *) RAW_ADDR (0x100000 + SECTOR_SIZE);
++
++ current_drive = drive;
++ while (next_partition (drive, 0xFFFFFF, &part, &type,
++ &start, &len, &offset, &entry,
++ &ext_offset, &gpt_offset,
++ &gpt_count, &gpt_size, buf))
++ {
++ if (type != PC_SLICE_TYPE_NONE
++ && ! IS_PC_SLICE_TYPE_BSD (type)
++ && ! IS_PC_SLICE_TYPE_EXTENDED (type))
++ {
++ current_partition = part;
++ errnum = ERR_NONE;
++ /* Attempt to open device, conventional way */
++ if (! open_device ())
++ {
++ errnum = ERR_NONE;
++ /* Failed, like NTFS or FAT filesystems, so try the rootnoverify way */
++ if (open_partition ())
++ {
++ set_bootdev (0);
++ if (errnum)
++ {
++ /* Give up */
++ errnum = ERR_NONE;
++ continue;
++ }
++ }
++ }
++
++ /* And probe for uuid across all fs types */
++ saved_drive = current_drive;
++ saved_partition = current_partition;
++
++ grub_memset(vol_id, 0, sizeof(struct volume_id) );
++ volume_id_all_probers(uuid_all_probers, vol_id, 0, len, (void*)&uc_data);
++ if (uc_data.found)
++ {
++ /* Success! */
++ errnum = ERR_NONE;
++ return 0;
++ }
++ }
++ /* We want to ignore any error here. */
++ errnum = ERR_NONE;
++ }
++
++ /* next_partition always sets ERRNUM in the last call, so clear it. */
++ errnum = ERR_NONE;
++ }
++
++ saved_drive = tmp_drive;
++ saved_partition = tmp_partition;
++ current_drive = GRUB_INVALID_DRIVE;
++ current_partition = 0xFFFFFF;
++ errnum = ERR_FILE_NOT_FOUND;
++
++ if (!*arg)
++ {
++ errnum = ERR_NONE;
++ return 0;
++ }
++ return 1;
++}
++
++static struct builtin builtin_uuid =
++{
++ "uuid",
++ uuid_func,
++ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
++ "uuid UUID",
++ "Set the current \"root device\" to the device with the uuid UUID,"
++ " then attempt to mount it"
++};
++#endif
+
+
+ /* The table of builtin commands. Sorted in dictionary order. */
+@@ -4879,6 +5045,9 @@
+ &builtin_title,
+ &builtin_unhide,
+ &builtin_uppermem,
++#ifdef SUPPORT_UUID
++ &builtin_uuid,
++#endif
+ &builtin_vbeprobe,
+ 0
+ };
+
diff --git a/sys-boot/grub/files/grub-0.97-uuid_doc.patch b/sys-boot/grub/files/grub-0.97-uuid_doc.patch
new file mode 100644
index 00000000..06bfbdeb
--- /dev/null
+++ b/sys-boot/grub/files/grub-0.97-uuid_doc.patch
@@ -0,0 +1,38 @@
+--- grub-0.97.orig/docs/grub.texi 2008-07-17 11:07:25.000000000 +0100
++++ grub-0.97/docs/grub.texi 2008-07-17 10:57:41.000000000 +0100
+@@ -2707,6 +2707,7 @@
+ * testload:: Load a file for testing a filesystem
+ * testvbe:: Test VESA BIOS EXTENSION
+ * uppermem:: Set the upper memory size
++* uuid:: Set GRUB's root device using UUID
+ * vbeprobe:: Probe VESA BIOS EXTENSION
+ @end menu
+
+@@ -3266,6 +3267,27 @@
+ also be used for debugging purposes to lie to an OS.
+ @end deffn
+
++@node uuid
++@subsection uuid
++
++@deffn Command uuid [UUID]
++Set the current @dfn{root device} to the device with the universally
++unique identifier @var{UUID}, then attempt to mount it. This is
++equivalent to the @ref{root} command, but allows one to select a
++filesystem by UUID rather than by device.
++
++The command recognises ext2, ext3, fat, hfs, jfs, ntfs, ocfs, reiserfs
++and xfs filesystems.
++
++@strong{Note:} grub detects and recognises fat UUIDs in lower case
++whereas examining /dev/disk/by-uuid on Linux will report fat UUIDs
++in upper case.
++
++By not specifying @var{UUID}, the command will scan partitions on
++attached devices and will display the device, partition type and
++UUID for each recognised filesystem.
++@end deffn
++
+
+ @node vbeprobe
+ @subsection vbeprobe
diff --git a/sys-boot/grub/files/grub-1.96-genkernel.patch b/sys-boot/grub/files/grub-1.96-genkernel.patch
new file mode 100644
index 00000000..e06f3835
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.96-genkernel.patch
@@ -0,0 +1,19 @@
+--- util/grub.d/10_linux.in
++++ util/grub.d/10_linux.in
+@@ -61,7 +61,7 @@
+ EOF
+ }
+
+-list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do
++list=`for i in /boot/kernel-* /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do
+ if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
+ done`
+
+@@ -78,6 +78,7 @@
+ initrd=
+ for i in "initrd.img-${version}" "initrd-${version}.img" \
+ "initrd-${version}" "initrd.img-${alt_version}" \
++ "initramfs-genkernel-${version}" "initramfs-genkernel-${alt_version}" \
+ "initrd-${alt_version}.img" "initrd-${alt_version}"; do
+ if test -e "${dirname}/${i}" ; then
+ initrd="$i"
diff --git a/sys-boot/grub/files/grub-1.97-genkernel.patch b/sys-boot/grub/files/grub-1.97-genkernel.patch
new file mode 100644
index 00000000..ae64ae45
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.97-genkernel.patch
@@ -0,0 +1,28 @@
+--- grub-1.97.2.orig/util/grub.d/10_linux.in
++++ grub-1.97.2/util/grub.d/10_linux.in
+@@ -49,7 +49,7 @@ menuentry "$1" {
+ EOF
+ prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/"
+ cat << EOF
+- linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro $2
++ linux ${rel_dirname}/${basename} ro $2
+ EOF
+ if test -n "${initrd}" ; then
+ cat << EOF
+@@ -61,7 +61,7 @@ EOF
+ EOF
+ }
+
+-list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do
++list=`for i in /boot/kernel-* /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do
+ if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
+ done`
+
+@@ -78,6 +78,7 @@ while [ "x$list" != "x" ] ; do
+ initrd=
+ for i in "initrd.img-${version}" "initrd-${version}.img" \
+ "initrd-${version}" "initrd.img-${alt_version}" \
++ "initramfs-genkernel-${version}" "initramfs-genkernel-${alt_version}" \
+ "initrd-${alt_version}.img" "initrd-${alt_version}"; do
+ if test -e "${dirname}/${i}" ; then
+ initrd="$i"
diff --git a/sys-boot/grub/files/grub-1.97-hostdisk.patch b/sys-boot/grub/files/grub-1.97-hostdisk.patch
new file mode 100644
index 00000000..6eb7fe48
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.97-hostdisk.patch
@@ -0,0 +1,60 @@
+--- util/hostdisk.c 2010-01-25 17:04:22 +0000
++++ util/hostdisk.c 2010-01-31 11:52:27 +0000
+@@ -336,7 +336,8 @@
+ char dev[PATH_MAX];
+
+ strcpy (dev, map[disk->id].device);
+- if (disk->partition && strncmp (map[disk->id].device, "/dev/", 5) == 0)
++ if (disk->partition && sector >= disk->partition->start
++ && strncmp (map[disk->id].device, "/dev/", 5) == 0)
+ is_partition = linux_find_partition (dev, disk->partition->start);
+
+ /* Open the partition. */
+@@ -490,6 +491,23 @@
+ {
+ int fd;
+
++ /* Split pre-partition and partition reads. */
++ if (disk->partition && sector < disk->partition->start
++ && sector + size > disk->partition->start)
++ {
++ grub_err_t err;
++ err = grub_util_biosdisk_read (disk, sector,
++ disk->partition->start - sector,
++ buf);
++ if (err)
++ return err;
++
++ return grub_util_biosdisk_read (disk, disk->partition->start,
++ size - (disk->partition->start - sector),
++ buf + ((disk->partition->start - sector)
++ << GRUB_DISK_SECTOR_BITS));
++ }
++
+ fd = open_device (disk, sector, O_RDONLY);
+ if (fd < 0)
+ return grub_errno;
+@@ -527,6 +545,23 @@
+ {
+ int fd;
+
++ /* Split pre-partition and partition writes. */
++ if (disk->partition && sector < disk->partition->start
++ && sector + size > disk->partition->start)
++ {
++ grub_err_t err;
++ err = grub_util_biosdisk_write (disk, sector,
++ disk->partition->start - sector,
++ buf);
++ if (err)
++ return err;
++
++ return grub_util_biosdisk_write (disk, disk->partition->start,
++ size - (disk->partition->start - sector),
++ buf + ((disk->partition->start - sector)
++ << GRUB_DISK_SECTOR_BITS));
++ }
++
+ fd = open_device (disk, sector, O_WRONLY);
+ if (fd < 0)
+ return grub_errno;
diff --git a/sys-boot/grub/files/grub-1.97-vga-deprecated.patch b/sys-boot/grub/files/grub-1.97-vga-deprecated.patch
new file mode 100644
index 00000000..16b2ef7e
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.97-vga-deprecated.patch
@@ -0,0 +1,12 @@
+--- grub-1.97.2.orig/util/grub.d/00_header.in
++++ grub-1.97.2/util/grub.d/00_header.in
+@@ -76,6 +76,9 @@ case x${GRUB_TERMINAL_OUTPUT} in
+ cat << EOF
+ if loadfont `make_system_path_relative_to_its_root ${GRUB_FONT_PATH}` ; then
+ set gfxmode=${GRUB_GFXMODE}
++ # vga= is deprecated, grub2 handles this just fine
++ # making grub2 res == linux fb res
++ set gfxpayload=keep
+ insmod gfxterm
+ insmod ${GRUB_VIDEO_BACKEND}
+ if terminal_output gfxterm ; then true ; else
diff --git a/sys-boot/grub/files/grub-1.97-wallpaper-settings-support.patch b/sys-boot/grub/files/grub-1.97-wallpaper-settings-support.patch
new file mode 100644
index 00000000..3bf4ffa8
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.97-wallpaper-settings-support.patch
@@ -0,0 +1,15 @@
+diff -Nurp grub-1.97.2.orig/util/grub-mkconfig.in grub-1.97.2/util/grub-mkconfig.in
+--- grub-1.97.2.orig/util/grub-mkconfig.in 2010-01-24 19:13:30.000000000 +0100
++++ grub-1.97.2/util/grub-mkconfig.in 2010-02-17 21:01:08.762963506 +0100
+@@ -224,7 +224,10 @@ export GRUB_DEFAULT \
+ GRUB_DISABLE_LINUX_UUID \
+ GRUB_DISABLE_LINUX_RECOVERY \
+ GRUB_GFXMODE \
+- GRUB_DISABLE_OS_PROBER
++ GRUB_DISABLE_OS_PROBER \
++ GRUB_WALLPAPER \
++ GRUB_COLOR_NORMAL \
++ GRUB_COLOR_HIGHLIGHT
+
+ if test "x${grub_cfg}" != "x"; then
+ rm -f ${grub_cfg}.new
diff --git a/sys-boot/grub/files/grub-1.98-add-legacy-rootfs-detection.patch b/sys-boot/grub/files/grub-1.98-add-legacy-rootfs-detection.patch
new file mode 100644
index 00000000..1fadd461
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.98-add-legacy-rootfs-detection.patch
@@ -0,0 +1,83 @@
+diff -ur grub2-orig/util/grub-mkconfig.in grub2-new/util/grub-mkconfig.in
+--- grub2-orig/util/grub-mkconfig.in 2010-01-28 15:01:46.746567396 +0100
++++ grub2-new/util/grub-mkconfig.in 2010-01-28 15:38:48.560587115 +0100
+@@ -119,8 +119,8 @@
+ fi
+
+ # Device containing our userland. Typically used for root= parameter.
+-GRUB_DEVICE="`${grub_probe} --target=device /`"
+-GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true
++GRUB_DEVICE="`${grub_probe} --target=device /`" || GRUB_DEVICE="`legacy_find_root_device`"
++GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || GRUB_DEVICE_UUID="`legacy_convert_to_uuid ${GRUB_DEVICE}`"
+
+ # Device containing our /boot partition. Usually the same as GRUB_DEVICE.
+ GRUB_DEVICE_BOOT="`${grub_probe} --target=device /boot`"
+diff -ur grub2-orig/util/grub-mkconfig_lib.in grub2-new/util/grub-mkconfig_lib.in
+--- grub2-orig/util/grub-mkconfig_lib.in 2010-01-28 15:01:46.740383831 +0100
++++ grub2-new/util/grub-mkconfig_lib.in 2010-01-28 15:38:10.474013430 +0100
+@@ -188,3 +188,65 @@
+ done
+ echo "$a"
+ }
++
++legacy_find_root_device ()
++{
++ mount_point=$1
++
++ # Autodetect current root device
++ device=
++ if [ -f /etc/fstab ] ; then
++ device="`awk '$1!~/^#/{
++ if ($2 ~ "^/+$") { $2 = "/"; } else { sub("/*$", "", $2); }
++ if ($2 == "'"$mount_point"'"){
++ print $1;
++ }
++ }' /etc/fstab | tail -n 1`"
++ fi
++
++ if [ -n "$device" ] ; then
++ case "$device" in
++ LABEL=* | UUID=*)
++ device="`findfs $device`"
++ device="`readlink -f "$device"`"
++ ;;
++ *)
++ device=`readlink -f "$device"`
++ ;;
++ esac
++ fi
++
++ echo $device
++}
++
++legacy_convert_to_uuid()
++{
++ echo "Cannot determine uuid of root device. Trying legacy probe method" >&2
++ local dev; dev="$1"
++
++ convert=false
++ case "$dev" in
++ /dev/disk/*)
++ ;;
++ /dev/mapper/*)
++ ;;
++ /dev/evms/[hs]d[a-z][0-9]*)
++ convert=:
++ ;;
++ /dev/evms/*)
++ ;;
++ /dev/md[0-9]*)
++ ;;
++ /dev/*)
++ convert=:
++ ;;
++ esac
++ if $convert; then
++ if [ -b "$dev" ]; then
++ uuid="`blkid -o value -s UUID "$dev" || true`"
++ fi
++ fi
++
++ echo "$uuid"
++}
++
diff --git a/sys-boot/grub/files/grub-1.98-follow-dev-mapper-symlinks.patch b/sys-boot/grub/files/grub-1.98-follow-dev-mapper-symlinks.patch
new file mode 100644
index 00000000..aead475c
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.98-follow-dev-mapper-symlinks.patch
@@ -0,0 +1,25 @@
+--- a/util/getroot.c 2010-03-06 20:51:37.000000000 +0000
++++ b/util/getroot.c 2010-05-28 19:21:57.592307313 +0100
+@@ -222,9 +222,20 @@ find_root_device (const char *dir, dev_t
+ /* Ignore any error. */
+ continue;
+
+- if (S_ISLNK (st.st_mode))
+- /* Don't follow symbolic links. */
++ if (S_ISLNK (st.st_mode)) {
++#ifdef __linux__
++ if (strcmp (dir, "mapper") == 0) {
++ /* Follow symbolic links under /dev/mapper/; the canonical name
++ may be something like /dev/dm-0, but the names under
++ /dev/mapper/ are more human-readable and so we prefer them if
++ we can get them. */
++ if (stat (ent->d_name, &st) < 0)
++ continue;
++ } else
++#endif /* __linux__ */
++ /* Don't follow other symbolic links. */
+ continue;
++ }
+
+ if (S_ISDIR (st.st_mode))
+ {
diff --git a/sys-boot/grub/files/grub-1.98-genkernel-initramfs-single.patch b/sys-boot/grub/files/grub-1.98-genkernel-initramfs-single.patch
new file mode 100644
index 00000000..4aa6ab99
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.98-genkernel-initramfs-single.patch
@@ -0,0 +1,11 @@
+--- grub-1.99.orig/util/grub.d/10_linux.in
++++ grub-1.99/util/grub.d/10_linux.in
+@@ -192,7 +192,7 @@ while [ "x$list" != "x" ] ; do
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+ if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+ linux_entry "${OS}" "${version}" true \
+- "single ${GRUB_CMDLINE_LINUX}"
++ "single init_opts=single ${GRUB_CMDLINE_LINUX/splash=silent/splash=verbose}"
+ fi
+
+ list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
diff --git a/sys-boot/grub/files/grub-1.98-genkernel.patch b/sys-boot/grub/files/grub-1.98-genkernel.patch
new file mode 100644
index 00000000..8fbf39ab
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.98-genkernel.patch
@@ -0,0 +1,28 @@
+--- grub-1.98.orig/util/grub.d/10_linux.in 2010-03-06 21:51:37.000000000 +0100
++++ grub-1.98/util/grub.d/10_linux.in 2010-04-12 11:25:51.982167950 +0200
+@@ -84,7 +84,7 @@ EOF
+ printf '%s\n' "${prepare_boot_cache}"
+ cat << EOF
+ echo $(printf "$(gettext "Loading Linux %s ...")" ${version})
+- linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
++ linux ${rel_dirname}/${basename} ro ${args}
+ EOF
+ if test -n "${initrd}" ; then
+ cat << EOF
+@@ -97,7 +97,7 @@ EOF
+ EOF
+ }
+
+-list=`for i in /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do
++list=`for i in /boot/kernel-* /boot/vmlinu[xz]-* /vmlinu[xz]-* ; do
+ if grub_file_is_not_garbage "$i" ; then echo -n "$i " ; fi
+ done`
+ prepare_boot_cache=
+@@ -114,6 +114,7 @@ while [ "x$list" != "x" ] ; do
+
+ initrd=
+ for i in "initrd.img-${version}" "initrd-${version}.img" \
++ "initramfs-genkernel-${version}" "initramfs-genkernel-${alt_version}" \
+ "initrd-${version}" "initrd.img-${alt_version}" \
+ "initrd-${alt_version}.img" "initrd-${alt_version}"; do
+ if test -e "${dirname}/${i}" ; then
diff --git a/sys-boot/grub/files/grub-1.98-wallpaper-settings-support.patch b/sys-boot/grub/files/grub-1.98-wallpaper-settings-support.patch
new file mode 100644
index 00000000..f34f393b
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.98-wallpaper-settings-support.patch
@@ -0,0 +1,15 @@
+diff -Nurp grub-1.98.orig/util/grub-mkconfig.in grub-1.98/util/grub-mkconfig.in
+--- grub-1.98.orig/util/grub-mkconfig.in 2010-03-06 21:51:37.000000000 +0100
++++ grub-1.98/util/grub-mkconfig.in 2010-04-12 11:29:28.396075050 +0200
+@@ -224,7 +224,10 @@ export GRUB_DEFAULT \
+ GRUB_GFXPAYLOAD_LINUX \
+ GRUB_DISABLE_OS_PROBER \
+ GRUB_INIT_TUNE \
+- GRUB_SAVEDEFAULT
++ GRUB_SAVEDEFAULT \
++ GRUB_WALLPAPER \
++ GRUB_COLOR_NORMAL \
++ GRUB_COLOR_HIGHLIGHT
+
+ if test "x${grub_cfg}" != "x"; then
+ rm -f ${grub_cfg}.new
diff --git a/sys-boot/grub/files/grub-1.99-disable-floppies.patch b/sys-boot/grub/files/grub-1.99-disable-floppies.patch
new file mode 100644
index 00000000..6bb28626
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.99-disable-floppies.patch
@@ -0,0 +1,28 @@
+
+Author: Robert Millan
+
+An ugly kludge. Should this be merged upstream?
+
+Index: b/grub-core/kern/emu/hostdisk.c
+===================================================================
+--- a/grub-core/kern/emu/hostdisk.c
++++ b/grub-core/kern/emu/hostdisk.c
+@@ -1077,6 +1077,18 @@
+ continue;
+ }
+
++ if (! strncmp (p, "/dev/fd", sizeof ("/dev/fd") - 1))
++ {
++ char *q = p + sizeof ("/dev/fd") - 1;
++ if (*q >= '0' && *q <= '9')
++ {
++ free (map[drive].drive);
++ map[drive].drive = NULL;
++ grub_util_info ("`%s' looks like a floppy drive, skipping", p);
++ continue;
++ }
++ }
++
+ #ifdef __linux__
+ /* On Linux, the devfs uses symbolic links horribly, and that
+ confuses the interface very much, so use realpath to expand
diff --git a/sys-boot/grub/files/grub-1.99-genkernel.patch b/sys-boot/grub/files/grub-1.99-genkernel.patch
new file mode 100644
index 00000000..433e583d
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.99-genkernel.patch
@@ -0,0 +1,11 @@
+--- grub-1.99.orig/util/grub.d/10_linux.in
++++ grub-1.99/util/grub.d/10_linux.in
+@@ -116,7 +116,7 @@ EOF
+ message="$(gettext_printf "Loading Linux %s ..." ${version})"
+ cat << EOF
+ echo '$message'
+- linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
++ linux ${rel_dirname}/${basename} ro ${args}
+ EOF
+ if test -n "${initrd}" ; then
+ message="$(gettext_printf "Loading initial ramdisk ...")"
diff --git a/sys-boot/grub/files/grub-1.99-vga-deprecated-not-yet.patch b/sys-boot/grub/files/grub-1.99-vga-deprecated-not-yet.patch
new file mode 100644
index 00000000..d850c178
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.99-vga-deprecated-not-yet.patch
@@ -0,0 +1,14 @@
+diff -Nurp grub-1.99.orig/grub-core/loader/i386/linux.c grub-1.99/grub-core/loader/i386/linux.c
+--- grub-1.99.orig/grub-core/loader/i386/linux.c 2011-06-11 10:49:46.975998646 +0200
++++ grub-1.99/grub-core/loader/i386/linux.c 2011-06-11 11:52:14.419996325 +0200
+@@ -821,10 +821,6 @@ grub_cmd_linux (grub_command_t cmd __att
+ if (! buf)
+ goto fail;
+
+- grub_printf ("%s is deprecated. "
+- "Use set gfxpayload=%s before "
+- "linux command instead.\n",
+- argv[i], buf);
+ err = grub_env_set ("gfxpayload", buf);
+ grub_free (buf);
+ if (err)
diff --git a/sys-boot/grub/files/grub-1.99-vga-deprecated.patch b/sys-boot/grub/files/grub-1.99-vga-deprecated.patch
new file mode 100644
index 00000000..20ea6d89
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.99-vga-deprecated.patch
@@ -0,0 +1,12 @@
+--- grub-1.99~rc1.orig/util/grub.d/00_header.in
++++ grub-1.99~rc1/util/grub.d/00_header.in
+@@ -131,6 +131,9 @@ if [ "x$gfxterm" = x1 ]; then
+ if loadfont `make_system_path_relative_to_its_root "${GRUB_FONT_PATH}"` ; then
+ set gfxmode=${GRUB_GFXMODE}
+ load_video
++ # vga= is deprecated, grub2 handles this just fine
++ # making grub2 res == linux fb res
++ set gfxpayload=keep
+ insmod gfxterm
+ fi
+ EOF
diff --git a/sys-boot/grub/files/grub-1.99-wallpaper-settings-support.patch b/sys-boot/grub/files/grub-1.99-wallpaper-settings-support.patch
new file mode 100644
index 00000000..6f3f3749
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.99-wallpaper-settings-support.patch
@@ -0,0 +1,15 @@
+diff -Nurp grub-1.99~rc1.orig/util/grub-mkconfig.in grub-1.99~rc1/util/grub-mkconfig.in
+--- grub-1.99~rc1.orig/util/grub-mkconfig.in 2010-12-01 15:45:43.000000000 +0100
++++ grub-1.99~rc1/util/grub-mkconfig.in 2011-06-08 14:37:02.209761705 +0200
+@@ -254,7 +254,10 @@ export GRUB_DEFAULT \
+ GRUB_DISABLE_OS_PROBER \
+ GRUB_INIT_TUNE \
+ GRUB_SAVEDEFAULT \
+- GRUB_BADRAM
++ GRUB_BADRAM \
++ GRUB_WALLPAPER \
++ GRUB_COLOR_NORMAL \
++ GRUB_COLOR_HIGHLIGHT
+
+ if test "x${grub_cfg}" != "x"; then
+ rm -f ${grub_cfg}.new
diff --git a/sys-boot/grub/files/grub-1.99-workaround-raid-bios-bug.patch b/sys-boot/grub/files/grub-1.99-workaround-raid-bios-bug.patch
new file mode 100644
index 00000000..391c40ac
--- /dev/null
+++ b/sys-boot/grub/files/grub-1.99-workaround-raid-bios-bug.patch
@@ -0,0 +1,17 @@
+diff -Nurp grub-1.99.orig/grub-core/disk/raid.c grub-1.99/grub-core/disk/raid.c
+--- grub-1.99.orig/grub-core/disk/raid.c 2011-04-18 23:16:16.000000000 +0200
++++ grub-1.99/grub-core/disk/raid.c 2011-06-11 10:48:16.606998702 +0200
+@@ -562,13 +562,6 @@ insert_array (grub_disk_t disk, struct g
+ "superfluous RAID member (%d found)",
+ array->total_devs);
+
+- if (array->members[new_array->index].device != NULL)
+- /* We found multiple devices with the same number. Again,
+- this shouldn't happen. */
+- return grub_error (GRUB_ERR_BAD_DEVICE,
+- "found two disks with the index %d for RAID %s",
+- new_array->index, array->name);
+-
+ if (new_array->disk_size < array->disk_size)
+ array->disk_size = new_array->disk_size;
+ break;
diff --git a/sys-boot/grub/files/grub-2.00-20_linux_xen.patch b/sys-boot/grub/files/grub-2.00-20_linux_xen.patch
new file mode 100644
index 00000000..c83f0b04
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-20_linux_xen.patch
@@ -0,0 +1,14 @@
+Fix detection of genkernel initramfs for xen
+
+https://bugs.gentoo.org/show_bug.cgi?id=463992
+
+--- a/util/grub.d/20_linux_xen.in
++++ b/util/grub.d/20_linux_xen.in
+@@ -174,6 +174,7 @@
+
+ title_correction_code=
+
++machine=`uname -m`
+ case "$machine" in
+ i?86) GENKERNEL_ARCH="x86" ;;
+ mips|mips64) GENKERNEL_ARCH="mips" ;;
diff --git a/sys-boot/grub/files/grub-2.00-compression.patch b/sys-boot/grub/files/grub-2.00-compression.patch
new file mode 100644
index 00000000..58bc1f93
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-compression.patch
@@ -0,0 +1,84 @@
+https://bugs.gentoo.org/show_bug.cgi?id=424527
+https://savannah.gnu.org/bugs/index.php?36770
+
+=== modified file 'grub-core/lib/xzembed/xz_dec_stream.c'
+--- grub-core/lib/xzembed/xz_dec_stream.c 2012-02-29 13:56:51 +0000
++++ grub-core/lib/xzembed/xz_dec_stream.c 2012-07-22 14:27:03 +0000
+@@ -403,18 +403,25 @@
+ }
+ #endif
+
+- do {
++ if (b->in_pos == b->in_size)
++ return XZ_OK;
++
++ if (!crc32 && s->hash_size == 0)
++ s->pos += 8;
++
++ while (s->pos < (crc32 ? 32 : s->hash_size * 8)) {
+ if (b->in_pos == b->in_size)
+ return XZ_OK;
+
+ #ifndef GRUB_EMBED_DECOMPRESSOR
+- if (hash && s->hash_value[s->pos / 8] != b->in[b->in_pos++])
++ if (hash && s->hash_value[s->pos / 8] != b->in[b->in_pos])
+ return XZ_DATA_ERROR;
+ #endif
++ b->in_pos++;
+
+ s->pos += 8;
+
+- } while (s->pos < (crc32 ? 32 : s->hash_size * 8));
++ }
+
+ #ifndef GRUB_EMBED_DECOMPRESSOR
+ if (s->hash)
+@@ -529,8 +536,6 @@
+ s->hash->init(s->index.hash.hash_context);
+ s->hash->init(s->block.hash.hash_context);
+ }
+- if (!s->hash)
+- return XZ_OPTIONS_ERROR;
+ #endif
+ }
+ else
+
+=== modified file 'grub-core/normal/autofs.c'
+--- grub-core/normal/autofs.c 2012-05-01 13:26:36 +0000
++++ grub-core/normal/autofs.c 2012-07-22 14:23:46 +0000
+@@ -32,11 +32,21 @@
+ autoload_fs_module (void)
+ {
+ grub_named_list_t p;
++ int ret = 0;
++ grub_file_filter_t grub_file_filters_was[GRUB_FILE_FILTER_MAX];
++
++ grub_memcpy (grub_file_filters_was, grub_file_filters_enabled,
++ sizeof (grub_file_filters_enabled));
++ grub_memcpy (grub_file_filters_enabled, grub_file_filters_all,
++ sizeof (grub_file_filters_enabled));
+
+ while ((p = fs_module_list) != NULL)
+ {
+ if (! grub_dl_get (p->name) && grub_dl_load (p->name))
+- return 1;
++ {
++ ret = 1;
++ break;
++ }
+
+ if (grub_errno)
+ grub_print_error ();
+@@ -46,7 +56,10 @@
+ grub_free (p);
+ }
+
+- return 0;
++ grub_memcpy (grub_file_filters_enabled, grub_file_filters_was,
++ sizeof (grub_file_filters_enabled));
++
++ return ret;
+ }
+
+ /* Read the file fs.lst for auto-loading. */
+
diff --git a/sys-boot/grub/files/grub-2.00-config-quoting.patch b/sys-boot/grub/files/grub-2.00-config-quoting.patch
new file mode 100644
index 00000000..3b031c62
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-config-quoting.patch
@@ -0,0 +1,113 @@
+https://bugs.gentoo.org/show_bug.cgi?id=426364
+https://savannah.gnu.org/bugs/index.php?36839
+--- util/grub-mkconfig_lib.in
++++ util/grub-mkconfig_lib.in
+@@ -255,19 +255,19 @@
+ echo "$version_find_latest_a"
+ }
+
+-# One layer of quotation is eaten by "", the second by sed, and the third by
+-# printf; so this turns ' into \'. Note that you must use the output of
++# One layer of quotation is eaten by "" and the second by
++# sed; so this turns ' into \'. Note that you must use the output of
+ # this function in a printf format string.
+
+ grub_quote () {
+- sed "s/'/'\\\\\\\\''/g"
++ sed "s/'/'\\\\''/g"
+ }
+
+ gettext_quoted () {
+- gettext "$@" | sed "s/'/'\\\\\\\\''/g"
++ gettext "$@" | grub_quote
+ }
+
+-# Run the first argument through gettext_quoted, and then pass that and all
++# Run the first argument through gettext, and then pass that and all
+ # remaining arguments to printf. This is a useful abbreviation and tends to
+ # be easier to type.
+ gettext_printf () {
+
+=== modified file 'util/grub.d/10_hurd.in'
+--- util/grub.d/10_hurd.in
++++ util/grub.d/10_hurd.in
+@@ -117,7 +117,7 @@
+ opts=
+ fi
+ sed "s/^/$submenu_indentation/" << EOF
+- echo '$message'
++ echo '$(echo "$message" | grub_quote)'
+ multiboot ${kernel} root=device:${GRUB_DEVICE#/dev/} $opts ${GRUB_CMDLINE_GNUMACH}
+ EOF
+
+@@ -133,7 +133,7 @@
+ fi
+
+ sed "s/^/$submenu_indentation/" << EOF
+- echo '$message'
++ echo '$(echo "$message" | grub_quote)'
+ module /hurd/${hurd_fs}.static ${hurd_fs} $opts \\
+ --multiboot-command-line='\${kernel-command-line}' \\
+ --host-priv-port='\${host-port}' \\
+--- util/grub.d/10_illumos.in
++++ util/grub.d/10_illumos.in
+@@ -46,6 +46,7 @@
+ ISADIR=
+ fi
+ zfs-bootfs $($grub_mkrelpath /) ZFS_BOOTFS
++ echo '$(echo "$message" | grub_quote)'
+ multiboot $($grub_mkrelpath /platform/i86pc/kernel)/\$ISADIR/unix /platform/i86pc/kernel/\$ISADIR/unix -B \$ZFS_BOOTFS,console=text
+ module $($grub_mkrelpath /platform/i86pc)/\$ISADIR/boot_archive /platform/i86pc/\$ISADIR/boot_archive
+ }
+--- util/grub.d/10_kfreebsd.in
++++ util/grub.d/10_kfreebsd.in
+@@ -100,7 +100,7 @@
+ printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+ message="$(gettext_printf "Loading kernel of FreeBSD %s ..." ${version})"
+ sed "s/^/$submenu_indentation/" << EOF
+- echo '$message'
++ echo '$(echo "$message" | grub_quote)'
+ kfreebsd ${rel_dirname}/${basename} ${args}
+ EOF
+
+--- util/grub.d/10_linux.in
++++ util/grub.d/10_linux.in
+@@ -134,14 +134,14 @@
+ fi
+ message="$(gettext_printf "Loading Linux %s ..." ${version})"
+ sed "s/^/$submenu_indentation/" << EOF
+- echo '$message'
++ echo '$(echo "$message" | grub_quote)'
+ linux ${rel_dirname}/${basename} root=${linux_root_device_thisversion} ro ${args}
+ EOF
+ if test -n "${initrd}" ; then
+ # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+ message="$(gettext_printf "Loading initial ramdisk ...")"
+ sed "s/^/$submenu_indentation/" << EOF
+- echo '$message'
++ echo '$(echo "$message" | grub_quote)'
+ initrd ${rel_dirname}/${initrd}
+ EOF
+ fi
+--- util/grub.d/20_linux_xen.in
++++ util/grub.d/20_linux_xen.in
+@@ -120,16 +120,16 @@
+ xmessage="$(gettext_printf "Loading Xen %s ..." ${xen_version})"
+ lmessage="$(gettext_printf "Loading Linux %s ..." ${version})"
+ sed "s/^/$submenu_indentation/" << EOF
+- echo '$xmessage'
++ echo '$(echo "$xmessage" | grub_quote)'
+ multiboot ${rel_xen_dirname}/${xen_basename} placeholder ${xen_args}
+- echo '$lmessage'
++ echo '$(echo "$lmessage" | grub_quote)'
+ module ${rel_dirname}/${basename} placeholder root=${linux_root_device_thisversion} ro ${args}
+ EOF
+ if test -n "${initrd}" ; then
+ # TRANSLATORS: ramdisk isn't identifier. Should be translated.
+ message="$(gettext_printf "Loading initial ramdisk ...")"
+ sed "s/^/$submenu_indentation/" << EOF
+- echo '$message'
++ echo '$(echo "$message" | grub_quote)'
+ module ${rel_dirname}/${initrd}
+ EOF
+ fi
diff --git a/sys-boot/grub/files/grub-2.00-dmraid.patch b/sys-boot/grub/files/grub-2.00-dmraid.patch
new file mode 100644
index 00000000..c39267ae
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-dmraid.patch
@@ -0,0 +1,28 @@
+Fix DMRAID partition handling
+
+https://bugs.gentoo.org/show_bug.cgi?id=430748
+https://savannah.gnu.org/bugs/?37073
+http://bzr.savannah.gnu.org/lh/grub/trunk/grub/revision/4858
+
+=== modified file 'util/getroot.c'
+--- util/getroot.c 2013-04-12 20:37:59 +0000
++++ util/getroot.c 2013-04-15 06:37:13 +0000
+@@ -1956,6 +1956,7 @@
+ grub_util_info ("dm_tree_find_node failed");
+ goto devmapper_out;
+ }
++ reiterate:
+ node_uuid = dm_tree_node_get_uuid (node);
+ if (! node_uuid)
+ {
+@@ -2030,6 +2031,9 @@
+ goto devmapper_out;
+ }
+ mapper_name = child_name;
++ *is_part = 1;
++ node = child;
++ goto reiterate;
+
+ devmapper_out:
+ if (! mapper_name && node)
+
diff --git a/sys-boot/grub/files/grub-2.00-freebsd.patch b/sys-boot/grub/files/grub-2.00-freebsd.patch
new file mode 100644
index 00000000..bcfbf263
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-freebsd.patch
@@ -0,0 +1,382 @@
+Taken from
+http://bzr.savannah.gnu.org/lh/grub/trunk/grub/revision/4556
+http://bzr.savannah.gnu.org/lh/grub/trunk/grub/revision/4584
+http://bzr.savannah.gnu.org/lh/grub/trunk/grub/revision/4624
+http://bzr.savannah.gnu.org/lh/grub/trunk/grub/revision/4625
+
+diff -Nur grub-2.00.orig/grub-core/loader/i386/bsd.c grub-2.00/grub-core/loader/i386/bsd.c
+--- grub-2.00.orig/grub-core/loader/i386/bsd.c 2012-06-07 22:06:00.000000000 +0900
++++ grub-2.00/grub-core/loader/i386/bsd.c 2013-01-04 19:50:55.000000000 +0900
+@@ -1309,7 +1309,7 @@
+ && phdr->p_type != PT_DYNAMIC)
+ return 0;
+
+- paddr = phdr->p_paddr & 0xFFFFFF;
++ paddr = phdr->p_paddr & 0xFFFFFFF;
+
+ if (paddr < kern_start)
+ kern_start = paddr;
+@@ -1333,7 +1333,7 @@
+ }
+
+ *do_load = 1;
+- phdr->p_paddr &= 0xFFFFFF;
++ phdr->p_paddr &= 0xFFFFFFF;
+ paddr = phdr->p_paddr;
+
+ *addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src);
+@@ -1351,7 +1351,7 @@
+ && phdr->p_type != PT_DYNAMIC)
+ return 0;
+
+- paddr = phdr->p_paddr & 0xffffff;
++ paddr = phdr->p_paddr & 0xfffffff;
+
+ if (paddr < kern_start)
+ kern_start = paddr;
+@@ -1375,7 +1375,7 @@
+ }
+
+ *do_load = 1;
+- paddr = phdr->p_paddr & 0xffffff;
++ paddr = phdr->p_paddr & 0xfffffff;
+
+ *addr = (grub_addr_t) (paddr - kern_start + (grub_uint8_t *) kern_chunk_src);
+
+@@ -1394,7 +1394,7 @@
+ {
+ grub_relocator_chunk_t ch;
+
+- entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFF;
++ entry = elf->ehdr.ehdr32.e_entry & 0xFFFFFFF;
+ err = grub_elf32_phdr_iterate (elf, filename,
+ grub_bsd_elf32_size_hook, NULL);
+ if (err)
+diff -Nur grub-2.00.orig/util/grub-mkconfig_lib.in grub-2.00/util/grub-mkconfig_lib.in
+--- grub-2.00.orig/util/grub-mkconfig_lib.in 2012-06-28 00:27:53.000000000 +0900
++++ grub-2.00/util/grub-mkconfig_lib.in 2013-01-04 19:50:55.000000000 +0900
+@@ -349,3 +349,10 @@
+ cat
+ fi
+ }
++
++grub_tab=" "
++
++grub_add_tab () {
++ sed -e "s/^/$grub_tab/"
++}
++
+diff -Nur grub-2.00.orig/util/grub.d/10_hurd.in grub-2.00/util/grub.d/10_hurd.in
+--- grub-2.00.orig/util/grub.d/10_hurd.in 2012-03-05 05:10:04.000000000 +0900
++++ grub-2.00/util/grub.d/10_hurd.in 2013-01-04 19:50:55.000000000 +0900
+@@ -108,7 +108,7 @@
+ EOF
+ fi
+
+- prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | sed -e "s/^/\t/"|sed "s/^/$submenu_indentation/"
++ prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | grub_add_tab|sed "s/^/$submenu_indentation/"
+ message="$(gettext_printf "Loading GNU Mach ...")"
+
+ if [ x$type = xrecovery ] ; then
+@@ -122,9 +122,9 @@
+ EOF
+
+ if [ x$type != xrecovery ] ; then
+- save_default_entry | sed -e "s/^/\t/"| sed "s/^/$submenu_indentation/"
++ save_default_entry | grub_add_tab| sed "s/^/$submenu_indentation/"
+ fi
+- prepare_grub_to_access_device "${GRUB_DEVICE}" | sed -e "s/^/\t/"| sed "s/^/$submenu_indentation/"
++ prepare_grub_to_access_device "${GRUB_DEVICE}" | grub_add_tab| sed "s/^/$submenu_indentation/"
+ message="$(gettext_printf "Loading the Hurd ...")"
+ if [ x$type = xrecovery ] ; then
+ opts=
+@@ -158,7 +158,7 @@
+
+ if [ "x$is_first_entry" = xtrue ]; then
+ hurd_entry "$kernel" simple
+- submenu_indentation="\t"
++ submenu_indentation="$grub_tab"
+
+ # TRANSLATORS: %s is replaced with an OS name
+ echo "submenu '$(gettext_printf "Advanced options for %s" "${OS}" | grub_quote)' \$menuentry_id_option 'gnuhurd-advanced-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")' {"
+diff -Nur grub-2.00.orig/util/grub.d/10_illumos.in grub-2.00/util/grub.d/10_illumos.in
+--- grub-2.00.orig/util/grub.d/10_illumos.in 2012-03-05 04:03:38.000000000 +0900
++++ grub-2.00/util/grub.d/10_illumos.in 2013-01-04 19:50:55.000000000 +0900
+@@ -35,8 +35,8 @@
+ esac
+
+ echo "menuentry '$(echo "$OS" | grub_quote)' ${CLASS} \$menuentry_id_option 'illumos-$(grub_get_device_id "${GRUB_DEVICE_BOOT}")' {"
+-save_default_entry | sed -e "s/^/\t/"
+-prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | sed -e "s/^/\t/"
++save_default_entry | grub_add_tab
++prepare_grub_to_access_device "${GRUB_DEVICE_BOOT}" | grub_add_tab
+ message="$(gettext_printf "Loading kernel of Illumos ...")"
+ cat << EOF
+ insmod gzio
+diff -Nur grub-2.00.orig/util/grub.d/10_kfreebsd.in grub-2.00/util/grub.d/10_kfreebsd.in
+--- grub-2.00.orig/util/grub.d/10_kfreebsd.in 2012-03-05 06:02:30.000000000 +0900
++++ grub-2.00/util/grub.d/10_kfreebsd.in 2013-01-04 19:50:55.000000000 +0900
+@@ -54,7 +54,7 @@
+ fi
+
+ if [ -z "${prepare_module_dir_cache}" ]; then
+- prepare_module_dir_cache="$(prepare_grub_to_access_device $(grub-probe -t device "${module_dir}") | sed -e "s/^/\t/")"
++ prepare_module_dir_cache="$(prepare_grub_to_access_device $(${grub_probe} -t device "${module_dir}") | grub_add_tab)"
+ fi
+
+ printf '%s\n' "${prepare_module_dir_cache}"
+@@ -91,10 +91,10 @@
+ echo "menuentry '$(echo "$OS" | grub_quote)' ${CLASS} \$menuentry_id_option 'kfreebsd-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+ fi
+ if [ x$type != xrecovery ] ; then
+- save_default_entry | sed -e "s/^/\t/" | sed "s/^/$submenu_indentation/"
++ save_default_entry | grub_add_tab | sed "s/^/$submenu_indentation/"
+ fi
+ if [ -z "${prepare_boot_cache}" ]; then
+- prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
++ prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)"
+ fi
+
+ printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+@@ -112,7 +112,7 @@
+
+ load_kfreebsd_module acpi true
+
+- for abstraction in dummy $(grub-probe -t abstraction --device ${GRUB_DEVICE}) ; do
++ for abstraction in dummy $(${grub_probe} -t abstraction --device ${GRUB_DEVICE}) ; do
+ case $abstraction in
+ lvm) load_kfreebsd_module geom_linux_lvm false ;;
+ esac
+@@ -122,10 +122,10 @@
+ zfs)
+ load_kfreebsd_module opensolaris false
+
+- ls "${dirname}/zfs/zpool.cache" > /dev/null
++ ls "/boot/zfs/zpool.cache" > /dev/null
+ printf '%s\n' "${prepare_boot_cache}"
+ sed "s/^/$submenu_indentation/" << EOF
+- kfreebsd_module ${rel_dirname}/zfs/zpool.cache type=/boot/zfs/zpool.cache
++ kfreebsd_module $(make_system_path_relative_to_its_root /boot)/zfs/zpool.cache type=/boot/zfs/zpool.cache
+ EOF
+ ;;
+ esac
+@@ -179,7 +179,7 @@
+ case ${GRUB_FS} in
+ zfs)
+ # zpool name
+- kfreebsd_device=$(grub-probe -t fs_label --device ${GRUB_DEVICE})
++ kfreebsd_device=$(${grub_probe} -t fs_label --device ${GRUB_DEVICE})
+ # filesystem name (empty string for the main filesystem)
+ kfreebsd_device="${kfreebsd_device}$(${grub_mkrelpath} / | sed -e "s,/*@$,,")"
+ ;;
+@@ -213,7 +213,7 @@
+
+ if [ "x$is_first_entry" = xtrue ]; then
+ kfreebsd_entry "${OS}" "${version}" simple
+- submenu_indentation="\t"
++ submenu_indentation="$grub_tab"
+
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+diff -Nur grub-2.00.orig/util/grub.d/10_linux.in grub-2.00/util/grub.d/10_linux.in
+--- grub-2.00.orig/util/grub.d/10_linux.in 2012-04-19 06:24:38.000000000 +0900
++++ grub-2.00/util/grub.d/10_linux.in 2013-01-04 19:50:55.000000000 +0900
+@@ -101,7 +101,7 @@
+ echo "menuentry '$(echo "$os" | grub_quote)' ${CLASS} \$menuentry_id_option 'gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+ fi
+ if [ x$type != xrecovery ] ; then
+- save_default_entry | sed -e "s/^/\t/"
++ save_default_entry | grub_add_tab
+ fi
+
+ # Use ELILO's generic "efifb" when it's known to be available.
+@@ -123,12 +123,12 @@
+
+ if [ x$dirname = x/ ]; then
+ if [ -z "${prepare_root_cache}" ]; then
+- prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/\t/")"
++ prepare_root_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab)"
+ fi
+ printf '%s\n' "${prepare_root_cache}" | sed "s/^/$submenu_indentation/"
+ else
+ if [ -z "${prepare_boot_cache}" ]; then
+- prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
++ prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)"
+ fi
+ printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+ fi
+@@ -230,7 +230,7 @@
+ linux_entry "${OS}" "${version}" simple \
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+
+- submenu_indentation="\t"
++ submenu_indentation="$grub_tab"
+
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+diff -Nur grub-2.00.orig/util/grub.d/10_netbsd.in grub-2.00/util/grub.d/10_netbsd.in
+--- grub-2.00.orig/util/grub.d/10_netbsd.in 2012-03-05 04:47:35.000000000 +0900
++++ grub-2.00/util/grub.d/10_netbsd.in 2013-01-04 19:50:55.000000000 +0900
+@@ -77,10 +77,10 @@
+ prepare_grub_to_access_device $(${grub_probe} -t device "${kmodule}") | sed -e 's,^, ,'
+ case "${loader}" in
+ knetbsd)
+- printf "\tknetbsd_module_elf %s\n" "${kmodule_rel}"
++ printf "$grub_tabknetbsd_module_elf %s\n" "${kmodule_rel}"
+ ;;
+ multiboot)
+- printf "\tmodule %s\n" "${kmodule_rel}"
++ printf "$grub_tabmodule %s\n" "${kmodule_rel}"
+ ;;
+ esac
+ }
+@@ -121,11 +121,11 @@
+ printf "%s\n" "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+ case "${loader}" in
+ knetbsd)
+- printf "\tknetbsd %s -r %s %s\n" \
++ printf "$grub_tabknetbsd %s -r %s %s\n" \
+ "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" | sed "s/^/$submenu_indentation/"
+ ;;
+ multiboot)
+- printf "\tmultiboot %s %s root=%s %s\n" \
++ printf "$grub_tabmultiboot %s %s root=%s %s\n" \
+ "${kernel}" "${kernel}" "${kroot_device}" "${GRUB_CMDLINE_NETBSD} ${args}" | sed "s/^/$submenu_indentation/"
+ ;;
+ esac
+@@ -159,7 +159,7 @@
+
+ if [ "x$is_first_entry" = xtrue ]; then
+ netbsd_entry "knetbsd" "$k" simple "${GRUB_CMDLINE_NETBSD_DEFAULT}"
+- submenu_indentation="\t"
++ submenu_indentation="$grub_tab"
+
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+diff -Nur grub-2.00.orig/util/grub.d/10_windows.in grub-2.00/util/grub.d/10_windows.in
+--- grub-2.00.orig/util/grub.d/10_windows.in 2012-03-05 06:11:43.000000000 +0900
++++ grub-2.00/util/grub.d/10_windows.in 2013-01-04 19:50:55.000000000 +0900
+@@ -45,7 +45,7 @@
+ sort | uniq | wc -l`" = 1 || return 1
+
+ # Search 'default=PARTITION'
+- get_os_name_from_boot_ini_part=`sed -n 's,^default=,,p' "$1" | sed 's,\\\\,/,g;s,[ \t\r]*$,,;1q'`
++ get_os_name_from_boot_ini_part=`sed -n 's,^default=,,p' "$1" | sed 's,\\\\,/,g;s,[ $grub_tab\r]*$,,;1q'`
+ test -n "$get_os_name_from_boot_ini_part" || return 1
+
+ # Search 'PARTITION="NAME" ...'
+@@ -87,8 +87,8 @@
+ menuentry '$(echo "$OS" | grub_quote)' \$menuentry_id_option '$osid-$(grub_get_device_id "${dev}")' {
+ EOF
+
+- save_default_entry | sed -e 's,^,\t,'
+- prepare_grub_to_access_device "$dev" | sed 's,^,\t,'
++ save_default_entry | sed -e 's,^,$grub_tab,'
++ prepare_grub_to_access_device "$dev" | sed 's,^,$grub_tab,'
+ test -z "$needmap" || cat <<EOF
+ drivemap -s (hd0) \$root
+ EOF
+diff -Nur grub-2.00.orig/util/grub.d/10_xnu.in grub-2.00/util/grub.d/10_xnu.in
+--- grub-2.00.orig/util/grub.d/10_xnu.in 2012-05-29 19:31:03.000000000 +0900
++++ grub-2.00/util/grub.d/10_xnu.in 2013-01-04 19:50:55.000000000 +0900
+@@ -39,8 +39,8 @@
+ cat << EOF
+ menuentry '$(echo "Darwin/Mac OS X $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${GRUB_DEVICE}")' {
+ EOF
+- save_default_entry | sed -e "s/^/ /"
+- prepare_grub_to_access_device ${GRUB_DEVICE} | sed -e "s/^/ /"
++ save_default_entry | grub_add_tab
++ prepare_grub_to_access_device ${GRUB_DEVICE} | grub_add_tab
+ cat << EOF
+ load_video
+ set do_resume=0
+diff -Nur grub-2.00.orig/util/grub.d/20_linux_xen.in grub-2.00/util/grub.d/20_linux_xen.in
+--- grub-2.00.orig/util/grub.d/20_linux_xen.in 2012-06-04 04:57:42.000000000 +0900
++++ grub-2.00/util/grub.d/20_linux_xen.in 2013-01-04 19:50:55.000000000 +0900
+@@ -110,11 +110,11 @@
+ echo "menuentry '$(echo "$title" | grub_quote)' ${CLASS} \$menuentry_id_option 'xen-gnulinux-simple-$boot_device_id' {" | sed "s/^/$submenu_indentation/"
+ fi
+ if [ x$type != xrecovery ] ; then
+- save_default_entry | sed -e "s/^/\t/" | sed "s/^/$submenu_indentation/"
++ save_default_entry | grub_add_tab | sed "s/^/$submenu_indentation/"
+ fi
+
+ if [ -z "${prepare_boot_cache}" ]; then
+- prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | sed -e "s/^/\t/")"
++ prepare_boot_cache="$(prepare_grub_to_access_device ${GRUB_DEVICE_BOOT} | grub_add_tab)"
+ fi
+ printf '%s\n' "${prepare_boot_cache}" | sed "s/^/$submenu_indentation/"
+ xmessage="$(gettext_printf "Loading Xen %s ..." ${xen_version})"
+@@ -236,7 +236,7 @@
+ linux_entry "${OS}" "${version}" "${xen_version}" simple \
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}" "${GRUB_CMDLINE_XEN} ${GRUB_CMDLINE_XEN_DEFAULT}"
+
+- submenu_indentation="\t\t"
++ submenu_indentation="$grub_tab$grub_tab"
+
+ if [ -z "$boot_device_id" ]; then
+ boot_device_id="$(grub_get_device_id "${GRUB_DEVICE}")"
+diff -Nur grub-2.00.orig/util/grub.d/30_os-prober.in grub-2.00/util/grub.d/30_os-prober.in
+--- grub-2.00.orig/util/grub.d/30_os-prober.in 2012-03-05 05:52:03.000000000 +0900
++++ grub-2.00/util/grub.d/30_os-prober.in 2013-01-04 19:50:55.000000000 +0900
+@@ -54,8 +54,8 @@
+ cat << EOF
+ menuentry '$(echo "${LONGNAME} $bitstr $onstr" | grub_quote)' --class osx --class darwin --class os \$menuentry_id_option 'osprober-xnu-$2-$(grub_get_device_id "${DEVICE}")' {
+ EOF
+- save_default_entry | sed -e "s/^/\t/"
+- prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
++ save_default_entry | grub_add_tab
++ prepare_grub_to_access_device ${DEVICE} | grub_add_tab
+ cat << EOF
+ load_video
+ set do_resume=0
+@@ -126,8 +126,8 @@
+ cat << EOF
+ menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class windows --class os \$menuentry_id_option 'osprober-chain-$(grub_get_device_id "${DEVICE}")' {
+ EOF
+- save_default_entry | sed -e "s/^/\t/"
+- prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
++ save_default_entry | grub_add_tab
++ prepare_grub_to_access_device ${DEVICE} | grub_add_tab
+
+ case ${LONGNAME} in
+ Windows\ Vista*|Windows\ 7*|Windows\ Server\ 2008*)
+@@ -181,14 +181,14 @@
+ used_osprober_linux_ids="$used_osprober_linux_ids 'osprober-gnulinux-$LKERNEL-${recovery_params}-$counter-$boot_device_id'"
+
+ if [ -z "${prepare_boot_cache}" ]; then
+- prepare_boot_cache="$(prepare_grub_to_access_device ${LBOOT} | sed -e "s/^/\t/")"
++ prepare_boot_cache="$(prepare_grub_to_access_device ${LBOOT} | grub_add_tab)"
+ fi
+
+ if [ "x$is_first_entry" = xtrue ]; then
+ cat << EOF
+ menuentry '$(echo "$OS" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-simple-$boot_device_id' {
+ EOF
+- save_default_entry | sed -e "s/^/\t/"
++ save_default_entry | grub_add_tab
+ printf '%s\n' "${prepare_boot_cache}"
+ cat << EOF
+ linux ${LKERNEL} ${LPARAMS}
+@@ -208,8 +208,8 @@
+ cat << EOF
+ menuentry '$(echo "$title" | grub_quote)' --class gnu-linux --class gnu --class os \$menuentry_id_option 'osprober-gnulinux-$LKERNEL-${recovery_params}-$boot_device_id' {
+ EOF
+- save_default_entry | sed -e "s/^/\t\t/"
+- printf '%s\n' "${prepare_boot_cache}" | sed -e "s/^/\t/"
++ save_default_entry | sed -e "s/^/$grub_tab$grub_tab/"
++ printf '%s\n' "${prepare_boot_cache}" | grub_add_tab
+ cat << EOF
+ linux ${LKERNEL} ${LPARAMS}
+ EOF
+@@ -243,8 +243,8 @@
+ cat << EOF
+ menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class hurd --class gnu --class os \$menuentry_id_option 'osprober-gnuhurd-/boot/gnumach.gz-false-$(grub_get_device_id "${DEVICE}")' {
+ EOF
+- save_default_entry | sed -e "s/^/\t/"
+- prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
++ save_default_entry | grub_add_tab
++ prepare_grub_to_access_device ${DEVICE} | grub_add_tab
+ grub_device="`${grub_probe} --device ${DEVICE} --target=drive`"
+ mach_device="`echo "${grub_device}" | sed -e 's/(\(hd.*\),msdos\(.*\))/\1s\2/'`"
+ grub_fs="`${grub_probe} --device ${DEVICE} --target=fs`"
diff --git a/sys-boot/grub/files/grub-2.00-genkernel-initramfs-single.patch b/sys-boot/grub/files/grub-2.00-genkernel-initramfs-single.patch
new file mode 100644
index 00000000..95a247e0
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-genkernel-initramfs-single.patch
@@ -0,0 +1,11 @@
+--- grub-2.00.orig/util/grub.d/10_linux.in
++++ grub-2.00/util/grub.d/10_linux.in
+@@ -243,7 +243,7 @@ while [ "x$list" != "x" ] ; do
+ "${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}"
+ if [ "x${GRUB_DISABLE_RECOVERY}" != "xtrue" ]; then
+ linux_entry "${OS}" "${version}" recovery \
+- "single ${GRUB_CMDLINE_LINUX}"
++ "single init_opts=single ${GRUB_CMDLINE_LINUX/splash=silent/splash=verbose}"
+ fi
+
+ list=`echo $list | tr ' ' '\n' | grep -vx $linux | tr '\n' ' '`
diff --git a/sys-boot/grub/files/grub-2.00-hardcoded-awk.patch b/sys-boot/grub/files/grub-2.00-hardcoded-awk.patch
new file mode 100644
index 00000000..8019a3c7
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-hardcoded-awk.patch
@@ -0,0 +1,15 @@
+https://bugs.gentoo.org/show_bug.cgi?id=424137
+https://savannah.gnu.org/bugs/?37558
+https://code.google.com/p/original-mawk/issues/detail?id=17
+--- grub-core/Makefile.am 2012-07-07 12:29:01 +0000
++++ grub-core/Makefile.am 2012-10-12 13:04:02 +0000
+@@ -349,7 +349,7 @@
+
+ # generate global module dependencies list
+ moddep.lst: syminfo.lst genmoddep.awk video.lst
+- cat $< | sort | awk -f $(srcdir)/genmoddep.awk > $@ || (rm -f $@; exit 1)
++ cat $< | sort | $(AWK) -f $(srcdir)/genmoddep.awk > $@ || (rm -f $@; exit 1)
+ platform_DATA += moddep.lst
+ CLEANFILES += config.log syminfo.lst moddep.lst
+
+
diff --git a/sys-boot/grub/files/grub-2.00-no-gets.patch b/sys-boot/grub/files/grub-2.00-no-gets.patch
new file mode 100644
index 00000000..c21d4b97
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-no-gets.patch
@@ -0,0 +1,22 @@
+hack until gzip pulls a newer gnulib version
+
+From 66712c23388e93e5c518ebc8515140fa0c807348 Mon Sep 17 00:00:00 2001
+From: Eric Blake <eblake@redhat.com>
+Date: Thu, 29 Mar 2012 13:30:41 -0600
+Subject: [PATCH] stdio: don't assume gets any more
+
+Gnulib intentionally does not have a gets module, and now that C11
+and glibc have dropped it, we should be more proactive about warning
+any user on a platform that still has a declaration of this dangerous
+interface.
+
+--- a/grub-core/gnulib/stdio.in.h
++++ b/grub-core/gnulib/stdio.in.h
+@@ -125,7 +125,6 @@
+ so any use of gets warrants an unconditional warning. Assume it is
+ always declared, since it is required by C89. */
+ #undef gets
+-_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
+
+ #if @GNULIB_FOPEN@
+ # if @REPLACE_FOPEN@
diff --git a/sys-boot/grub/files/grub-2.00-os-prober-efi-system.patch b/sys-boot/grub/files/grub-2.00-os-prober-efi-system.patch
new file mode 100644
index 00000000..7e0888a8
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-os-prober-efi-system.patch
@@ -0,0 +1,27 @@
+=== modified file 'util/grub.d/30_os-prober.in'
+--- util/grub.d/30_os-prober.in 2013-04-19 08:08:46 +0000
++++ util/grub.d/30_os-prober.in 2013-05-31 16:29:03 +0000
+@@ -149,6 +149,22 @@
+ }
+ EOF
+ ;;
++ efi)
++
++ EFIPATH=${DEVICE#*@}
++ DEVICE=${DEVICE%@*}
++ onstr="$(gettext_printf "(on %s)" "${DEVICE}")"
++ cat << EOF
++menuentry '$(echo "${LONGNAME} $onstr" | grub_quote)' --class windows --class os \$menuentry_id_option 'osprober-efi-$(grub_get_device_id "${DEVICE}")' {
++EOF
++ save_default_entry | sed -e "s/^/\t/"
++ prepare_grub_to_access_device ${DEVICE} | sed -e "s/^/\t/"
++
++ cat <<EOF
++ chainloader ${EFIPATH}
++}
++EOF
++ ;;
+ linux)
+ if [ "x$BTRFS" = "xbtrfs" ]; then
+ LINUXPROBED="`linux-boot-prober btrfs ${BTRFSuuid} ${BTRFSsubvol} 2> /dev/null | tr ' ' '^' | paste -s -d ' '`"
+
diff --git a/sys-boot/grub/files/grub-2.00-parallel-make.patch b/sys-boot/grub/files/grub-2.00-parallel-make.patch
new file mode 100644
index 00000000..03d634bb
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-parallel-make.patch
@@ -0,0 +1,46 @@
+Fix parallel make problems.
+Upstream changesets 4547, 4552, 4578.
+--- gentpl.py
++++ gentpl.py
+@@ -484,10 +484,10 @@
+ def installdir(default="bin"):
+ return "[+ IF installdir +][+ installdir +][+ ELSE +]" + default + "[+ ENDIF +]"
+
+-def manpage():
++def manpage(adddeps):
+ r = "if COND_MAN_PAGES\n"
+ r += gvar_add("man_MANS", "[+ name +].[+ mansection +]\n")
+- r += rule("[+ name +].[+ mansection +]", "[+ name +]", """
++ r += rule("[+ name +].[+ mansection +]", "[+ name +] " + adddeps, """
+ chmod a+x [+ name +]
+ PATH=$(builddir):$$PATH pkgdatadir=$(builddir) $(HELP2MAN) --section=[+ mansection +] -i $(top_srcdir)/docs/man/[+ name +].h2m -o $@ [+ name +]
+ """)
+@@ -503,7 +503,7 @@
+ r += gvar_add("TESTS", "[+ name +]")
+ r += "[+ ELSE +]"
+ r += var_add(installdir() + "_PROGRAMS", "[+ name +]")
+- r += "[+ IF mansection +]" + manpage() + "[+ ENDIF +]"
++ r += "[+ IF mansection +]" + manpage("") + "[+ ENDIF +]"
+ r += "[+ ENDIF +]"
+
+ r += var_set(cname() + "_SOURCES", platform_sources(platform))
+@@ -532,7 +532,7 @@
+ r += gvar_add ("TESTS", "[+ name +]")
+ r += "[+ ELSE +]"
+ r += var_add(installdir() + "_SCRIPTS", "[+ name +]")
+- r += "[+ IF mansection +]" + manpage() + "[+ ENDIF +]"
++ r += "[+ IF mansection +]" + manpage("grub-mkconfig_lib") + "[+ ENDIF +]"
+ r += "[+ ENDIF +]"
+
+ r += rule("[+ name +]", platform_sources(platform) + " $(top_builddir)/config.status", """
+--- grub-core/Makefile.am
++++ grub-core/Makefile.am
+@@ -63,7 +63,7 @@
+ rs_decoder.S: $(srcdir)/lib/reed_solomon.c
+ $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) -Os -I$(top_builddir) -S -DSTANDALONE -o $@ $< -g0 -mregparm=3 -ffreestanding
+
+-kern/i386/pc/startup.S: $(builddir)/rs_decoder.S
++boot/i386/pc/startup_raw.S: $(builddir)/rs_decoder.S
+ boot/mips/loongson/fwstart.S: $(builddir)/sm712_start.S
+
+ CLEANFILES += grub_script.yy.c grub_script.yy.h
diff --git a/sys-boot/grub/files/grub-2.00-rogentos-patch.patch b/sys-boot/grub/files/grub-2.00-rogentos-patch.patch
new file mode 100644
index 00000000..f3238628
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-rogentos-patch.patch
@@ -0,0 +1,10 @@
+--- grub-2.00.orig/util/grub.d/10_linux.in 2012-09-09 23:41:17.299578772 +0000
++++ grub-2.00/util/grub.d/10_linux.in 2012-09-09 23:40:11.014407451 +0000
+@@ -25,6 +25,7 @@ datarootdir="@datarootdir@"
+
+ export TEXTDOMAIN=@PACKAGE@
+ export TEXTDOMAINDIR="@localedir@"
++export GRUB_DISTRIBUTOR=Rogentos
+
+ CLASS="--class gnu-linux --class gnu --class os"
+
diff --git a/sys-boot/grub/files/grub-2.00-secureboot-user-sign-2.patch b/sys-boot/grub/files/grub-2.00-secureboot-user-sign-2.patch
new file mode 100644
index 00000000..6882d1f4
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-secureboot-user-sign-2.patch
@@ -0,0 +1,64 @@
+diff -Nurp grub-2.00.orig/util/grub-install.in grub-2.00/util/grub-install.in
+--- grub-2.00.orig/util/grub-install.in 2012-06-26 23:31:03.000000000 +0200
++++ grub-2.00/util/grub-install.in 2012-12-28 10:11:09.515872080 +0100
+@@ -821,12 +821,60 @@ elif [ x"${grub_modinfo_target_cpu}-${gr
+ gettext "You will have to set \`SystemPartition' and \`OSLoader' manually." 1>&2
+ echo 1>&2
+ elif [ x"$grub_modinfo_platform" = xefi ]; then
++
++ # sign the efi file with the User SecureBoot key
++ _sign_grub_efi() {
++ local _image="${1}"
++ local _image_dir="$(dirname "${_image}")"
++ local _image_name="$(basename "${_image}")"
++
++ case "$host_os" in
++ linux*)
++ modprobe -q efivars 2>/dev/null || true ;;
++ esac
++
++ local _private="/boot/SecureBoot/user-private.key"
++ local _public="/boot/SecureBoot/user-public.crt"
++ local _shim_dir="/usr/share/shim-signed-*"
++ if test -f "${_private}" && test -f "${_public}"; then
++ echo "SecureBoot signing ${_image}"
++ sbsign --key "${_private}" --cert "${_public}" \
++ --output "${_image}.signed" \
++ "${_image}" && \
++ mv "${_image}.signed" "${_image}" && \
++ cp ${_shim_dir}/*.efi "${_image_dir}/"
++
++ # if the image is called bootx64.efi, we need to rename it into
++ # grubx64.efi and place shim.efi there.
++ if test "${_image_name}" = "bootx64.efi" || test "${_image_name}" = "BOOTX64.EFI"; then
++ mv "${_image}" "${_image_dir}/grubx64.efi"
++ mv "${_image_dir}/shim.efi" "${_image_dir}/${_image_name}"
++ else
++ # otherwise, if it's named grubx64.efi, we just need to move
++ # shim.efi to bootx64.efi
++ mv "${_image_dir}/shim.efi" "${_image_dir}/bootx64.efi"
++ if test "${_image_name}" != "grubx64.efi" && test "${_image_name}" != "GRUBX64.EFI"; then
++ mv "${_image_dir}/${_image_name}" "${_image_dir}/grubx64.efi"
++ fi
++ # and then change efi_file
++ efi_file="bootx64.efi"
++ fi
++ else
++ echo "Cannot sign ${_image} for SecureBoot" 1>&2
++ echo "RogentOS keypair at $(basename ${_private}) not found" 1>&2
++ fi
++ }
++
+ cp "${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" "${efidir}/${efi_file}"
++ _efi_grub_file="${efidir}/${efi_file}"
+ # For old macs. Suggested by Peter Jones.
+ if [ x$grub_modinfo_target_cpu = xi386 ]; then
+ cp "${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" "${efidir}/boot.efi"
++ _efi_grub_file="${efidir}/boot.efi"
+ fi
+
++ _sign_grub_efi "${_efi_grub_file}"
++
+ # Try to make this image bootable using the EFI Boot Manager, if available.
+ efibootmgr="`which efibootmgr`"
+ if test "$removable" = no && test -n "$efi_distributor" && \
diff --git a/sys-boot/grub/files/grub-2.00-secureboot-user-sign.patch b/sys-boot/grub/files/grub-2.00-secureboot-user-sign.patch
new file mode 100644
index 00000000..6c02cbd4
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-secureboot-user-sign.patch
@@ -0,0 +1,42 @@
+--- a/util/grub-install.in
++++ b/util/grub-install.in
+@@ -821,12 +821,39 @@ elif [ x"${grub_modinfo_target_cpu}-${gr
+ gettext "You will have to set \`SystemPartition' and \`OSLoader' manually." 1>&2
+ echo 1>&2
+ elif [ x"$grub_modinfo_platform" = xefi ]; then
++
++ # sign the efi file with the User SecureBoot key
++ _sign_grub_efi() {
++ local _image="${1}"
++ case "$host_os" in
++ linux*)
++ modprobe -q efivars 2>/dev/null || true ;;
++ esac
++
++ local _private="/boot/SecureBoot/user-private.key"
++ local _public="/boot/SecureBoot/user-public.crt"
++ if test -f "${_private}" && test -f "${_public}"; then
++ echo "SecureBoot signing ${_image}"
++ sbsign --key "${_private}" --cert "${_public}" \
++ --output "${_image}.signed" \
++ "${_image}" && \
++ mv "${_image}.signed" "${_image}"
++ else
++ echo "Cannot sign ${_image} for SecureBoot" 1>&2
++ echo "RogentOS keypair at $(basename ${_private}) not found" 1>&2
++ fi
++ }
++
+ cp "${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" "${efidir}/${efi_file}"
++ _efi_grub_file="${efidir}/${efi_file}"
+ # For old macs. Suggested by Peter Jones.
+ if [ x$grub_modinfo_target_cpu = xi386 ]; then
+ cp "${grubdir}/${grub_modinfo_target_cpu}-$grub_modinfo_platform/core.${imgext}" "${efidir}/boot.efi"
++ _efi_grub_file="${efidir}/boot.efi"
+ fi
+
++ _sign_grub_efi "${_efi_grub_file}"
++
+ # Try to make this image bootable using the EFI Boot Manager, if available.
+ efibootmgr="`which efibootmgr`"
+ if test "$removable" = no && test -n "$efi_distributor" && \
diff --git a/sys-boot/grub/files/grub-2.00-texinfo.patch b/sys-boot/grub/files/grub-2.00-texinfo.patch
new file mode 100644
index 00000000..803f3cbc
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-texinfo.patch
@@ -0,0 +1,16 @@
+Fix for texinfo-5.1
+
+=== modified file 'docs/grub-dev.texi'
+--- docs/grub-dev.texi 2012-05-22 07:15:28 +0000
++++ docs/grub-dev.texi 2013-04-08 13:23:07 +0000
+@@ -1394,8 +1394,8 @@
+
+ @node Bitmap API
+ @section Bitmap API
+-@itemize
+ @subsection grub_video_bitmap_create
++@itemize
+ @item Prototype:
+ @example
+ grub_err_t grub_video_bitmap_create (struct grub_video_bitmap **bitmap, unsigned int width, unsigned int height, enum grub_video_blit_format blit_format)
+
diff --git a/sys-boot/grub/files/grub-2.00-tftp-endian.patch b/sys-boot/grub/files/grub-2.00-tftp-endian.patch
new file mode 100644
index 00000000..f4e56445
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-tftp-endian.patch
@@ -0,0 +1,24 @@
+https://bugs.gentoo.org/show_bug.cgi?id=438612
+
+=== modified file 'grub-core/net/tftp.c'
+--- grub-core/net/tftp.c 2012-06-22 20:04:16 +0000
++++ grub-core/net/tftp.c 2012-07-02 09:22:50 +0000
+@@ -143,7 +143,7 @@
+
+ tftph_ack = (struct tftphdr *) nb_ack.data;
+ tftph_ack->opcode = grub_cpu_to_be16 (TFTP_ACK);
+- tftph_ack->u.ack.block = block;
++ tftph_ack->u.ack.block = grub_cpu_to_be16 (block);
+
+ err = grub_net_send_udp_packet (data->sock, &nb_ack);
+ if (err)
+@@ -225,7 +225,7 @@
+ grub_priority_queue_pop (data->pq);
+
+ if (file->device->net->packs.count < 50)
+- err = ack (data, tftph->u.data.block);
++ err = ack (data, data->block + 1);
+ else
+ {
+ file->device->net->stall = 1;
+
diff --git a/sys-boot/grub/files/grub-2.00-vga-deprecated-not-yet.patch b/sys-boot/grub/files/grub-2.00-vga-deprecated-not-yet.patch
new file mode 100644
index 00000000..3859bb2e
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-vga-deprecated-not-yet.patch
@@ -0,0 +1,13 @@
+--- grub-2.00.orig/grub-core/loader/i386/linux.c
++++ grub-2.00/grub-core/loader/i386/linux.c
+@@ -946,10 +946,6 @@ grub_cmd_linux (grub_command_t cmd __att
+ if (! buf)
+ goto fail;
+
+- grub_printf_ (N_("%s is deprecated. "
+- "Use set gfxpayload=%s before "
+- "linux command instead.\n"),
+- argv[i], buf);
+ err = grub_env_set ("gfxpayload", buf);
+ grub_free (buf);
+ if (err)
diff --git a/sys-boot/grub/files/grub-2.00-wallpaper-settings-support.patch b/sys-boot/grub/files/grub-2.00-wallpaper-settings-support.patch
new file mode 100644
index 00000000..828eef72
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-wallpaper-settings-support.patch
@@ -0,0 +1,14 @@
+--- grub-2.00.orig/util/grub-mkconfig.in
++++ grub-2.00/util/grub-mkconfig.in
+@@ -216,7 +216,10 @@ export GRUB_DEFAULT \
+ GRUB_INIT_TUNE \
+ GRUB_SAVEDEFAULT \
+ GRUB_ENABLE_CRYPTODISK \
+- GRUB_BADRAM
++ GRUB_BADRAM \
++ GRUB_WALLPAPER \
++ GRUB_COLOR_NORMAL \
++ GRUB_COLOR_HIGHLIGHT
+
+ if test "x${grub_cfg}" != "x"; then
+ rm -f "${grub_cfg}.new"
diff --git a/sys-boot/grub/files/grub-2.00-zfs-feature-flag-support-r1.patch b/sys-boot/grub/files/grub-2.00-zfs-feature-flag-support-r1.patch
new file mode 100644
index 00000000..b7d780f2
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-zfs-feature-flag-support-r1.patch
@@ -0,0 +1,893 @@
+ZFS Feature Flag Support
+
+This is a monolithic version of the following commits:
+
+https://github.com/maxximino/grub2/commit/31a32560fd7948ae5ff5c63105d7c068de7890c8
+https://github.com/maxximino/grub2/commit/595d76e8ca0690a963f5533689de8db54ef07e75
+https://github.com/maxximino/grub2/commit/58344034e40218b20500fa2936eb4d7d019e1e88
+https://github.com/maxximino/grub2/commit/f98cb078abab2c14bb0766b5a0ceb055683dab81
+https://github.com/maxximino/grub2/commit/f12806f43a969a654dee7bb89b2e8fd5c42f0e2e
+
+A change was made to account for d8a0feb6 from upstream. This change prevents a
+compile time failure that is caused by a change in the callback interface used
+by mzap_interate(). Modifications to nvlist_find_value() were reverted to
+resolve Gentoo bug #462740. This eliminated the need for the new nvpair_type()
+and nvpair_value() functions. They have been removed to silence a compiler
+warning and reduce the size of the patch. Further adjustments were made to
+silence the following warnings:
+
+/var/tmp/portage/sys-boot/grub-2.00-r2/work/grub-2.00/grub-core/fs/zfs/zfs_lz4.c:77:5:
+warning: "__STDC_VERSION__" is not defined [-Wundef]
+/var/tmp/portage/sys-boot/grub-2.00-r2/work/grub-2.00/grub-core/fs/zfs/zfs.c:4079:3:
+warning: passing argument 4 of 'mzap_iterate' from incompatible pointer type
+[enabled by default]
+
+The initial feature flag support patches were written by Delphix while the LZ4
+support was written by Saso Kiselkov. The work porting this to GRUB2 was done
+by Massimo Maggi, while the adaption to Gentoo's GRUB2 package was done by
+Richard Yao.
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index b80187c..1bf3038 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -95,6 +95,7 @@ library = {
+ common = grub-core/fs/zfs/zfs.c;
+ common = grub-core/fs/zfs/zfsinfo.c;
+ common = grub-core/fs/zfs/zfs_lzjb.c;
++ common = grub-core/fs/zfs/zfs_lz4.c;
+ common = grub-core/fs/zfs/zfs_sha256.c;
+ common = grub-core/fs/zfs/zfs_fletcher.c;
+ common = grub-core/lib/envblk.c;
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 39e77a4..1550b90 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1186,6 +1186,7 @@ module = {
+ name = zfs;
+ common = fs/zfs/zfs.c;
+ common = fs/zfs/zfs_lzjb.c;
++ common = fs/zfs/zfs_lz4.c;
+ common = fs/zfs/zfs_sha256.c;
+ common = fs/zfs/zfs_fletcher.c;
+ };
+diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
+index ba0554a..811e3df 100644
+--- a/grub-core/fs/zfs/zfs.c
++++ b/grub-core/fs/zfs/zfs.c
+@@ -2,6 +2,7 @@
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc.
+ * Copyright 2010 Sun Microsystems, Inc.
++ * Copyright (c) 2012 by Delphix. All rights reserved.
+ *
+ * GRUB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -153,11 +154,13 @@ ZAP_LEAF_ENTRY(zap_leaf_phys_t *l, int bs, int idx)
+
+
+ /*
+- * Decompression Entry - lzjb
++ * Decompression Entry - lzjb & lz4
+ */
+
+ extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t);
+
++extern grub_err_t lz4_decompress (void *, void *, grub_size_t, grub_size_t);
++
+ typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start,
+ grub_size_t s_len, grub_size_t d_len);
+ typedef struct decomp_entry
+@@ -263,6 +266,19 @@ grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key
+ grub_size_t keysize,
+ grub_uint64_t salt,
+ grub_uint64_t algo) = NULL;
++/*
++ * List of pool features that the grub implementation of ZFS supports for
++ * read. Note that features that are only required for write do not need
++ * to be listed here since grub opens pools in read-only mode.
++ */
++static const char *spa_feature_names[] = {
++ "org.illumos:lz4_compress",NULL
++};
++
++static int NESTED_FUNC_ATTR
++check_feature(const char *name, grub_uint64_t val);
++static int
++check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data );
+
+ static grub_err_t
+ zlib_decompress (void *s, void *d,
+@@ -322,6 +338,7 @@ static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
+ {"gzip-8", zlib_decompress}, /* ZIO_COMPRESS_GZIP8 */
+ {"gzip-9", zlib_decompress}, /* ZIO_COMPRESS_GZIP9 */
+ {"zle", zle_decompress}, /* ZIO_COMPRESS_ZLE */
++ {"lz4", lz4_decompress}, /* ZIO_COMPRESS_LZ4 */
+ };
+
+ static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian,
+@@ -482,15 +499,11 @@ uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset,
+
+ if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
+ == UBERBLOCK_MAGIC
+- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0
+- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN)
+- <= SPA_VERSION)
+- endian = GRUB_ZFS_LITTLE_ENDIAN;
++ && SPA_VERSION_IS_SUPPORTED(grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN)))
++ endian = GRUB_ZFS_LITTLE_ENDIAN;
+
+ if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC
+- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0
+- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN)
+- <= SPA_VERSION)
++ && SPA_VERSION_IS_SUPPORTED(grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN)))
+ endian = GRUB_ZFS_BIG_ENDIAN;
+
+ if (endian == GRUB_ZFS_UNKNOWN_ENDIAN)
+@@ -764,6 +777,99 @@ fill_vdev_info (struct grub_zfs_data *data,
+ }
+
+ /*
++ * For a given XDR packed nvlist, verify the first 4 bytes and move on.
++ *
++ * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
++ *
++ * encoding method/host endian (4 bytes)
++ * nvl_version (4 bytes)
++ * nvl_nvflag (4 bytes)
++ * encoded nvpairs:
++ * encoded size of the nvpair (4 bytes)
++ * decoded size of the nvpair (4 bytes)
++ * name string size (4 bytes)
++ * name string data (sizeof(NV_ALIGN4(string))
++ * data type (4 bytes)
++ * # of elements in the nvpair (4 bytes)
++ * data
++ * 2 zero's for the last nvpair
++ * (end of the entire list) (8 bytes)
++ *
++ */
++
++/*
++ * The nvlist_next_nvpair() function returns a handle to the next nvpair in the
++ * list following nvpair. If nvpair is NULL, the first pair is returned. If
++ * nvpair is the last pair in the nvlist, NULL is returned.
++ */
++static const char *
++nvlist_next_nvpair(const char *nvl, const char *nvpair)
++{
++ const char *nvp;
++ int encode_size;
++ int name_len;
++ if (nvl == NULL)
++ return (NULL);
++
++ if (nvpair == NULL) {
++ /* skip over header, nvl_version and nvl_nvflag */
++ nvpair = nvl + 4 * 3;
++ } else {
++ /* skip to the next nvpair */
++ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair));
++ nvpair += encode_size;
++ }
++ /* 8 bytes of 0 marks the end of the list */
++ if (*(grub_uint64_t*)nvpair == 0)
++ return (NULL);
++ /*consistency checks*/
++ if (nvpair + 4 * 3 >= nvl + VDEV_PHYS_SIZE)
++ {
++ grub_dprintf ("zfs", "nvlist overflow\n");
++ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
++ return (NULL);
++ }
++ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair));
++
++ nvp = nvpair + 4*2;
++ name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
++ nvp += 4;
++
++ nvp = nvp + ((name_len + 3) & ~3); // align
++ if (nvp + 4 >= nvl + VDEV_PHYS_SIZE
++ || encode_size < 0
++ || nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE)
++ {
++ grub_dprintf ("zfs", "nvlist overflow\n");
++ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
++ return (NULL);
++ }
++ /* end consistency checks */
++
++ return (nvpair);
++}
++/*
++ * This function returns 0 on success and 1 on failure. On success, a string
++ * containing the name of nvpair is saved in buf.
++ */
++static int
++nvpair_name(const char *nvp, char **buf, int* buflen)
++{
++ int len;
++
++ /* skip over encode/decode size */
++ nvp += 4 * 2;
++
++ len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
++ nvp=nvp+4;
++
++ *buf=(char*)nvp;
++ *buflen=len;
++
++ return (0);
++}
++
++/*
+ * Check the disk label information and retrieve needed vdev name-value pairs.
+ *
+ */
+@@ -773,7 +879,7 @@ check_pool_label (struct grub_zfs_data *data,
+ int *inserted)
+ {
+ grub_uint64_t pool_state, txg = 0;
+- char *nvlist;
++ char *nvlist,*features;
+ #if 0
+ char *nv;
+ #endif
+@@ -837,13 +943,13 @@ check_pool_label (struct grub_zfs_data *data,
+ }
+ grub_dprintf ("zfs", "check 8 passed\n");
+
+- if (version > SPA_VERSION)
++ if (!SPA_VERSION_IS_SUPPORTED(version))
+ {
+ grub_free (nvlist);
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "too new version %llu > %llu",
+ (unsigned long long) version,
+- (unsigned long long) SPA_VERSION);
++ (unsigned long long) SPA_VERSION_BEFORE_FEATURES);
+ }
+ grub_dprintf ("zfs", "check 9 passed\n");
+
+@@ -893,7 +999,30 @@ check_pool_label (struct grub_zfs_data *data,
+ grub_free (nv);
+ }
+ grub_dprintf ("zfs", "check 10 passed\n");
+-
++ if ((features=grub_zfs_nvlist_lookup_nvlist(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ)))
++ {
++ const char *nvp=NULL;
++ char *name = grub_zalloc(51);
++ char *nameptr;
++ int namelen;
++ while ((nvp = nvlist_next_nvpair(features, nvp)) != NULL)
++ {
++ nvpair_name(nvp, &nameptr,&namelen);
++ if(namelen > 50){namelen=50;}
++ grub_strncpy(name,nameptr,namelen);
++ name[namelen]=0;
++ grub_dprintf("zfs","namelen=%u str=%s\n",namelen,name);
++ if (check_feature(name,1) != 0)
++ {
++ grub_dprintf("zfs","feature missing in check_pool_label:%s\n",name);
++ err= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET," check_pool_label missing feature '%s' for read",name);
++ grub_free(name);
++ return err;
++ }
++ }
++ grub_free(name);
++ }
++ grub_dprintf ("zfs", "check 12 passed (feature flags)\n");
+ grub_free (nvlist);
+
+ return GRUB_ERR_NONE;
+@@ -3034,27 +3163,6 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
+ return err;
+ }
+
+-/*
+- * For a given XDR packed nvlist, verify the first 4 bytes and move on.
+- *
+- * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
+- *
+- * encoding method/host endian (4 bytes)
+- * nvl_version (4 bytes)
+- * nvl_nvflag (4 bytes)
+- * encoded nvpairs:
+- * encoded size of the nvpair (4 bytes)
+- * decoded size of the nvpair (4 bytes)
+- * name string size (4 bytes)
+- * name string data (sizeof(NV_ALIGN4(string))
+- * data type (4 bytes)
+- * # of elements in the nvpair (4 bytes)
+- * data
+- * 2 zero's for the last nvpair
+- * (end of the entire list) (8 bytes)
+- *
+- */
+-
+ static int
+ nvlist_find_value (const char *nvlist_in, const char *name,
+ int valtype, char **val,
+@@ -3386,6 +3494,10 @@ zfs_mount (grub_device_t dev)
+ return NULL;
+ }
+
++ if (ub->ub_version >= SPA_VERSION_FEATURES &&
++ check_mos_features(&((objset_phys_t *) osp)->os_meta_dnode,ub_endian, data) != 0)
++ return NULL;
++
+ /* Got the MOS. Save it at the memory addr MOS. */
+ grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
+ DNODE_SIZE);
+@@ -3910,6 +4022,64 @@ grub_zfs_dir (grub_device_t device, const char *path,
+ return grub_errno;
+ }
+
++static int NESTED_FUNC_ATTR
++check_feature(const char *name, grub_uint64_t val)
++{
++ int i;
++ if(val ==0) return 0;
++ if(*name==0) return 0;
++ for (i = 0; spa_feature_names[i] != NULL; i++)
++ {
++ if (grub_strcmp(name, spa_feature_names[i]) == 0)
++ return 0;
++ }
++ grub_printf("missing feature for read '%s'\n",name);
++ return 1;
++}
++
++/*
++ * Checks whether the MOS features that are active are supported by this
++ * (GRUB's) implementation of ZFS.
++ *
++ * Return:
++ * 0: Success.
++ * errnum: Failure.
++ */
++
++static int
++check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data )
++{
++ grub_uint64_t objnum;
++ grub_uint8_t errnum = 0;
++ dnode_end_t dn,mosmdn;
++ mzap_phys_t* mzp;
++ grub_zfs_endian_t endianzap;
++ int size;
++ grub_memmove(&(mosmdn.dn),mosmdn_phys,sizeof(dnode_phys_t));
++ mosmdn.endian=endian;
++ if ((errnum = dnode_get(&mosmdn, DMU_POOL_DIRECTORY_OBJECT,
++ DMU_OT_OBJECT_DIRECTORY, &dn,data)) != 0)
++ return (errnum);
++
++ /*
++ * Find the object number for 'features_for_read' and retrieve its
++ * corresponding dnode. Note that we don't check features_for_write
++ * because GRUB is not opening the pool for write.
++ */
++ if ((errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data,0)) != 0)
++ return (errnum);
++
++ if ((errnum = dnode_get(&mosmdn, objnum, DMU_OTN_ZAP_METADATA, &dn, data)) != 0)
++ return (errnum);
++
++ if ((errnum = dmu_read(&dn, 0, (void**)&mzp, &endianzap,data)) != 0)
++ return (errnum);
++
++ size = grub_zfs_to_cpu16 (dn.dn.dn_datablkszsec, dn.endian) << SPA_MINBLOCKSHIFT;
++ return (mzap_iterate(mzp,endianzap, size, check_feature));
++}
++
++
+ #ifdef GRUB_UTIL
+ static grub_err_t
+ grub_zfs_embed (grub_device_t device __attribute__ ((unused)),
+diff --git a/grub-core/fs/zfs/zfs_lz4.c b/grub-core/fs/zfs/zfs_lz4.c
+new file mode 100644
+index 0000000..ff85a77
+--- /dev/null
++++ b/grub-core/fs/zfs/zfs_lz4.c
+@@ -0,0 +1,321 @@
++/*
++ * LZ4 - Fast LZ compression algorithm
++ * Header File
++ * Copyright (C) 2011-2013, Yann Collet.
++ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are
++ * met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You can contact the author at :
++ * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
++ * - LZ4 source repository : http://code.google.com/p/lz4/
++ */
++
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++
++static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest,
++ int isize, int maxOutputSize);
++
++/*
++ * CPU Feature Detection
++ */
++
++/* 32 or 64 bits ? */
++#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || \
++ defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || \
++ defined(__LP64__) || defined(_LP64))
++#define LZ4_ARCH64 1
++#else
++#define LZ4_ARCH64 0
++#endif
++
++/*
++ * Little Endian or Big Endian?
++ * Note: overwrite the below #define if you know your architecture endianess.
++ */
++#if (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || \
++ defined(_BIG_ENDIAN) || defined(_ARCH_PPC) || defined(__PPC__) || \
++ defined(__PPC) || defined(PPC) || defined(__powerpc__) || \
++ defined(__powerpc) || defined(powerpc) || \
++ ((defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))))
++#define LZ4_BIG_ENDIAN 1
++#else
++ /*
++ * Little Endian assumed. PDP Endian and other very rare endian format
++ * are unsupported.
++ */
++#endif
++
++/*
++ * Compiler Options
++ */
++
++#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
++/* "restrict" is a known keyword */
++#else
++/* Disable restrict */
++#ifndef restrict
++#define restrict /* Only if somebody already didn't take care of that.*/
++#endif
++#endif
++
++#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
++
++#define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) \
++ | (((x) & 0xffu) << 8)))
++
++#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
++#define expect(expr, value) (__builtin_expect((expr), (value)))
++#else
++#define expect(expr, value) (expr)
++#endif
++
++#define likely(expr) expect((expr) != 0, 1)
++#define unlikely(expr) expect((expr) != 0, 0)
++
++/* Basic types */
++#define BYTE grub_uint8_t
++#define U16 grub_uint16_t
++#define U32 grub_uint32_t
++#define S32 grub_int32_t
++#define U64 grub_uint64_t
++typedef grub_size_t size_t;
++
++typedef struct _U16_S {
++ U16 v;
++} U16_S;
++typedef struct _U32_S {
++ U32 v;
++} U32_S;
++typedef struct _U64_S {
++ U64 v;
++} U64_S;
++
++#define A64(x) (((U64_S *)(x))->v)
++#define A32(x) (((U32_S *)(x))->v)
++#define A16(x) (((U16_S *)(x))->v)
++
++/*
++ * Constants
++ */
++#define MINMATCH 4
++
++#define COPYLENGTH 8
++#define LASTLITERALS 5
++
++#define ML_BITS 4
++#define ML_MASK ((1U<<ML_BITS)-1)
++#define RUN_BITS (8-ML_BITS)
++#define RUN_MASK ((1U<<RUN_BITS)-1)
++
++/*
++ * Architecture-specific macros
++ */
++#if LZ4_ARCH64
++#define STEPSIZE 8
++#define UARCH U64
++#define AARCH A64
++#define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d += 8; s += 8;
++#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d)
++#define LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e)
++#define HTYPE U32
++#define INITBASE(base) const BYTE* const base = ip
++#else
++#define STEPSIZE 4
++#define UARCH U32
++#define AARCH A32
++#define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d += 4; s += 4;
++#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d);
++#define LZ4_SECURECOPY LZ4_WILDCOPY
++#define HTYPE const BYTE*
++#define INITBASE(base) const int base = 0
++#endif
++
++#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE))
++#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
++ { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; }
++#define LZ4_WRITE_LITTLEENDIAN_16(p, i) \
++ { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; }
++#else
++#define LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); }
++#define LZ4_WRITE_LITTLEENDIAN_16(p, v) { A16(p) = v; p += 2; }
++#endif
++
++/* Macros */
++#define LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e);
++
++/* Decompression functions */
++grub_err_t
++lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len);
++
++grub_err_t
++lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len)
++{
++ const BYTE *src = s_start;
++ U32 bufsiz = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) |
++ src[3];
++
++ /* invalid compressed buffer size encoded at start */
++ if (bufsiz + 4 > s_len)
++ return grub_error(GRUB_ERR_BAD_FS,"lz4 decompression failed.");
++
++ /*
++ * Returns 0 on success (decompression function returned non-negative)
++ * and appropriate error on failure (decompression function returned negative).
++ */
++ return (LZ4_uncompress_unknownOutputSize((char*)s_start + 4, d_start, bufsiz,
++ d_len) < 0)?grub_error(GRUB_ERR_BAD_FS,"lz4 decompression failed."):0;
++}
++
++static int
++LZ4_uncompress_unknownOutputSize(const char *source,
++ char *dest, int isize, int maxOutputSize)
++{
++ /* Local Variables */
++ const BYTE *restrict ip = (const BYTE *) source;
++ const BYTE *const iend = ip + isize;
++ const BYTE *restrict ref;
++
++ BYTE *restrict op = (BYTE *) dest;
++ BYTE *const oend = op + maxOutputSize;
++ BYTE *cpy;
++
++ size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 };
++
++ /* Main Loop */
++ while (ip < iend) {
++ BYTE token;
++ int length;
++
++ /* get runlength */
++ token = *ip++;
++ if ((length = (token >> ML_BITS)) == RUN_MASK) {
++ int s = 255;
++ while ((ip < iend) && (s == 255)) {
++ s = *ip++;
++ length += s;
++ }
++ }
++ /* copy literals */
++ cpy = op + length;
++ if ((cpy > oend - COPYLENGTH) ||
++ (ip + length > iend - COPYLENGTH)) {
++ if (cpy > oend)
++ /*
++ * Error: request to write beyond destination
++ * buffer.
++ */
++ goto _output_error;
++ if (ip + length > iend)
++ /*
++ * Error : request to read beyond source
++ * buffer.
++ */
++ goto _output_error;
++ grub_memcpy(op, ip, length);
++ op += length;
++ ip += length;
++ if (ip < iend)
++ /* Error : LZ4 format violation */
++ goto _output_error;
++ /* Necessarily EOF, due to parsing restrictions. */
++ break;
++ }
++ LZ4_WILDCOPY(ip, op, cpy);
++ ip -= (op - cpy);
++ op = cpy;
++
++ /* get offset */
++ LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip);
++ ip += 2;
++ if (ref < (BYTE * const) dest)
++ /*
++ * Error: offset creates reference outside of
++ * destination buffer.
++ */
++ goto _output_error;
++
++ /* get matchlength */
++ if ((length = (token & ML_MASK)) == ML_MASK) {
++ while (ip < iend) {
++ int s = *ip++;
++ length += s;
++ if (s == 255)
++ continue;
++ break;
++ }
++ }
++ /* copy repeated sequence */
++ if unlikely(op - ref < STEPSIZE) {
++#if LZ4_ARCH64
++ size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 };
++ size_t dec2 = dec2table[op - ref];
++#else
++ const int dec2 = 0;
++#endif
++ *op++ = *ref++;
++ *op++ = *ref++;
++ *op++ = *ref++;
++ *op++ = *ref++;
++ ref -= dec[op - ref];
++ A32(op) = A32(ref);
++ op += STEPSIZE - 4;
++ ref -= dec2;
++ } else {
++ LZ4_COPYSTEP(ref, op);
++ }
++ cpy = op + length - (STEPSIZE - 4);
++ if (cpy > oend - COPYLENGTH) {
++ if (cpy > oend)
++ /*
++ * Error: request to write outside of
++ * destination buffer.
++ */
++ goto _output_error;
++ LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
++ while (op < cpy)
++ *op++ = *ref++;
++ op = cpy;
++ if (op == oend)
++ /*
++ * Check EOF (should never happen, since last
++ * 5 bytes are supposed to be literals).
++ */
++ break;
++ continue;
++ }
++ LZ4_SECURECOPY(ref, op, cpy);
++ op = cpy; /* correction */
++ }
++
++ /* end of decoding */
++ return (int)(((char *)op) - dest);
++
++ /* write overflow error detected */
++ _output_error:
++ return (int)(-(((char *)ip) - source));
++}
+diff --git a/grub-core/fs/zfs/zfsinfo.c b/grub-core/fs/zfs/zfsinfo.c
+index fdb587a..c96bf21 100644
+--- a/grub-core/fs/zfs/zfsinfo.c
++++ b/grub-core/fs/zfs/zfsinfo.c
+@@ -132,21 +132,31 @@ print_vdev_info (char *nvlist, int tab)
+ grub_free (path);
+ return GRUB_ERR_NONE;
+ }
++ char is_mirror=(grub_strcmp(type,VDEV_TYPE_MIRROR) == 0);
++ char is_raidz=(grub_strcmp(type,VDEV_TYPE_RAIDZ) == 0);
+
+- if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
++ if (is_mirror || is_raidz)
+ {
+ int nelm, i;
+
+ nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
+ (nvlist, ZPOOL_CONFIG_CHILDREN);
+
++ if(is_mirror){
++ grub_puts_ (N_("This VDEV is a mirror"));
++ }
++ else if(is_raidz){
++ grub_uint64_t parity;
++ grub_zfs_nvlist_lookup_uint64(nvlist,"nparity",&parity);
++ grub_printf_ (N_("This VDEV is a RAIDZ%llu\n"),(unsigned long long)parity);
++ }
+ print_tabs (tab);
+ if (nelm <= 0)
+ {
+- grub_puts_ (N_("Incorrect mirror"));
++ grub_puts_ (N_("Incorrect VDEV"));
+ return GRUB_ERR_NONE;
+ }
+- grub_printf_ (N_("Mirror with %d children\n"), nelm);
++ grub_printf_ (N_("VDEV with %d children\n"), nelm);
+ print_state (nvlist, tab);
+ for (i = 0; i < nelm; i++)
+ {
+@@ -162,14 +172,14 @@ print_vdev_info (char *nvlist, int tab)
+ total element number. And the number itself is fine,
+ only the element isn't.
+ */
+- grub_printf_ (N_("Mirror element number %d isn't correct\n"), i);
++ grub_printf_ (N_("VDEV element number %d isn't correct\n"), i);
+ continue;
+ }
+
+ /* TRANSLATORS: it's the element carying the number %d, not
+ total element number. This is used in enumeration
+ "Element number 1", "Element number 2", ... */
+- grub_printf_ (N_("Mirror element number %d:\n"), i);
++ grub_printf_ (N_("VDEV element number %d:\n"), i);
+ print_vdev_info (child, tab + 1);
+
+ grub_free (child);
+diff --git a/include/grub/zfs/dmu.h b/include/grub/zfs/dmu.h
+index 8fc6dc5..4ad616c 100644
+--- a/include/grub/zfs/dmu.h
++++ b/include/grub/zfs/dmu.h
+@@ -22,6 +22,39 @@
+
+ #ifndef _SYS_DMU_H
+ #define _SYS_DMU_H
++#define B_FALSE 0
++#define B_TRUE 1
++
++#define DMU_OT_NEWTYPE 0x80
++#define DMU_OT_METADATA 0x40
++#define DMU_OT_BYTESWAP_MASK 0x3f
++
++#define DMU_OT(byteswap, metadata) \
++ (DMU_OT_NEWTYPE | \
++ ((metadata) ? DMU_OT_METADATA : 0) | \
++ ((byteswap) & DMU_OT_BYTESWAP_MASK))
++
++#define DMU_OT_IS_VALID(ot) (((ot) & DMU_OT_NEWTYPE) ? \
++ ((ot) & DMU_OT_BYTESWAP_MASK) < DMU_BSWAP_NUMFUNCS : \
++ (ot) < DMU_OT_NUMTYPES)
++
++#define DMU_OT_IS_METADATA(ot) (((ot) & DMU_OT_NEWTYPE) ? \
++ ((ot) & DMU_OT_METADATA) : \
++ dmu_ot[(ot)].ot_metadata)
++
++typedef enum dmu_object_byteswap {
++ DMU_BSWAP_UINT8,
++ DMU_BSWAP_UINT16,
++ DMU_BSWAP_UINT32,
++ DMU_BSWAP_UINT64,
++ DMU_BSWAP_ZAP,
++ DMU_BSWAP_DNODE,
++ DMU_BSWAP_OBJSET,
++ DMU_BSWAP_ZNODE,
++ DMU_BSWAP_OLDACL,
++ DMU_BSWAP_ACL,
++ DMU_BSWAP_NUMFUNCS
++} dmu_object_byteswap_t;
+
+ /*
+ * This file describes the interface that the DMU provides for its
+@@ -89,7 +122,17 @@ typedef enum dmu_object_type {
+ DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */
+ DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */
+ DMU_OT_DSL_KEYCHAIN = 54,
+- DMU_OT_NUMTYPES
++ DMU_OT_NUMTYPES,
++ DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE),
++ DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE),
++ DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE),
++ DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE),
++ DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE),
++ DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE),
++ DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE),
++ DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE),
++ DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE),
++ DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE),
+ } dmu_object_type_t;
+
+ typedef enum dmu_objset_type {
+@@ -116,5 +159,6 @@ typedef enum dmu_objset_type {
+ #define DMU_POOL_HISTORY "history"
+ #define DMU_POOL_PROPS "pool_props"
+ #define DMU_POOL_L2CACHE "l2cache"
++#define DMU_POOL_FEATURES_FOR_READ "features_for_read"
+
+ #endif /* _SYS_DMU_H */
+diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h
+index e326c8b..761ade7 100644
+--- a/include/grub/zfs/zfs.h
++++ b/include/grub/zfs/zfs.h
+@@ -36,8 +36,13 @@ typedef enum grub_zfs_endian
+ /*
+ * On-disk version number.
+ */
+-#define SPA_VERSION 33ULL
+-
++#define SPA_VERSION_INITIAL 1ULL
++#define SPA_VERSION_BEFORE_FEATURES 33ULL
++#define SPA_VERSION 5000ULL
++#define SPA_VERSION_FEATURES 5000ULL
++#define SPA_VERSION_IS_SUPPORTED(v) \
++ (((v) >= SPA_VERSION_INITIAL && (v) <= SPA_VERSION_BEFORE_FEATURES) || \
++ ((v) >= SPA_VERSION_FEATURES && (v) <= SPA_VERSION))
+ /*
+ * The following are configuration names used in the nvlist describing a pool's
+ * configuration.
+@@ -76,6 +81,7 @@ typedef enum grub_zfs_endian
+ #define ZPOOL_CONFIG_DDT_HISTOGRAM "ddt_histogram"
+ #define ZPOOL_CONFIG_DDT_OBJ_STATS "ddt_object_stats"
+ #define ZPOOL_CONFIG_DDT_STATS "ddt_stats"
++#define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read"
+ /*
+ * The persistent vdev state is stored as separate values rather than a single
+ * 'vdev_state' entry. This is because a device can be in multiple states, such
+diff --git a/include/grub/zfs/zio.h b/include/grub/zfs/zio.h
+index b1c46da..8fad2cc 100644
+--- a/include/grub/zfs/zio.h
++++ b/include/grub/zfs/zio.h
+@@ -88,6 +88,7 @@ enum zio_compress {
+ ZIO_COMPRESS_GZIP8,
+ ZIO_COMPRESS_GZIP9,
+ ZIO_COMPRESS_ZLE,
++ ZIO_COMPRESS_LZ4,
+ ZIO_COMPRESS_FUNCTIONS
+ };
+
+diff --git a/po/POTFILES.in b/po/POTFILES.in
+index 987b37a..c55d9e3 100644
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -173,6 +173,7 @@
+ ./grub-core/fs/zfs/zfs_fletcher.c
+ ./grub-core/fs/zfs/zfsinfo.c
+ ./grub-core/fs/zfs/zfs_lzjb.c
++./grub-core/fs/zfs/zfs_lz4.c
+ ./grub-core/fs/zfs/zfs_sha256.c
+ ./grub-core/gdb/cstub.c
+ ./grub-core/gdb/gdb.c
diff --git a/sys-boot/grub/files/grub-2.00-zfs-feature-flag-support.patch b/sys-boot/grub/files/grub-2.00-zfs-feature-flag-support.patch
new file mode 100644
index 00000000..998dc073
--- /dev/null
+++ b/sys-boot/grub/files/grub-2.00-zfs-feature-flag-support.patch
@@ -0,0 +1,1017 @@
+ZFS Feature Flag Support
+
+This is a monolithic version of the following commits:
+
+https://github.com/maxximino/grub2/commit/31a32560fd7948ae5ff5c63105d7c068de7890c8
+https://github.com/maxximino/grub2/commit/595d76e8ca0690a963f5533689de8db54ef07e75
+https://github.com/maxximino/grub2/commit/58344034e40218b20500fa2936eb4d7d019e1e88
+https://github.com/maxximino/grub2/commit/f98cb078abab2c14bb0766b5a0ceb055683dab81
+https://github.com/maxximino/grub2/commit/f12806f43a969a654dee7bb89b2e8fd5c42f0e2e
+
+A minor change was made to account for d8a0feb6 from upstream. This change
+prevents a compile time failure that is caused by a change in the callback
+interface used by mzap_interate().
+
+The initial feature flag support patches were written by Delphix while the LZ4
+support was written by Saso Kiselkov. The work porting this to GRUB2 was done
+by Massimo Maggi, while the adaption to Gentoo's GRUB2 package was done by
+Richard Yao.
+
+diff --git a/Makefile.util.def b/Makefile.util.def
+index b80187c..1bf3038 100644
+--- a/Makefile.util.def
++++ b/Makefile.util.def
+@@ -95,6 +95,7 @@ library = {
+ common = grub-core/fs/zfs/zfs.c;
+ common = grub-core/fs/zfs/zfsinfo.c;
+ common = grub-core/fs/zfs/zfs_lzjb.c;
++ common = grub-core/fs/zfs/zfs_lz4.c;
+ common = grub-core/fs/zfs/zfs_sha256.c;
+ common = grub-core/fs/zfs/zfs_fletcher.c;
+ common = grub-core/lib/envblk.c;
+diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
+index 39e77a4..1550b90 100644
+--- a/grub-core/Makefile.core.def
++++ b/grub-core/Makefile.core.def
+@@ -1186,6 +1186,7 @@ module = {
+ name = zfs;
+ common = fs/zfs/zfs.c;
+ common = fs/zfs/zfs_lzjb.c;
++ common = fs/zfs/zfs_lz4.c;
+ common = fs/zfs/zfs_sha256.c;
+ common = fs/zfs/zfs_fletcher.c;
+ };
+diff --git a/grub-core/fs/zfs/zfs.c b/grub-core/fs/zfs/zfs.c
+index ba0554a..de31e6c 100644
+--- a/grub-core/fs/zfs/zfs.c
++++ b/grub-core/fs/zfs/zfs.c
+@@ -2,6 +2,7 @@
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2009,2010,2011 Free Software Foundation, Inc.
+ * Copyright 2010 Sun Microsystems, Inc.
++ * Copyright (c) 2012 by Delphix. All rights reserved.
+ *
+ * GRUB is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+@@ -153,11 +154,13 @@ ZAP_LEAF_ENTRY(zap_leaf_phys_t *l, int bs, int idx)
+
+
+ /*
+- * Decompression Entry - lzjb
++ * Decompression Entry - lzjb & lz4
+ */
+
+ extern grub_err_t lzjb_decompress (void *, void *, grub_size_t, grub_size_t);
+
++extern grub_err_t lz4_decompress (void *, void *, grub_size_t, grub_size_t);
++
+ typedef grub_err_t zfs_decomp_func_t (void *s_start, void *d_start,
+ grub_size_t s_len, grub_size_t d_len);
+ typedef struct decomp_entry
+@@ -263,6 +266,19 @@ grub_crypto_cipher_handle_t (*grub_zfs_load_key) (const struct grub_zfs_key *key
+ grub_size_t keysize,
+ grub_uint64_t salt,
+ grub_uint64_t algo) = NULL;
++/*
++ * List of pool features that the grub implementation of ZFS supports for
++ * read. Note that features that are only required for write do not need
++ * to be listed here since grub opens pools in read-only mode.
++ */
++static const char *spa_feature_names[] = {
++ "org.illumos:lz4_compress",NULL
++};
++
++static int
++check_feature(const char *name, grub_uint64_t val);
++static int
++check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data );
+
+ static grub_err_t
+ zlib_decompress (void *s, void *d,
+@@ -322,6 +338,7 @@ static decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = {
+ {"gzip-8", zlib_decompress}, /* ZIO_COMPRESS_GZIP8 */
+ {"gzip-9", zlib_decompress}, /* ZIO_COMPRESS_GZIP9 */
+ {"zle", zle_decompress}, /* ZIO_COMPRESS_ZLE */
++ {"lz4", lz4_decompress}, /* ZIO_COMPRESS_LZ4 */
+ };
+
+ static grub_err_t zio_read_data (blkptr_t * bp, grub_zfs_endian_t endian,
+@@ -482,15 +499,11 @@ uberblock_verify (uberblock_phys_t * ub, grub_uint64_t offset,
+
+ if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_LITTLE_ENDIAN)
+ == UBERBLOCK_MAGIC
+- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0
+- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN)
+- <= SPA_VERSION)
+- endian = GRUB_ZFS_LITTLE_ENDIAN;
++ && SPA_VERSION_IS_SUPPORTED(grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN)))
++ endian = GRUB_ZFS_LITTLE_ENDIAN;
+
+ if (grub_zfs_to_cpu64 (uber->ub_magic, GRUB_ZFS_BIG_ENDIAN) == UBERBLOCK_MAGIC
+- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0
+- && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN)
+- <= SPA_VERSION)
++ && SPA_VERSION_IS_SUPPORTED(grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN)))
+ endian = GRUB_ZFS_BIG_ENDIAN;
+
+ if (endian == GRUB_ZFS_UNKNOWN_ENDIAN)
+@@ -764,6 +777,155 @@ fill_vdev_info (struct grub_zfs_data *data,
+ }
+
+ /*
++ * For a given XDR packed nvlist, verify the first 4 bytes and move on.
++ *
++ * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
++ *
++ * encoding method/host endian (4 bytes)
++ * nvl_version (4 bytes)
++ * nvl_nvflag (4 bytes)
++ * encoded nvpairs:
++ * encoded size of the nvpair (4 bytes)
++ * decoded size of the nvpair (4 bytes)
++ * name string size (4 bytes)
++ * name string data (sizeof(NV_ALIGN4(string))
++ * data type (4 bytes)
++ * # of elements in the nvpair (4 bytes)
++ * data
++ * 2 zero's for the last nvpair
++ * (end of the entire list) (8 bytes)
++ *
++ */
++
++/*
++ * The nvlist_next_nvpair() function returns a handle to the next nvpair in the
++ * list following nvpair. If nvpair is NULL, the first pair is returned. If
++ * nvpair is the last pair in the nvlist, NULL is returned.
++ */
++static const char *
++nvlist_next_nvpair(const char *nvl, const char *nvpair)
++{
++ const char *nvp;
++ int encode_size;
++ int name_len;
++ if (nvl == NULL)
++ return (NULL);
++
++ if (nvpair == NULL) {
++ /* skip over header, nvl_version and nvl_nvflag */
++ nvpair = nvl + 4 * 3;
++ } else {
++ /* skip to the next nvpair */
++ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair));
++ nvpair += encode_size;
++ }
++ /* 8 bytes of 0 marks the end of the list */
++ if (*(grub_uint64_t*)nvpair == 0)
++ return (NULL);
++ /*consistency checks*/
++ if (nvpair + 4 * 3 >= nvl + VDEV_PHYS_SIZE)
++ {
++ grub_dprintf ("zfs", "nvlist overflow\n");
++ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
++ return (NULL);
++ }
++ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvpair));
++
++ nvp = nvpair + 4*2;
++ name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
++ nvp += 4;
++
++ nvp = nvp + ((name_len + 3) & ~3); // align
++ if (nvp + 4 >= nvl + VDEV_PHYS_SIZE
++ || encode_size < 0
++ || nvp + 4 + encode_size > nvl + VDEV_PHYS_SIZE)
++ {
++ grub_dprintf ("zfs", "nvlist overflow\n");
++ grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
++ return (NULL);
++ }
++ /* end consistency checks */
++
++ return (nvpair);
++}
++/*
++ * This function returns 0 on success and 1 on failure. On success, a string
++ * containing the name of nvpair is saved in buf.
++ */
++static int
++nvpair_name(const char *nvp, char **buf, int* buflen)
++{
++ int len;
++
++ /* skip over encode/decode size */
++ nvp += 4 * 2;
++
++ len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
++ nvp=nvp+4;
++
++ *buf=(char*)nvp;
++ *buflen=len;
++
++ return (0);
++}
++/*
++ * This function retrieves the value of the nvpair in the form of enumerated
++ * type data_type_t.
++ */
++static int
++nvpair_type(const char *nvp)
++{
++ int name_len, type;
++
++ /* skip over encode/decode size */
++ nvp += 4 * 2;
++
++ /* skip over name_len */
++ name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
++ nvp += 4;
++
++ /* skip over name */
++ nvp = nvp + ((name_len + 3) & ~3); /* align */
++
++ type = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
++
++ return (type);
++}
++static int
++nvpair_value(const char *nvp,char **val,
++ grub_size_t *size_out, grub_size_t *nelm_out)
++{
++ int name_len,nelm,encode_size;
++
++ /* skip over encode/decode size */
++ encode_size = grub_be_to_cpu32 (grub_get_unaligned32(nvp));
++ nvp += 8;
++
++ /* skip over name_len */
++ name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
++ nvp += 4;
++
++ /* skip over name */
++ nvp = nvp + ((name_len + 3) & ~3); /* align */
++
++ /* skip over type */
++ nvp += 4;
++ nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvp));
++ nvp +=4;
++ if (nelm < 1)
++ {
++ grub_error (GRUB_ERR_BAD_FS, "empty nvpair");
++ return 0;
++ }
++ *val = (char *) nvp;
++ *size_out = encode_size;
++ if (nelm_out)
++ *nelm_out = nelm;
++
++ return 1;
++}
++
++/*
+ * Check the disk label information and retrieve needed vdev name-value pairs.
+ *
+ */
+@@ -773,7 +935,7 @@ check_pool_label (struct grub_zfs_data *data,
+ int *inserted)
+ {
+ grub_uint64_t pool_state, txg = 0;
+- char *nvlist;
++ char *nvlist,*features;
+ #if 0
+ char *nv;
+ #endif
+@@ -837,13 +999,13 @@ check_pool_label (struct grub_zfs_data *data,
+ }
+ grub_dprintf ("zfs", "check 8 passed\n");
+
+- if (version > SPA_VERSION)
++ if (!SPA_VERSION_IS_SUPPORTED(version))
+ {
+ grub_free (nvlist);
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "too new version %llu > %llu",
+ (unsigned long long) version,
+- (unsigned long long) SPA_VERSION);
++ (unsigned long long) SPA_VERSION_BEFORE_FEATURES);
+ }
+ grub_dprintf ("zfs", "check 9 passed\n");
+
+@@ -893,7 +1055,30 @@ check_pool_label (struct grub_zfs_data *data,
+ grub_free (nv);
+ }
+ grub_dprintf ("zfs", "check 10 passed\n");
+-
++ if ((features=grub_zfs_nvlist_lookup_nvlist(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ)))
++ {
++ const char *nvp=NULL;
++ char *name = grub_zalloc(51);
++ char *nameptr;
++ int namelen;
++ while ((nvp = nvlist_next_nvpair(features, nvp)) != NULL)
++ {
++ nvpair_name(nvp, &nameptr,&namelen);
++ if(namelen > 50){namelen=50;}
++ grub_strncpy(name,nameptr,namelen);
++ name[namelen]=0;
++ grub_dprintf("zfs","namelen=%u str=%s\n",namelen,name);
++ if (check_feature(name,1) != 0)
++ {
++ grub_dprintf("zfs","feature missing in check_pool_label:%s\n",name);
++ err= grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET," check_pool_label missing feature '%s' for read",name);
++ grub_free(name);
++ return err;
++ }
++ }
++ grub_free(name);
++ }
++ grub_dprintf ("zfs", "check 12 passed (feature flags)\n");
+ grub_free (nvlist);
+
+ return GRUB_ERR_NONE;
+@@ -3034,34 +3219,14 @@ dnode_get_fullpath (const char *fullpath, struct subvolume *subvol,
+ return err;
+ }
+
+-/*
+- * For a given XDR packed nvlist, verify the first 4 bytes and move on.
+- *
+- * An XDR packed nvlist is encoded as (comments from nvs_xdr_create) :
+- *
+- * encoding method/host endian (4 bytes)
+- * nvl_version (4 bytes)
+- * nvl_nvflag (4 bytes)
+- * encoded nvpairs:
+- * encoded size of the nvpair (4 bytes)
+- * decoded size of the nvpair (4 bytes)
+- * name string size (4 bytes)
+- * name string data (sizeof(NV_ALIGN4(string))
+- * data type (4 bytes)
+- * # of elements in the nvpair (4 bytes)
+- * data
+- * 2 zero's for the last nvpair
+- * (end of the entire list) (8 bytes)
+- *
+- */
+-
+ static int
+ nvlist_find_value (const char *nvlist_in, const char *name,
+ int valtype, char **val,
+ grub_size_t *size_out, grub_size_t *nelm_out)
+ {
+- int name_len, type, encode_size;
+- const char *nvpair, *nvp_name, *nvlist = nvlist_in;
++ int name_len, type ;
++ const char *nvpair=NULL,*nvlist=nvlist_in;
++ char *nvp_name;
+
+ /* Verify if the 1st and 2nd byte in the nvlist are valid. */
+ /* NOTE: independently of what endianness header announces all
+@@ -3074,62 +3239,18 @@ nvlist_find_value (const char *nvlist_in, const char *name,
+ return 0;
+ }
+
+- /* skip the header, nvl_version, and nvl_nvflag */
+- nvlist = nvlist + 4 * 3;
+ /*
+ * Loop thru the nvpair list
+ * The XDR representation of an integer is in big-endian byte order.
+ */
+- while ((encode_size = grub_be_to_cpu32 (grub_get_unaligned32 (nvlist))))
++ while ((nvpair=nvlist_next_nvpair(nvlist,nvpair)))
+ {
+- int nelm;
+-
+- if (nvlist + 4 * 4 >= nvlist_in + VDEV_PHYS_SIZE)
+- {
+- grub_dprintf ("zfs", "nvlist overflow\n");
+- grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
+- return 0;
+- }
+-
+- nvpair = nvlist + 4 * 2; /* skip the encode/decode size */
+-
+- name_len = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
+- nvpair += 4;
+-
+- nvp_name = nvpair;
+- nvpair = nvpair + ((name_len + 3) & ~3); /* align */
+-
+- if (nvpair + 8 >= nvlist_in + VDEV_PHYS_SIZE
+- || encode_size < 0
+- || nvpair + 8 + encode_size > nvlist_in + VDEV_PHYS_SIZE)
++ nvpair_name(nvpair,&nvp_name,&name_len);
++ type = nvpair_type(nvpair);
++ if ((grub_strncmp (nvp_name, name, grub_strlen(name)) == 0) && type == valtype)
+ {
+- grub_dprintf ("zfs", "nvlist overflow\n");
+- grub_error (GRUB_ERR_BAD_FS, "incorrect nvlist");
+- return 0;
++ return nvpair_value(nvpair,val,size_out,nelm_out);
+ }
+-
+- type = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
+- nvpair += 4;
+-
+- nelm = grub_be_to_cpu32 (grub_get_unaligned32 (nvpair));
+- if (nelm < 1)
+- {
+- grub_error (GRUB_ERR_BAD_FS, "empty nvpair");
+- return 0;
+- }
+-
+- nvpair += 4;
+-
+- if ((grub_strncmp (nvp_name, name, name_len) == 0) && type == valtype)
+- {
+- *val = (char *) nvpair;
+- *size_out = encode_size;
+- if (nelm_out)
+- *nelm_out = nelm;
+- return 1;
+- }
+-
+- nvlist += encode_size; /* goto the next nvpair */
+ }
+ return 0;
+ }
+@@ -3386,6 +3507,10 @@ zfs_mount (grub_device_t dev)
+ return NULL;
+ }
+
++ if (ub->ub_version >= SPA_VERSION_FEATURES &&
++ check_mos_features(&((objset_phys_t *) osp)->os_meta_dnode,ub_endian, data) != 0)
++ return NULL;
++
+ /* Got the MOS. Save it at the memory addr MOS. */
+ grub_memmove (&(data->mos.dn), &((objset_phys_t *) osp)->os_meta_dnode,
+ DNODE_SIZE);
+@@ -3910,6 +4035,64 @@ grub_zfs_dir (grub_device_t device, const char *path,
+ return grub_errno;
+ }
+
++static int
++check_feature(const char *name, grub_uint64_t val)
++{
++ int i;
++ if(val ==0) return 0;
++ if(*name==0) return 0;
++ for (i = 0; spa_feature_names[i] != NULL; i++)
++ {
++ if (grub_strcmp(name, spa_feature_names[i]) == 0)
++ return 0;
++ }
++ grub_printf("missing feature for read '%s'\n",name);
++ return 1;
++}
++
++/*
++ * Checks whether the MOS features that are active are supported by this
++ * (GRUB's) implementation of ZFS.
++ *
++ * Return:
++ * 0: Success.
++ * errnum: Failure.
++ */
++
++static int
++check_mos_features(dnode_phys_t *mosmdn_phys,grub_zfs_endian_t endian,struct grub_zfs_data* data )
++{
++ grub_uint64_t objnum;
++ grub_uint8_t errnum = 0;
++ dnode_end_t dn,mosmdn;
++ mzap_phys_t* mzp;
++ grub_zfs_endian_t endianzap;
++ int size;
++ grub_memmove(&(mosmdn.dn),mosmdn_phys,sizeof(dnode_phys_t));
++ mosmdn.endian=endian;
++ if ((errnum = dnode_get(&mosmdn, DMU_POOL_DIRECTORY_OBJECT,
++ DMU_OT_OBJECT_DIRECTORY, &dn,data)) != 0)
++ return (errnum);
++
++ /*
++ * Find the object number for 'features_for_read' and retrieve its
++ * corresponding dnode. Note that we don't check features_for_write
++ * because GRUB is not opening the pool for write.
++ */
++ if ((errnum = zap_lookup(&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data,0)) != 0)
++ return (errnum);
++
++ if ((errnum = dnode_get(&mosmdn, objnum, DMU_OTN_ZAP_METADATA, &dn, data)) != 0)
++ return (errnum);
++
++ if ((errnum = dmu_read(&dn, 0, (void**)&mzp, &endianzap,data)) != 0)
++ return (errnum);
++
++ size = grub_zfs_to_cpu16 (dn.dn.dn_datablkszsec, dn.endian) << SPA_MINBLOCKSHIFT;
++ return (mzap_iterate(mzp,endianzap, size, check_feature));
++}
++
++
+ #ifdef GRUB_UTIL
+ static grub_err_t
+ grub_zfs_embed (grub_device_t device __attribute__ ((unused)),
+diff --git a/grub-core/fs/zfs/zfs_lz4.c b/grub-core/fs/zfs/zfs_lz4.c
+new file mode 100644
+index 0000000..f199434
+--- /dev/null
++++ b/grub-core/fs/zfs/zfs_lz4.c
+@@ -0,0 +1,321 @@
++/*
++ * LZ4 - Fast LZ compression algorithm
++ * Header File
++ * Copyright (C) 2011-2013, Yann Collet.
++ * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions are
++ * met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above
++ * copyright notice, this list of conditions and the following disclaimer
++ * in the documentation and/or other materials provided with the
++ * distribution.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * You can contact the author at :
++ * - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
++ * - LZ4 source repository : http://code.google.com/p/lz4/
++ */
++
++#include <grub/err.h>
++#include <grub/mm.h>
++#include <grub/misc.h>
++#include <grub/types.h>
++
++static int LZ4_uncompress_unknownOutputSize(const char *source, char *dest,
++ int isize, int maxOutputSize);
++
++/*
++ * CPU Feature Detection
++ */
++
++/* 32 or 64 bits ? */
++#if (defined(__x86_64__) || defined(__x86_64) || defined(__amd64__) || \
++ defined(__amd64) || defined(__ppc64__) || defined(_WIN64) || \
++ defined(__LP64__) || defined(_LP64))
++#define LZ4_ARCH64 1
++#else
++#define LZ4_ARCH64 0
++#endif
++
++/*
++ * Little Endian or Big Endian?
++ * Note: overwrite the below #define if you know your architecture endianess.
++ */
++#if (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || \
++ defined(_BIG_ENDIAN) || defined(_ARCH_PPC) || defined(__PPC__) || \
++ defined(__PPC) || defined(PPC) || defined(__powerpc__) || \
++ defined(__powerpc) || defined(powerpc) || \
++ ((defined(__BYTE_ORDER__)&&(__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))))
++#define LZ4_BIG_ENDIAN 1
++#else
++ /*
++ * Little Endian assumed. PDP Endian and other very rare endian format
++ * are unsupported.
++ */
++#endif
++
++/*
++ * Compiler Options
++ */
++
++#if __STDC_VERSION__ >= 199901L /* C99 */
++/* "restrict" is a known keyword */
++#else
++/* Disable restrict */
++#ifndef restrict
++#define restrict /* Only if somebody already didn't take care of that.*/
++#endif
++#endif
++
++#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
++
++#define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) \
++ | (((x) & 0xffu) << 8)))
++
++#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
++#define expect(expr, value) (__builtin_expect((expr), (value)))
++#else
++#define expect(expr, value) (expr)
++#endif
++
++#define likely(expr) expect((expr) != 0, 1)
++#define unlikely(expr) expect((expr) != 0, 0)
++
++/* Basic types */
++#define BYTE grub_uint8_t
++#define U16 grub_uint16_t
++#define U32 grub_uint32_t
++#define S32 grub_int32_t
++#define U64 grub_uint64_t
++typedef grub_size_t size_t;
++
++typedef struct _U16_S {
++ U16 v;
++} U16_S;
++typedef struct _U32_S {
++ U32 v;
++} U32_S;
++typedef struct _U64_S {
++ U64 v;
++} U64_S;
++
++#define A64(x) (((U64_S *)(x))->v)
++#define A32(x) (((U32_S *)(x))->v)
++#define A16(x) (((U16_S *)(x))->v)
++
++/*
++ * Constants
++ */
++#define MINMATCH 4
++
++#define COPYLENGTH 8
++#define LASTLITERALS 5
++
++#define ML_BITS 4
++#define ML_MASK ((1U<<ML_BITS)-1)
++#define RUN_BITS (8-ML_BITS)
++#define RUN_MASK ((1U<<RUN_BITS)-1)
++
++/*
++ * Architecture-specific macros
++ */
++#if LZ4_ARCH64
++#define STEPSIZE 8
++#define UARCH U64
++#define AARCH A64
++#define LZ4_COPYSTEP(s, d) A64(d) = A64(s); d += 8; s += 8;
++#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d)
++#define LZ4_SECURECOPY(s, d, e) if (d < e) LZ4_WILDCOPY(s, d, e)
++#define HTYPE U32
++#define INITBASE(base) const BYTE* const base = ip
++#else
++#define STEPSIZE 4
++#define UARCH U32
++#define AARCH A32
++#define LZ4_COPYSTEP(s, d) A32(d) = A32(s); d += 4; s += 4;
++#define LZ4_COPYPACKET(s, d) LZ4_COPYSTEP(s, d); LZ4_COPYSTEP(s, d);
++#define LZ4_SECURECOPY LZ4_WILDCOPY
++#define HTYPE const BYTE*
++#define INITBASE(base) const int base = 0
++#endif
++
++#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE))
++#define LZ4_READ_LITTLEENDIAN_16(d, s, p) \
++ { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; }
++#define LZ4_WRITE_LITTLEENDIAN_16(p, i) \
++ { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p += 2; }
++#else
++#define LZ4_READ_LITTLEENDIAN_16(d, s, p) { d = (s) - A16(p); }
++#define LZ4_WRITE_LITTLEENDIAN_16(p, v) { A16(p) = v; p += 2; }
++#endif
++
++/* Macros */
++#define LZ4_WILDCOPY(s, d, e) do { LZ4_COPYPACKET(s, d) } while (d < e);
++
++/* Decompression functions */
++grub_err_t
++lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len);
++
++grub_err_t
++lz4_decompress(void *s_start, void *d_start, size_t s_len, size_t d_len)
++{
++ const BYTE *src = s_start;
++ U32 bufsiz = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) |
++ src[3];
++
++ /* invalid compressed buffer size encoded at start */
++ if (bufsiz + 4 > s_len)
++ return grub_error(GRUB_ERR_BAD_FS,"lz4 decompression failed.");
++
++ /*
++ * Returns 0 on success (decompression function returned non-negative)
++ * and appropriate error on failure (decompression function returned negative).
++ */
++ return (LZ4_uncompress_unknownOutputSize((char*)s_start + 4, d_start, bufsiz,
++ d_len) < 0)?grub_error(GRUB_ERR_BAD_FS,"lz4 decompression failed."):0;
++}
++
++static int
++LZ4_uncompress_unknownOutputSize(const char *source,
++ char *dest, int isize, int maxOutputSize)
++{
++ /* Local Variables */
++ const BYTE *restrict ip = (const BYTE *) source;
++ const BYTE *const iend = ip + isize;
++ const BYTE *restrict ref;
++
++ BYTE *restrict op = (BYTE *) dest;
++ BYTE *const oend = op + maxOutputSize;
++ BYTE *cpy;
++
++ size_t dec[] = { 0, 3, 2, 3, 0, 0, 0, 0 };
++
++ /* Main Loop */
++ while (ip < iend) {
++ BYTE token;
++ int length;
++
++ /* get runlength */
++ token = *ip++;
++ if ((length = (token >> ML_BITS)) == RUN_MASK) {
++ int s = 255;
++ while ((ip < iend) && (s == 255)) {
++ s = *ip++;
++ length += s;
++ }
++ }
++ /* copy literals */
++ cpy = op + length;
++ if ((cpy > oend - COPYLENGTH) ||
++ (ip + length > iend - COPYLENGTH)) {
++ if (cpy > oend)
++ /*
++ * Error: request to write beyond destination
++ * buffer.
++ */
++ goto _output_error;
++ if (ip + length > iend)
++ /*
++ * Error : request to read beyond source
++ * buffer.
++ */
++ goto _output_error;
++ grub_memcpy(op, ip, length);
++ op += length;
++ ip += length;
++ if (ip < iend)
++ /* Error : LZ4 format violation */
++ goto _output_error;
++ /* Necessarily EOF, due to parsing restrictions. */
++ break;
++ }
++ LZ4_WILDCOPY(ip, op, cpy);
++ ip -= (op - cpy);
++ op = cpy;
++
++ /* get offset */
++ LZ4_READ_LITTLEENDIAN_16(ref, cpy, ip);
++ ip += 2;
++ if (ref < (BYTE * const) dest)
++ /*
++ * Error: offset creates reference outside of
++ * destination buffer.
++ */
++ goto _output_error;
++
++ /* get matchlength */
++ if ((length = (token & ML_MASK)) == ML_MASK) {
++ while (ip < iend) {
++ int s = *ip++;
++ length += s;
++ if (s == 255)
++ continue;
++ break;
++ }
++ }
++ /* copy repeated sequence */
++ if unlikely(op - ref < STEPSIZE) {
++#if LZ4_ARCH64
++ size_t dec2table[] = { 0, 0, 0, -1, 0, 1, 2, 3 };
++ size_t dec2 = dec2table[op - ref];
++#else
++ const int dec2 = 0;
++#endif
++ *op++ = *ref++;
++ *op++ = *ref++;
++ *op++ = *ref++;
++ *op++ = *ref++;
++ ref -= dec[op - ref];
++ A32(op) = A32(ref);
++ op += STEPSIZE - 4;
++ ref -= dec2;
++ } else {
++ LZ4_COPYSTEP(ref, op);
++ }
++ cpy = op + length - (STEPSIZE - 4);
++ if (cpy > oend - COPYLENGTH) {
++ if (cpy > oend)
++ /*
++ * Error: request to write outside of
++ * destination buffer.
++ */
++ goto _output_error;
++ LZ4_SECURECOPY(ref, op, (oend - COPYLENGTH));
++ while (op < cpy)
++ *op++ = *ref++;
++ op = cpy;
++ if (op == oend)
++ /*
++ * Check EOF (should never happen, since last
++ * 5 bytes are supposed to be literals).
++ */
++ break;
++ continue;
++ }
++ LZ4_SECURECOPY(ref, op, cpy);
++ op = cpy; /* correction */
++ }
++
++ /* end of decoding */
++ return (int)(((char *)op) - dest);
++
++ /* write overflow error detected */
++ _output_error:
++ return (int)(-(((char *)ip) - source));
++}
+diff --git a/grub-core/fs/zfs/zfsinfo.c b/grub-core/fs/zfs/zfsinfo.c
+index fdb587a..c96bf21 100644
+--- a/grub-core/fs/zfs/zfsinfo.c
++++ b/grub-core/fs/zfs/zfsinfo.c
+@@ -132,21 +132,31 @@ print_vdev_info (char *nvlist, int tab)
+ grub_free (path);
+ return GRUB_ERR_NONE;
+ }
++ char is_mirror=(grub_strcmp(type,VDEV_TYPE_MIRROR) == 0);
++ char is_raidz=(grub_strcmp(type,VDEV_TYPE_RAIDZ) == 0);
+
+- if (grub_strcmp (type, VDEV_TYPE_MIRROR) == 0)
++ if (is_mirror || is_raidz)
+ {
+ int nelm, i;
+
+ nelm = grub_zfs_nvlist_lookup_nvlist_array_get_nelm
+ (nvlist, ZPOOL_CONFIG_CHILDREN);
+
++ if(is_mirror){
++ grub_puts_ (N_("This VDEV is a mirror"));
++ }
++ else if(is_raidz){
++ grub_uint64_t parity;
++ grub_zfs_nvlist_lookup_uint64(nvlist,"nparity",&parity);
++ grub_printf_ (N_("This VDEV is a RAIDZ%llu\n"),(unsigned long long)parity);
++ }
+ print_tabs (tab);
+ if (nelm <= 0)
+ {
+- grub_puts_ (N_("Incorrect mirror"));
++ grub_puts_ (N_("Incorrect VDEV"));
+ return GRUB_ERR_NONE;
+ }
+- grub_printf_ (N_("Mirror with %d children\n"), nelm);
++ grub_printf_ (N_("VDEV with %d children\n"), nelm);
+ print_state (nvlist, tab);
+ for (i = 0; i < nelm; i++)
+ {
+@@ -162,14 +172,14 @@ print_vdev_info (char *nvlist, int tab)
+ total element number. And the number itself is fine,
+ only the element isn't.
+ */
+- grub_printf_ (N_("Mirror element number %d isn't correct\n"), i);
++ grub_printf_ (N_("VDEV element number %d isn't correct\n"), i);
+ continue;
+ }
+
+ /* TRANSLATORS: it's the element carying the number %d, not
+ total element number. This is used in enumeration
+ "Element number 1", "Element number 2", ... */
+- grub_printf_ (N_("Mirror element number %d:\n"), i);
++ grub_printf_ (N_("VDEV element number %d:\n"), i);
+ print_vdev_info (child, tab + 1);
+
+ grub_free (child);
+diff --git a/include/grub/zfs/dmu.h b/include/grub/zfs/dmu.h
+index 8fc6dc5..4ad616c 100644
+--- a/include/grub/zfs/dmu.h
++++ b/include/grub/zfs/dmu.h
+@@ -22,6 +22,39 @@
+
+ #ifndef _SYS_DMU_H
+ #define _SYS_DMU_H
++#define B_FALSE 0
++#define B_TRUE 1
++
++#define DMU_OT_NEWTYPE 0x80
++#define DMU_OT_METADATA 0x40
++#define DMU_OT_BYTESWAP_MASK 0x3f
++
++#define DMU_OT(byteswap, metadata) \
++ (DMU_OT_NEWTYPE | \
++ ((metadata) ? DMU_OT_METADATA : 0) | \
++ ((byteswap) & DMU_OT_BYTESWAP_MASK))
++
++#define DMU_OT_IS_VALID(ot) (((ot) & DMU_OT_NEWTYPE) ? \
++ ((ot) & DMU_OT_BYTESWAP_MASK) < DMU_BSWAP_NUMFUNCS : \
++ (ot) < DMU_OT_NUMTYPES)
++
++#define DMU_OT_IS_METADATA(ot) (((ot) & DMU_OT_NEWTYPE) ? \
++ ((ot) & DMU_OT_METADATA) : \
++ dmu_ot[(ot)].ot_metadata)
++
++typedef enum dmu_object_byteswap {
++ DMU_BSWAP_UINT8,
++ DMU_BSWAP_UINT16,
++ DMU_BSWAP_UINT32,
++ DMU_BSWAP_UINT64,
++ DMU_BSWAP_ZAP,
++ DMU_BSWAP_DNODE,
++ DMU_BSWAP_OBJSET,
++ DMU_BSWAP_ZNODE,
++ DMU_BSWAP_OLDACL,
++ DMU_BSWAP_ACL,
++ DMU_BSWAP_NUMFUNCS
++} dmu_object_byteswap_t;
+
+ /*
+ * This file describes the interface that the DMU provides for its
+@@ -89,7 +122,17 @@ typedef enum dmu_object_type {
+ DMU_OT_SA_ATTR_REGISTRATION, /* ZAP */
+ DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */
+ DMU_OT_DSL_KEYCHAIN = 54,
+- DMU_OT_NUMTYPES
++ DMU_OT_NUMTYPES,
++ DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE),
++ DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE),
++ DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE),
++ DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE),
++ DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE),
++ DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE),
++ DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE),
++ DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE),
++ DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE),
++ DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE),
+ } dmu_object_type_t;
+
+ typedef enum dmu_objset_type {
+@@ -116,5 +159,6 @@ typedef enum dmu_objset_type {
+ #define DMU_POOL_HISTORY "history"
+ #define DMU_POOL_PROPS "pool_props"
+ #define DMU_POOL_L2CACHE "l2cache"
++#define DMU_POOL_FEATURES_FOR_READ "features_for_read"
+
+ #endif /* _SYS_DMU_H */
+diff --git a/include/grub/zfs/zfs.h b/include/grub/zfs/zfs.h
+index e326c8b..761ade7 100644
+--- a/include/grub/zfs/zfs.h
++++ b/include/grub/zfs/zfs.h
+@@ -36,8 +36,13 @@ typedef enum grub_zfs_endian
+ /*
+ * On-disk version number.
+ */
+-#define SPA_VERSION 33ULL
+-
++#define SPA_VERSION_INITIAL 1ULL
++#define SPA_VERSION_BEFORE_FEATURES 33ULL
++#define SPA_VERSION 5000ULL
++#define SPA_VERSION_FEATURES 5000ULL
++#define SPA_VERSION_IS_SUPPORTED(v) \
++ (((v) >= SPA_VERSION_INITIAL && (v) <= SPA_VERSION_BEFORE_FEATURES) || \
++ ((v) >= SPA_VERSION_FEATURES && (v) <= SPA_VERSION))
+ /*
+ * The following are configuration names used in the nvlist describing a pool's
+ * configuration.
+@@ -76,6 +81,7 @@ typedef enum grub_zfs_endian
+ #define ZPOOL_CONFIG_DDT_HISTOGRAM "ddt_histogram"
+ #define ZPOOL_CONFIG_DDT_OBJ_STATS "ddt_object_stats"
+ #define ZPOOL_CONFIG_DDT_STATS "ddt_stats"
++#define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read"
+ /*
+ * The persistent vdev state is stored as separate values rather than a single
+ * 'vdev_state' entry. This is because a device can be in multiple states, such
+diff --git a/include/grub/zfs/zio.h b/include/grub/zfs/zio.h
+index b1c46da..8fad2cc 100644
+--- a/include/grub/zfs/zio.h
++++ b/include/grub/zfs/zio.h
+@@ -88,6 +88,7 @@ enum zio_compress {
+ ZIO_COMPRESS_GZIP8,
+ ZIO_COMPRESS_GZIP9,
+ ZIO_COMPRESS_ZLE,
++ ZIO_COMPRESS_LZ4,
+ ZIO_COMPRESS_FUNCTIONS
+ };
+
+diff --git a/po/POTFILES.in b/po/POTFILES.in
+index 987b37a..c55d9e3 100644
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -173,6 +173,7 @@
+ ./grub-core/fs/zfs/zfs_fletcher.c
+ ./grub-core/fs/zfs/zfsinfo.c
+ ./grub-core/fs/zfs/zfs_lzjb.c
++./grub-core/fs/zfs/zfs_lz4.c
+ ./grub-core/fs/zfs/zfs_sha256.c
+ ./grub-core/gdb/cstub.c
+ ./grub-core/gdb/gdb.c
diff --git a/sys-boot/grub/files/grub.conf.gentoo b/sys-boot/grub/files/grub.conf.gentoo
new file mode 100644
index 00000000..0027099e
--- /dev/null
+++ b/sys-boot/grub/files/grub.conf.gentoo
@@ -0,0 +1,16 @@
+# This is a sample grub.conf for use with Genkernel, per the Gentoo handbook
+# http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?part=1&chap=10#doc_chap2
+# If you are not using Genkernel and you need help creating this file, you
+# should consult the handbook. Alternatively, consult the grub.conf.sample that
+# is included with the Grub documentation.
+
+default 0
+timeout 30
+#splashimage=(hd0,0)/boot/grub/splash.xpm.gz
+
+#title Gentoo Linux 2.6.24-r5
+#root (hd0,0)
+#kernel /boot/kernel-genkernel-x86-2.6.24-gentoo-r5 root=/dev/ram0 real_root=/dev/sda3
+#initrd /boot/initramfs-genkernel-x86-2.6.24-gentoo-r5
+
+# vim:ft=conf:
diff --git a/sys-boot/grub/files/grub.default-2 b/sys-boot/grub/files/grub.default-2
new file mode 100644
index 00000000..60f27303
--- /dev/null
+++ b/sys-boot/grub/files/grub.default-2
@@ -0,0 +1,57 @@
+# Copyright 1999-2012 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/sys-boot/grub/files/grub.default-2,v 1.2 2012/06/28 22:36:53 floppym Exp $
+#
+# To populate all changes in this file you need to regenerate your
+# grub configuration file afterwards:
+# 'grub2-mkconfig -o /boot/grub2/grub.cfg'
+#
+# See the grub info page for documentation on possible variables and
+# their associated values.
+
+GRUB_DEFAULT=saved
+GRUB_DISTRIBUTOR="RogentOS"
+
+GRUB_DEFAULT=0
+GRUB_HIDDEN_TIMEOUT=0
+GRUB_HIDDEN_TIMEOUT_QUIET=true
+GRUB_TIMEOUT=3
+
+GRUB_CMDLINE_LINUX_DEFAULT=""
+GRUB_CMDLINE_LINUX=""
+
+# Uncomment to disable graphical terminal (grub-pc only)
+#GRUB_TERMINAL=console
+
+# The resolution used on graphical terminal.
+# Note that you can use only modes which your graphic card supports via VBE.
+# You can see them in real GRUB with the command `vbeinfo'.
+GRUB_GFXMODE=1024x768
+
+# Path to theme spec txt file.
+# The starfield is by default provided with use truetype.
+# NOTE: when enabling custom theme, ensure you have required font/etc.
+#GRUB_THEME="/boot/grub2/themes/starfield/theme.txt"
+
+# Background image used on graphical terminal.
+# Can be in various bitmap formats.
+GRUB_BACKGROUND="/boot/grub/default-splash.png"
+
+# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to kernel
+#GRUB_DISABLE_LINUX_UUID=true
+
+# Uncomment to disable generation of recovery mode menu entries
+#GRUB_DISABLE_RECOVERY=true
+
+# Boot menu option normal color
+GRUB_COLOR_NORMAL="white/black"
+
+# Boot menu option "highlight" color
+GRUB_COLOR_HIGHLIGHT="magenta/black"
+
+if [ -f "/etc/default/rogentos-grub" ]; then
+ # this file is placed by the RogentOS Installer and contains
+ # custom GRUB_CMDLINE_LINUX parameters created at install
+ # time.
+ . /etc/default/rogentos-grub
+fi
diff --git a/sys-boot/grub/files/grub2-default b/sys-boot/grub/files/grub2-default
new file mode 100644
index 00000000..c93a6e8f
--- /dev/null
+++ b/sys-boot/grub/files/grub2-default
@@ -0,0 +1,62 @@
+# /etc/default/grub
+# If you change this file, run 'grub-mkconfig -o /boot/grub/grub.cfg' afterwards to update
+# /boot/grub/grub.cfg.
+
+GRUB_DEFAULT=saved
+GRUB_DISTRIBUTOR="RogentOS"
+GRUB_HIDDEN_TIMEOUT=0
+GRUB_HIDDEN_TIMEOUT_QUIET=true
+GRUB_TIMEOUT=5
+
+# Add your extra parameters here below
+# Dear user, put your boot flags here ;-)
+GRUB_CMDLINE_LINUX_DEFAULT=""
+# ATTENTION ATTENTION ATTENTION
+# DO NOT EDIT THIS MANUALLY NOR SET IT TO EMPTY IF IT'S ALREADY FILLED WITH
+# SOMETHING (DONE BY THE INSTALLER). REALLY, DON'T !
+GRUB_CMDLINE_LINUX=""
+# ATTENTION ATTENTION ATTENTION
+
+# Uncomment to disable graphical terminal (grub-pc only)
+# GRUB_TERMINAL=console
+
+# The resolution used on graphical terminal
+# note that you can use only modes which your graphic card supports via VBE
+# you can see them in real GRUB with the command `vbeinfo'
+GRUB_GFXMODE=1024x768
+
+# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
+#GRUB_DISABLE_LINUX_UUID=true
+
+# Uncomment to disable generation of recovery mode menu entrys
+# GRUB_DISABLE_LINUX_RECOVERY="false"
+
+# Default wallpaper image path
+GRUB_WALLPAPER="/boot/grub/default-splash.png"
+
+# Boot menu option normal color
+GRUB_COLOR_NORMAL="white/black"
+
+# Boot menu option "highlight" color
+GRUB_COLOR_HIGHLIGHT="magenta/black"
+
+if [ -f "/etc/default/rogentos-grub" ]; then
+ # this file is placed by the RogentOS Installer and contains
+ # custom GRUB_CMDLINE_LINUX parameters created at install
+ # time.
+ source /etc/default/rogentos-grub
+fi
+
+# DO NOT REMOVE THIS IF YOUR GRUB_CMDLINE_LINUX IS EMPTY (BACKWARD COMPAT)
+if [ -z "${GRUB_CMDLINE_LINUX}" ]; then
+ if [ ! -e "/proc/cmdline" ]; then
+ echo "ATTENTION ATTENTION ATTENTION" >&2
+ echo "GRUB_CMDLINE_LINUX is not set inside /etc/default/grub" >&2
+ echo " cannot generate a bootable configuration." >&2
+ else
+ echo "ATTENTION ATTENTION ATTENTION" >&2
+ echo "GRUB_CMDLINE_LINUX is not set inside /etc/default/grub" >&2
+ echo " grub is going to use your /proc/cmdline content" >&2
+ GRUB_CMDLINE_LINUX="`cat /proc/cmdline | sed -e 's#BOOT_IMAGE=.* ro ##g'`"
+ fi
+fi
diff --git a/sys-boot/grub/files/grub2-default-1.99 b/sys-boot/grub/files/grub2-default-1.99
new file mode 100644
index 00000000..acaabfd7
--- /dev/null
+++ b/sys-boot/grub/files/grub2-default-1.99
@@ -0,0 +1,49 @@
+# /etc/default/grub
+# If you change this file, run 'grub-mkconfig -o /boot/grub/grub.cfg' afterwards to update
+# /boot/grub/grub.cfg.
+
+GRUB_DEFAULT=saved
+GRUB_DISTRIBUTOR="RogentOS"
+GRUB_HIDDEN_TIMEOUT=0
+GRUB_HIDDEN_TIMEOUT_QUIET=true
+GRUB_TIMEOUT=5
+GRUB_DISABLE_LINUX_UUID=true
+
+# Add your extra parameters here below
+# Dear user, put your boot flags here ;-)
+GRUB_CMDLINE_LINUX_DEFAULT=""
+# ATTENTION ATTENTION ATTENTION
+# DO NOT EDIT THIS MANUALLY NOR SET IT TO EMPTY IF IT'S ALREADY FILLED WITH
+# SOMETHING (DONE BY THE INSTALLER). REALLY, DON'T !
+GRUB_CMDLINE_LINUX=""
+# ATTENTION ATTENTION ATTENTION
+
+# Uncomment to disable graphical terminal (grub-pc only)
+# GRUB_TERMINAL=console
+
+# The resolution used on graphical terminal
+# note that you can use only modes which your graphic card supports via VBE
+# you can see them in real GRUB with the command `vbeinfo'
+GRUB_GFXMODE=1024x768
+
+# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
+#GRUB_DISABLE_LINUX_UUID=true
+
+# Uncomment to disable generation of recovery mode menu entrys
+# GRUB_DISABLE_LINUX_RECOVERY="false"
+
+# Default wallpaper image path
+GRUB_WALLPAPER="/boot/grub/default-splash.png"
+
+# Boot menu option normal color
+GRUB_COLOR_NORMAL="white/black"
+
+# Boot menu option "highlight" color
+GRUB_COLOR_HIGHLIGHT="magenta/black"
+
+if [ -f "/etc/default/rogentos-grub" ]; then
+ # this file is placed by the RogentOS Installer and contains
+ # custom GRUB_CMDLINE_LINUX parameters created at install
+ # time.
+ . /etc/default/rogentos-grub
+fi
diff --git a/sys-boot/grub/files/splash.xpm.gz b/sys-boot/grub/files/splash.xpm.gz
new file mode 100644
index 00000000..f6836bda
--- /dev/null
+++ b/sys-boot/grub/files/splash.xpm.gz
Binary files differ
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/01_uuids_and_lvm_dont_play_along_nicely.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/01_uuids_and_lvm_dont_play_along_nicely.diff
new file mode 100644
index 00000000..c997b845
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/01_uuids_and_lvm_dont_play_along_nicely.diff
@@ -0,0 +1,14 @@
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index c2da413..cbd9d6b 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -36,7 +36,8 @@ case ${GRUB_DEVICE} in
+ esac
+
+ if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
+- || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then
++ || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
++ || [ "`grub-probe -t abstraction --device ${GRUB_DEVICE} | sed -e 's,.*\(lvm\).*,\1,'`" = "lvm" ] ; then
+ LINUX_ROOT_DEVICE=${GRUB_DEVICE}
+ else
+ LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/902_boot_blocklist_hack.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/902_boot_blocklist_hack.diff
new file mode 100644
index 00000000..63caf45e
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/902_boot_blocklist_hack.diff
@@ -0,0 +1,20 @@
+Index: util/i386/pc/grub-setup.c
+===================================================================
+--- util/i386/pc/grub-setup.c (revision 1836)
++++ util/i386/pc/grub-setup.c (working copy)
+@@ -383,6 +383,15 @@
+ grub_disk_cache_invalidate_all ();
+
+ file = grub_file_open (core_path_dev);
++
++ if (grub_errno == GRUB_ERR_FILE_NOT_FOUND)
++ {
++ /* Clean the previous grub_errno */
++ grub_errno = GRUB_ERR_NONE;
++ strcpy (core_path_dev, "/grub/core.img");
++ file = grub_file_open (core_path_dev);
++ }
++
+ if (file)
+ {
+ if (grub_file_size (file) != core_size)
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/904_disable_floppies.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/904_disable_floppies.diff
new file mode 100644
index 00000000..66a41cdc
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/904_disable_floppies.diff
@@ -0,0 +1,28 @@
+
+Author: Robert Millan
+
+An ugly kludge. Should this be merged upstream?
+
+Index: util/hostdisk.c
+===================================================================
+--- util/hostdisk.c (revision 1832)
++++ util/hostdisk.c (working copy)
+@@ -544,6 +544,18 @@
+ continue;
+ }
+
++ if (! strncmp (p, "/dev/fd", sizeof ("/dev/fd") - 1))
++ {
++ char *q = p + sizeof ("/dev/fd") - 1;
++ if (*q >= '0' && *q <= '9')
++ {
++ free (map[drive].drive);
++ map[drive].drive = NULL;
++ grub_util_info ("`%s' looks like a floppy drive, skipping", p);
++ continue;
++ }
++ }
++
+ #ifdef __linux__
+ /* On Linux, the devfs uses symbolic links horribly, and that
+ confuses the interface very much, so use realpath to expand
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/956_loopback_root.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/956_loopback_root.diff
new file mode 100644
index 00000000..ce54872e
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/956_loopback_root.diff
@@ -0,0 +1,139 @@
+Upstream: http://lists.gnu.org/archive/html/grub-devel/2009-09/msg00210.html
+Description: If you set root after running loopback, any attempts to open
+ files on the loopback device resolve the loopback file name relative to the
+ *new* root, not the root at the time loopback was invoked, and so the above
+ recurses until it runs out of stack. This causes problems for Wubi. I think
+ it's fairly clear that only the root that was in place when you ran
+ loopback should be relevant to the loopback file name.
+
+diff -Nur -x '*.orig' -x '*~' grub2-1.97~beta2/disk/loopback.c grub2-1.97~beta2.new/disk/loopback.c
+--- grub2-1.97~beta2/disk/loopback.c 2009-06-10 22:04:23.000000000 +0100
++++ grub2-1.97~beta2.new/disk/loopback.c 2009-09-10 21:42:56.000000000 +0100
+@@ -28,6 +28,7 @@
+ {
+ char *devname;
+ char *filename;
++ grub_file_t file;
+ int has_partitions;
+ struct grub_loopback *next;
+ };
+@@ -61,6 +62,7 @@
+ /* Remove the device from the list. */
+ *prev = dev->next;
+
++ grub_file_close (dev->file);
+ grub_free (dev->devname);
+ grub_free (dev->filename);
+ grub_free (dev);
+@@ -90,9 +92,6 @@
+ if (! file)
+ return grub_errno;
+
+- /* Close the file, the only reason for opening it is validation. */
+- grub_file_close (file);
+-
+ /* First try to replace the old device. */
+ for (newdev = loopback_list; newdev; newdev = newdev->next)
+ if (grub_strcmp (newdev->devname, args[0]) == 0)
+@@ -102,10 +101,12 @@
+ {
+ char *newname = grub_strdup (args[1]);
+ if (! newname)
+- return grub_errno;
++ goto fail;
+
+ grub_free (newdev->filename);
+ newdev->filename = newname;
++ grub_file_close (newdev->file);
++ newdev->file = file;
+
+ /* Set has_partitions when `--partitions' was used. */
+ newdev->has_partitions = state[1].set;
+@@ -116,13 +117,13 @@
+ /* Unable to replace it, make a new entry. */
+ newdev = grub_malloc (sizeof (struct grub_loopback));
+ if (! newdev)
+- return grub_errno;
++ goto fail;
+
+ newdev->devname = grub_strdup (args[0]);
+ if (! newdev->devname)
+ {
+ grub_free (newdev);
+- return grub_errno;
++ goto fail;
+ }
+
+ newdev->filename = grub_strdup (args[1]);
+@@ -130,9 +131,11 @@
+ {
+ grub_free (newdev->devname);
+ grub_free (newdev);
+- return grub_errno;
++ goto fail;
+ }
+
++ newdev->file = file;
++
+ /* Set has_partitions when `--partitions' was used. */
+ newdev->has_partitions = state[1].set;
+
+@@ -141,6 +144,10 @@
+ loopback_list = newdev;
+
+ return 0;
++
++fail:
++ grub_file_close (file);
++ return grub_errno;
+ }
+
+
+@@ -159,7 +166,6 @@
+ static grub_err_t
+ grub_loopback_open (const char *name, grub_disk_t disk)
+ {
+- grub_file_t file;
+ struct grub_loopback *dev;
+
+ for (dev = loopback_list; dev; dev = dev->next)
+@@ -169,29 +175,17 @@
+ if (! dev)
+ return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
+
+- file = grub_file_open (dev->filename);
+- if (! file)
+- return grub_errno;
+-
+ /* Use the filesize for the disk size, round up to a complete sector. */
+- disk->total_sectors = ((file->size + GRUB_DISK_SECTOR_SIZE - 1)
++ disk->total_sectors = ((dev->file->size + GRUB_DISK_SECTOR_SIZE - 1)
+ / GRUB_DISK_SECTOR_SIZE);
+ disk->id = (unsigned long) dev;
+
+ disk->has_partitions = dev->has_partitions;
+- disk->data = file;
++ disk->data = dev->file;
+
+ return 0;
+ }
+
+-static void
+-grub_loopback_close (grub_disk_t disk)
+-{
+- grub_file_t file = (grub_file_t) disk->data;
+-
+- grub_file_close (file);
+-}
+-
+ static grub_err_t
+ grub_loopback_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+@@ -233,7 +227,6 @@
+ .id = GRUB_DISK_DEVICE_LOOPBACK_ID,
+ .iterate = grub_loopback_iterate,
+ .open = grub_loopback_open,
+- .close = grub_loopback_close,
+ .read = grub_loopback_read,
+ .write = grub_loopback_write,
+ .next = 0
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/957_handle_loopback.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/957_handle_loopback.diff
new file mode 100644
index 00000000..0ee868fd
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/957_handle_loopback.diff
@@ -0,0 +1,45 @@
+Ubuntu: needed for Wubi
+Description: Change prepare_grub_to_access_device to handle filesystems
+ loop-mounted on file images.
+UbuntuSpecific: Not inherently. losetup and /proc/mounts are Linux-specific,
+ though, so we might need to refine this before sending it upstream.
+
+diff -Nur -x '*.orig' -x '*~' grub2-1.97~beta3/util/grub-mkconfig_lib.in grub2-1.97~beta3.new/util/grub-mkconfig_lib.in
+--- grub2-1.97~beta3/util/grub-mkconfig_lib.in 2009-09-15 00:23:50.000000000 +0100
++++ grub2-1.97~beta3.new/util/grub-mkconfig_lib.in 2009-09-15 00:31:31.000000000 +0100
+@@ -142,6 +142,20 @@
+ {
+ device=$1
+
++ loop_file=
++ case ${device} in
++ /dev/loop/*|/dev/loop[0-9])
++ loop_file=`losetup ${device} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
++ case $loop_file in
++ /dev/*) ;;
++ *)
++ loop_device=${device}
++ device=`${grub_probe} --target=device "${loop_file}"`
++ ;;
++ esac
++ ;;
++ esac
++
+ # Abstraction modules aren't auto-loaded.
+ abstraction="`${grub_probe} --device ${device} --target=abstraction`"
+ for module in ${abstraction} ; do
+@@ -159,6 +173,14 @@
+ if fs_uuid="`${grub_probe} --device ${device} --target=fs_uuid 2> /dev/null`" ; then
+ echo "search --no-floppy --fs-uuid --set ${fs_uuid}"
+ fi
++
++ if [ "x${loop_file}" != x ]; then
++ loop_mountpoint="$(awk '"'${loop_file}'" ~ "^"$2 && $2 != "/" { print $2 }' /proc/mounts | tail -n1)"
++ if [ "x${loop_mountpoint}" != x ]; then
++ echo "loopback loop0 ${loop_file#$loop_mountpoint}"
++ echo "set root=(loop0)"
++ fi
++ fi
+ }
+
+ grub_file_is_not_garbage ()
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/958_linux_no_loopmount.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/958_linux_no_loopmount.diff
new file mode 100644
index 00000000..9e0dfda9
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/958_linux_no_loopmount.diff
@@ -0,0 +1,20 @@
+Ubuntu: needed for Wubi
+Description: Ignore devices loop-mounted from files in 10_linux.
+UbuntuSpecific: Not inherently, but perhaps we should integrate 10_lupin
+ properly instead.
+
+diff -Nur -x '*.orig' -x '*~' grub2-1.97~beta3/util/grub.d/10_linux.in grub2-1.97~beta3.new/util/grub.d/10_linux.in
+--- grub2-1.97~beta3/util/grub.d/10_linux.in 2009-09-16 17:41:06.000000000 +0100
++++ grub2-1.97~beta3.new/util/grub.d/10_linux.in 2009-09-16 17:44:52.000000000 +0100
+@@ -32,6 +32,11 @@
+ case ${GRUB_DEVICE} in
+ /dev/loop/*|/dev/loop[0-9])
+ GRUB_DEVICE=`losetup ${GRUB_DEVICE} | sed -e "s/^[^(]*(\([^)]\+\)).*/\1/"`
++ # We can't cope with devices loop-mounted from files here.
++ case ${GRUB_DEVICE} in
++ /dev/*) ;;
++ *) exit 0 ;;
++ esac
+ ;;
+ esac
+
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/960_raid_virtio.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/960_raid_virtio.diff
new file mode 100644
index 00000000..3b060ba0
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/960_raid_virtio.diff
@@ -0,0 +1,158 @@
+diff -Nur -x '*.orig' -x '*~' grub2/include/grub/util/getroot.h grub2.new/include/grub/util/getroot.h
+--- grub2/include/grub/util/getroot.h 2009-11-29 18:42:14.000000000 -0800
++++ grub2.new/include/grub/util/getroot.h 2010-02-03 14:38:02.000000000 -0800
+@@ -19,12 +19,15 @@
+ #ifndef GRUB_UTIL_GETROOT_HEADER
+ #define GRUB_UTIL_GETROOT_HEADER 1
+
++#include <sys/types.h>
++
+ enum grub_dev_abstraction_types {
+ GRUB_DEV_ABSTRACTION_NONE,
+ GRUB_DEV_ABSTRACTION_LVM,
+ GRUB_DEV_ABSTRACTION_RAID,
+ };
+
++char *grub_find_device (const char *dir, dev_t dev);
+ char *grub_guess_root_device (const char *dir);
+ char *grub_get_prefix (const char *dir);
+ int grub_util_get_dev_abstraction (const char *os_dev);
+diff -Nur -x '*.orig' -x '*~' grub2/util/getroot.c grub2.new/util/getroot.c
+--- grub2/util/getroot.c 2010-02-01 14:33:16.000000000 -0800
++++ grub2.new/util/getroot.c 2010-02-03 14:38:02.000000000 -0800
+@@ -178,8 +178,8 @@
+
+ #ifdef __MINGW32__
+
+-static char *
+-find_root_device (const char *dir __attribute__ ((unused)),
++char *
++grub_find_device (const char *dir __attribute__ ((unused)),
+ dev_t dev __attribute__ ((unused)))
+ {
+ return 0;
+@@ -187,13 +187,22 @@
+
+ #elif ! defined(__CYGWIN__)
+
+-static char *
+-find_root_device (const char *dir, dev_t dev)
++char *
++grub_find_device (const char *dir, dev_t dev)
+ {
+ DIR *dp;
+ char *saved_cwd;
+ struct dirent *ent;
+
++ if (! dir)
++ {
++#ifdef __CYGWIN__
++ return NULL;
++#else
++ dir = "/dev";
++#endif
++ }
++
+ dp = opendir (dir);
+ if (! dp)
+ return 0;
+@@ -231,7 +240,7 @@
+ /* Find it recursively. */
+ char *res;
+
+- res = find_root_device (ent->d_name, dev);
++ res = grub_find_device (ent->d_name, dev);
+
+ if (res)
+ {
+@@ -334,8 +343,8 @@
+ return serial;
+ }
+
+-static char *
+-find_cygwin_root_device (const char *path, dev_t dev)
++char *
++grub_find_device (const char *path, dev_t dev)
+ {
+ /* No root device for /cygdrive. */
+ if (dev == (DEV_CYGDRIVE_MAJOR << 16))
+@@ -356,7 +365,7 @@
+
+ /* Cygwin returns the partition serial number in stat.st_dev.
+ This is never identical to the device number of the emulated
+- /dev/sdXN device, so above find_root_device () does not work.
++ /dev/sdXN device, so above grub_find_device () does not work.
+ Search the partition with the same serial in boot sector instead. */
+ char devpath[sizeof ("/dev/sda15") + 13]; /* Size + Paranoia. */
+ int d;
+@@ -449,12 +458,12 @@
+
+ #ifdef __CYGWIN__
+ /* Cygwin specific function. */
+- os_dev = find_cygwin_root_device (dir, st.st_dev);
++ os_dev = grub_find_device (dir, st.st_dev);
+
+ #else
+
+ /* This might be truly slow, but is there any better way? */
+- os_dev = find_root_device ("/dev", st.st_dev);
++ os_dev = grub_find_device ("/dev", st.st_dev);
+ #endif
+ #endif /* !__GNU__ */
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/raid.c grub2.new/util/raid.c
+--- grub2/util/raid.c 2010-02-01 14:33:15.000000000 -0800
++++ grub2.new/util/raid.c 2010-02-03 14:39:38.000000000 -0800
+@@ -21,40 +21,19 @@
+ #ifdef __linux__
+ #include <grub/util/misc.h>
+ #include <grub/util/raid.h>
++#include <grub/util/getroot.h>
+
+ #include <string.h>
+ #include <fcntl.h>
+ #include <sys/ioctl.h>
+ #include <errno.h>
++#include <sys/types.h>
+
+ #include <linux/types.h>
+ #include <linux/major.h>
+ #include <linux/raid/md_p.h>
+ #include <linux/raid/md_u.h>
+
+-static char *
+-grub_util_getdiskname (int major, int minor)
+-{
+- char *name = xmalloc (15);
+-
+- if (major == LOOP_MAJOR)
+- sprintf (name, "/dev/loop%d", minor);
+- else if (major == IDE0_MAJOR)
+- sprintf (name, "/dev/hd%c", 'a' + minor / 64);
+- else if (major == IDE1_MAJOR)
+- sprintf (name, "/dev/hd%c", 'c' + minor / 64);
+- else if (major == IDE2_MAJOR)
+- sprintf (name, "/dev/hd%c", 'e' + minor / 64);
+- else if (major == IDE3_MAJOR)
+- sprintf (name, "/dev/hd%c", 'g' + minor / 64);
+- else if (major == SCSI_DISK0_MAJOR)
+- sprintf (name, "/dev/sd%c", 'a' + minor / 16);
+- else
+- grub_util_error ("unknown device number: %d, %d", major, minor);
+-
+- return name;
+-}
+-
+ char **
+ grub_util_raid_getmembers (char *name)
+ {
+@@ -99,7 +78,8 @@
+
+ if (disk.state & (1 << MD_DISK_ACTIVE))
+ {
+- devicelist[j] = grub_util_getdiskname (disk.major, disk.minor);
++ devicelist[j] = grub_find_device (NULL,
++ makedev (disk.major, disk.minor));
+ j++;
+ }
+ }
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/961_dmraid_probe.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/961_dmraid_probe.diff
new file mode 100644
index 00000000..8bc94707
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/961_dmraid_probe.diff
@@ -0,0 +1,650 @@
+Description: Add DM-RAID probing support.
+Upstream: Maintained in an upstream branch,
+ sftp://bzr.sv.gnu.org/srv/bzr/grub/branches/dmraid-probe/; see
+ http://lists.gnu.org/archive/html/grub-devel/2010-01/msg00345.html
+
+diff -Nur -x '*.orig' -x '*~' grub2/ChangeLog.dmraid-probe grub2.new/ChangeLog.dmraid-probe
+--- grub2/ChangeLog.dmraid-probe 1969-12-31 16:00:00.000000000 -0800
++++ grub2.new/ChangeLog.dmraid-probe 2010-02-06 10:33:54.000000000 -0800
+@@ -0,0 +1,26 @@
++2010-01-31 Colin Watson <cjwatson@ubuntu.com>
++
++ * configure.ac: Check for Linux device-mapper support.
++
++ * util/hostdisk.c (device_is_mapped): New function.
++ (find_partition_start): New function, partly broken out from
++ linux_find_partition and grub_util_biosdisk_get_grub_dev but with
++ device-mapper support added.
++ (linux_find_partition): Use find_partition_start.
++ (convert_system_partition_to_system_disk): Add `st' argument.
++ Support Linux /dev/mapper/* devices if device-mapper support is
++ available; only DM-RAID devices are understood at present.
++ (find_system_device): Add `st' argument. Pass it to
++ convert_system_partition_to_system_disk.
++ (grub_util_biosdisk_get_grub_dev): Pass stat result to
++ find_system_device and convert_system_partition_to_system_disk. Use
++ find_partition_start.
++
++ * conf/common.rmk (grub_mkdevicemap_SOURCES): Add kern/env.c,
++ kern/err.c, kern/list.c, and kern/misc.c.
++ * util/deviceiter.c [__linux__]: Define MINOR.
++ (grub_util_iterate_devices): Add support for DM-RAID disk devices.
++ * util/mkdevicemap.c (grub_putchar): New function.
++ (grub_getkey): New function.
++ (grub_refresh): New function.
++ (main): Set debug=all if -v -v is used.
+diff -Nur -x '*.orig' -x '*~' grub2/conf/common.rmk grub2.new/conf/common.rmk
+--- grub2/conf/common.rmk 2010-02-06 10:32:37.000000000 -0800
++++ grub2.new/conf/common.rmk 2010-02-06 10:33:54.000000000 -0800
+@@ -3,7 +3,8 @@
+ sbin_UTILITIES += grub-mkdevicemap
+ grub_mkdevicemap_SOURCES = gnulib/progname.c util/grub-mkdevicemap.c \
+ util/deviceiter.c \
+- util/misc.c
++ util/misc.c \
++ kern/env.c kern/err.c kern/list.c kern/misc.c
+
+ ifeq ($(target_cpu)-$(platform), sparc64-ieee1275)
+ grub_mkdevicemap_SOURCES += util/ieee1275/ofpath.c util/ieee1275/devicemap.c
+diff -Nur -x '*.orig' -x '*~' grub2/configure.ac grub2.new/configure.ac
+--- grub2/configure.ac 2010-02-06 10:32:49.000000000 -0800
++++ grub2.new/configure.ac 2010-02-06 10:33:54.000000000 -0800
+@@ -660,6 +660,22 @@
+ AC_SUBST([freetype_cflags])
+ AC_SUBST([freetype_libs])
+
++AC_ARG_ENABLE([device-mapper],
++ [AS_HELP_STRING([--enable-device-mapper],
++ [enable Linux device-mapper support (default=guessed)])])
++if test x"$enable_device_mapper" = xno ; then
++ device_mapper_excuse="explicitly disabled"
++fi
++
++if test x"$device_mapper_excuse" = x ; then
++ # Check for device-mapper library.
++ AC_CHECK_LIB([devmapper], [dm_task_create],
++ [LDFLAGS="$LDFLAGS -ldevmapper"
++ AC_DEFINE([HAVE_DEVICE_MAPPER], [1],
++ [Define to 1 if you have the devmapper library.])],
++ [device_mapper_excuse="need devmapper library"])
++fi
++
+ AC_SUBST(ASFLAGS)
+
+ # Output files.
+diff -Nur -x '*.orig' -x '*~' grub2/util/deviceiter.c grub2.new/util/deviceiter.c
+--- grub2/util/deviceiter.c 2010-02-06 10:32:37.000000000 -0800
++++ grub2.new/util/deviceiter.c 2010-02-06 10:33:54.000000000 -0800
+@@ -31,6 +31,8 @@
+
+ #include <grub/util/misc.h>
+ #include <grub/util/deviceiter.h>
++#include <grub/list.h>
++#include <grub/misc.h>
+
+ #ifdef __linux__
+ # if !defined(__GLIBC__) || \
+@@ -62,12 +64,23 @@
+ | ((unsigned int) (__dev >> 32) & ~0xfff); \
+ })
+ # endif /* ! MAJOR */
++# ifndef MINOR
++# define MINOR(dev) \
++ ({ \
++ unsigned long long __dev = (dev); \
++ (unsigned) (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff); \
++ })
++# endif /* ! MINOR */
+ # ifndef CDROM_GET_CAPABILITY
+ # define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
+ # endif /* ! CDROM_GET_CAPABILITY */
+ # ifndef BLKGETSIZE
+ # define BLKGETSIZE _IO(0x12,96) /* return device size */
+ # endif /* ! BLKGETSIZE */
++
++#ifdef HAVE_DEVICE_MAPPER
++# include <libdevmapper.h>
++#endif
+ #endif /* __linux__ */
+
+ /* Use __FreeBSD_kernel__ instead of __FreeBSD__ for compatibility with
+@@ -411,6 +424,16 @@
+ return 1;
+ }
+
++#ifdef __linux__
++# ifdef HAVE_DEVICE_MAPPER
++struct dmraid_seen
++{
++ struct dmraid_seen *next;
++ const char *name;
++};
++# endif /* HAVE_DEVICE_MAPPER */
++#endif /* __linux__ */
++
+ void
+ grub_util_iterate_devices (int NESTED_FUNC_ATTR (*hook) (const char *, int),
+ int floppy_disks)
+@@ -643,6 +666,123 @@
+ return;
+ }
+ }
++
++# ifdef HAVE_DEVICE_MAPPER
++# define dmraid_check(cond, ...) \
++ if (! (cond)) \
++ { \
++ grub_dprintf ("deviceiter", __VA_ARGS__); \
++ goto dmraid_end; \
++ }
++
++ /* DM-RAID. */
++ {
++ struct dm_tree *tree = NULL;
++ struct dm_task *task = NULL;
++ struct dm_names *names = NULL;
++ unsigned int next = 0;
++ void *top_handle, *second_handle;
++ struct dm_tree_node *root, *top, *second;
++ struct dmraid_seen *seen = NULL;
++
++ /* Build DM tree for all devices. */
++ tree = dm_tree_create ();
++ dmraid_check (tree, "dm_tree_create failed\n");
++ task = dm_task_create (DM_DEVICE_LIST);
++ dmraid_check (task, "dm_task_create failed\n");
++ dmraid_check (dm_task_run (task), "dm_task_run failed\n");
++ names = dm_task_get_names (task);
++ dmraid_check (names, "dm_task_get_names failed\n");
++ dmraid_check (names->dev, "No DM devices found\n");
++ do
++ {
++ names = (void *) names + next;
++ dmraid_check (dm_tree_add_dev (tree, MAJOR (names->dev),
++ MINOR (names->dev)),
++ "dm_tree_add_dev (%s) failed\n", names->name);
++ next = names->next;
++ }
++ while (next);
++
++ /* Walk the second-level children of the inverted tree; that is, devices
++ which are directly composed of non-DM devices such as hard disks.
++ This class includes all DM-RAID disks and excludes all DM-RAID
++ partitions. */
++ root = dm_tree_find_node (tree, 0, 0);
++ top_handle = NULL;
++ top = dm_tree_next_child (&top_handle, root, 1);
++ while (top)
++ {
++ second_handle = NULL;
++ second = dm_tree_next_child (&second_handle, top, 1);
++ while (second)
++ {
++ const char *node_name, *node_uuid;
++ char *name;
++ struct dmraid_seen *seen_elt;
++
++ node_name = dm_tree_node_get_name (second);
++ dmraid_check (node_name, "dm_tree_node_get_name failed\n");
++ node_uuid = dm_tree_node_get_uuid (second);
++ dmraid_check (node_uuid, "dm_tree_node_get_uuid failed\n");
++ if (strncmp (node_uuid, "DMRAID-", 7) != 0)
++ {
++ grub_dprintf ("deviceiter", "%s is not DM-RAID\n", node_name);
++ goto dmraid_next_child;
++ }
++
++ /* Have we already seen this node? There are typically very few
++ DM-RAID disks, so a list should be fast enough. */
++ if (grub_named_list_find (GRUB_AS_NAMED_LIST (seen), node_name))
++ {
++ grub_dprintf ("deviceiter", "Already seen DM device %s\n",
++ node_name);
++ goto dmraid_next_child;
++ }
++
++ name = xasprintf ("/dev/mapper/%s", node_name);
++ if (check_device (name))
++ {
++ if (hook (name, 0))
++ {
++ free (name);
++ while (seen)
++ {
++ struct dmraid_seen *seen_elt =
++ grub_list_pop (GRUB_AS_LIST_P (&seen));
++ free (seen_elt);
++ }
++ if (task)
++ dm_task_destroy (task);
++ if (tree)
++ dm_tree_free (tree);
++ return;
++ }
++ }
++ free (name);
++
++ seen_elt = xmalloc (sizeof *seen_elt);
++ seen_elt->name = node_name;
++ grub_list_push (GRUB_AS_LIST_P (&seen), GRUB_AS_LIST (seen_elt));
++
++dmraid_next_child:
++ second = dm_tree_next_child (&second_handle, top, 1);
++ }
++ top = dm_tree_next_child (&top_handle, root, 1);
++ }
++
++dmraid_end:
++ while (seen)
++ {
++ struct dmraid_seen *seen_elt = grub_list_pop (GRUB_AS_LIST_P (&seen));
++ free (seen_elt);
++ }
++ if (task)
++ dm_task_destroy (task);
++ if (tree)
++ dm_tree_free (tree);
++ }
++# endif /* HAVE_DEVICE_MAPPER */
+ #endif /* __linux__ */
+ }
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/grub-mkdevicemap.c grub2.new/util/grub-mkdevicemap.c
+--- grub2/util/grub-mkdevicemap.c 2010-02-06 10:32:37.000000000 -0800
++++ grub2.new/util/grub-mkdevicemap.c 2010-02-06 10:33:54.000000000 -0800
+@@ -31,6 +31,7 @@
+
+ #include <grub/util/misc.h>
+ #include <grub/util/deviceiter.h>
++#include <grub/env.h>
+ #include <grub/i18n.h>
+
+ #define _GNU_SOURCE 1
+@@ -38,6 +39,24 @@
+
+ #include "progname.h"
+
++void
++grub_putchar (int c)
++{
++ putchar (c);
++}
++
++int
++grub_getkey (void)
++{
++ return -1;
++}
++
++void
++grub_refresh (void)
++{
++ fflush (stdout);
++}
++
+ static void
+ make_device_map (const char *device_map, int floppy_disks)
+ {
+@@ -158,6 +177,9 @@
+ }
+ }
+
++ if (verbosity > 1)
++ grub_env_set ("debug", "all");
++
+ make_device_map (dev_map ? : DEFAULT_DEVICE_MAP, floppy_disks);
+
+ free (dev_map);
+diff -Nur -x '*.orig' -x '*~' grub2/util/hostdisk.c grub2.new/util/hostdisk.c
+--- grub2/util/hostdisk.c 2010-02-06 10:32:55.000000000 -0800
++++ grub2.new/util/hostdisk.c 2010-02-06 10:33:54.000000000 -0800
+@@ -97,6 +97,10 @@
+ # include <sys/disk.h>
+ #endif
+
++#ifdef HAVE_DEVICE_MAPPER
++# include <libdevmapper.h>
++#endif
++
+ struct
+ {
+ char *drive;
+@@ -253,6 +257,115 @@
+ return GRUB_ERR_NONE;
+ }
+
++#ifdef HAVE_DEVICE_MAPPER
++static int
++device_is_mapped (const char *dev)
++{
++ struct stat st;
++
++ if (stat (dev, &st) < 0)
++ return 0;
++
++ return dm_is_dm_major (major (st.st_rdev));
++}
++#endif /* HAVE_DEVICE_MAPPER */
++
++#if defined(__linux__) || defined(__CYGWIN__)
++static grub_disk_addr_t
++find_partition_start (const char *dev)
++{
++ int fd;
++ struct hd_geometry hdg;
++
++#ifdef HAVE_DEVICE_MAPPER
++ if (device_is_mapped (dev)) {
++ struct dm_task *task = NULL;
++ grub_uint64_t start, length;
++ char *target_type, *params, *space;
++ grub_disk_addr_t partition_start;
++
++ /* If any device-mapper operation fails, we fall back silently to
++ HDIO_GETGEO. */
++ task = dm_task_create (DM_DEVICE_TABLE);
++ if (! task)
++ {
++ grub_dprintf ("hostdisk", "dm_task_create failed\n");
++ goto devmapper_fail;
++ }
++
++ if (! dm_task_set_name (task, dev))
++ {
++ grub_dprintf ("hostdisk", "dm_task_set_name failed\n");
++ goto devmapper_fail;
++ }
++
++ if (! dm_task_run (task))
++ {
++ grub_dprintf ("hostdisk", "dm_task_run failed\n");
++ goto devmapper_fail;
++ }
++
++ dm_get_next_target (task, NULL, &start, &length, &target_type, &params);
++ if (! target_type)
++ {
++ grub_dprintf ("hostdisk", "no dm target\n");
++ goto devmapper_fail;
++ }
++ if (strcmp (target_type, "linear") != 0)
++ {
++ grub_dprintf ("hostdisk", "ignoring dm target %s (not linear)\n",
++ target_type);
++ goto devmapper_fail;
++ }
++ if (! params)
++ {
++ grub_dprintf ("hostdisk", "no dm params\n");
++ goto devmapper_fail;
++ }
++
++ /* The params string for a linear target looks like this:
++ DEVICE-NAME START-SECTOR
++ Parse this out. */
++ space = strchr (params, ' ');
++ if (! space)
++ goto devmapper_fail;
++ errno = 0;
++ partition_start = strtoull (space + 1, NULL, 10);
++ if (errno == 0)
++ {
++ grub_dprintf ("hostdisk", "dm %s starts at %llu\n",
++ dev, partition_start);
++ dm_task_destroy (task);
++ return partition_start;
++ }
++
++devmapper_fail:
++ if (task)
++ dm_task_destroy (task);
++ }
++#endif /* HAVE_DEVICE_MAPPER */
++
++ fd = open (dev, O_RDONLY);
++ if (fd == -1)
++ {
++ grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", dev);
++ return 0;
++ }
++
++ if (ioctl (fd, HDIO_GETGEO, &hdg))
++ {
++ grub_error (GRUB_ERR_BAD_DEVICE,
++ "cannot get geometry of `%s'", dev);
++ close (fd);
++ return 0;
++ }
++
++ close (fd);
++
++ return hdg.start;
++}
++#endif /* __linux__ || __CYGWIN__ */
++
+ #ifdef __linux__
+ static int
+ linux_find_partition (char *dev, unsigned long sector)
+@@ -284,22 +397,20 @@
+ for (i = 1; i < 10000; i++)
+ {
+ int fd;
+- struct hd_geometry hdg;
++ grub_disk_addr_t start;
+
+ sprintf (p, format, i);
++
+ fd = open (real_dev, O_RDONLY);
+ if (fd == -1)
+ return 0;
+-
+- if (ioctl (fd, HDIO_GETGEO, &hdg))
+- {
+- close (fd);
+- return 0;
+- }
+-
+ close (fd);
+
+- if (hdg.start == sector)
++ start = find_partition_start (real_dev);
++ /* We don't care about errors here. */
++ grub_errno = GRUB_ERR_NONE;
++
++ if (start == sector)
+ {
+ strcpy (dev, real_dev);
+ return 1;
+@@ -711,7 +822,7 @@
+ }
+
+ static char *
+-convert_system_partition_to_system_disk (const char *os_dev)
++convert_system_partition_to_system_disk (const char *os_dev, struct stat *st)
+ {
+ #if defined(__linux__)
+ char *path = xmalloc (PATH_MAX);
+@@ -829,6 +940,96 @@
+ p[4] = '\0';
+ return path;
+ }
++
++#ifdef HAVE_DEVICE_MAPPER
++ /* If this is a DM-RAID device. */
++ if ((strncmp ("mapper/", p, 7) == 0))
++ {
++ static struct dm_tree *tree = NULL;
++ uint32_t maj, min;
++ struct dm_tree_node *node, *child;
++ void *handle;
++ const char *node_uuid, *mapper_name, *child_uuid, *child_name;
++
++ if (! tree)
++ tree = dm_tree_create ();
++
++ if (! tree)
++ {
++ grub_dprintf ("hostdisk", "dm_tree_create failed\n");
++ return NULL;
++ }
++
++ maj = major (st->st_rdev);
++ min = minor (st->st_rdev);
++ if (! dm_tree_add_dev (tree, maj, min))
++ {
++ grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
++ return NULL;
++ }
++
++ node = dm_tree_find_node (tree, maj, min);
++ if (! node)
++ {
++ grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
++ return NULL;
++ }
++ node_uuid = dm_tree_node_get_uuid (node);
++ if (! node_uuid)
++ {
++ grub_dprintf ("hostdisk", "%s has no DM uuid\n", path);
++ return NULL;
++ }
++ else if (strncmp (node_uuid, "DMRAID-", 7) != 0)
++ {
++ grub_dprintf ("hostdisk", "%s is not DM-RAID\n", path);
++ return NULL;
++ }
++
++ handle = NULL;
++ mapper_name = NULL;
++ /* Counter-intuitively, device-mapper refers to the disk-like
++ device containing a DM-RAID partition device as a "child" of
++ the partition device. */
++ child = dm_tree_next_child (&handle, node, 0);
++ if (! child)
++ {
++ grub_dprintf ("hostdisk", "%s has no DM children\n", path);
++ goto devmapper_out;
++ }
++ child_uuid = dm_tree_node_get_uuid (child);
++ if (! child_uuid)
++ {
++ grub_dprintf ("hostdisk", "%s child has no DM uuid\n", path);
++ goto devmapper_out;
++ }
++ else if (strncmp (child_uuid, "DMRAID-", 7) != 0)
++ {
++ grub_dprintf ("hostdisk", "%s child is not DM-RAID\n", path);
++ goto devmapper_out;
++ }
++ child_name = dm_tree_node_get_name (child);
++ if (! child_name)
++ {
++ grub_dprintf ("hostdisk", "%s child has no DM name\n", path);
++ goto devmapper_out;
++ }
++ mapper_name = child_name;
++
++devmapper_out:
++ if (! mapper_name)
++ {
++ /* This is a DM-RAID disk, not a partition. */
++ mapper_name = dm_tree_node_get_name (node);
++ if (! mapper_name)
++ {
++ grub_dprintf ("hostdisk", "%s has no DM name\n", path);
++ return NULL;
++ }
++ }
++ return xasprintf ("/dev/mapper/%s", mapper_name);
++ }
++#endif /* HAVE_DEVICE_MAPPER */
+ }
+
+ return path;
+@@ -884,12 +1085,12 @@
+ #endif
+
+ static int
+-find_system_device (const char *os_dev)
++find_system_device (const char *os_dev, struct stat *st)
+ {
+ unsigned int i;
+ char *os_disk;
+
+- os_disk = convert_system_partition_to_system_disk (os_dev);
++ os_disk = convert_system_partition_to_system_disk (os_dev, st);
+ if (! os_disk)
+ return -1;
+
+@@ -923,7 +1124,7 @@
+ return 0;
+ }
+
+- drive = find_system_device (os_dev);
++ drive = find_system_device (os_dev, &st);
+ if (drive < 0)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+@@ -931,8 +1132,8 @@
+ return 0;
+ }
+
+- if (grub_strcmp (os_dev, convert_system_partition_to_system_disk (os_dev))
+- == 0)
++ if (grub_strcmp (os_dev,
++ convert_system_partition_to_system_disk (os_dev, &st)) == 0)
+ return make_device_name (drive, -1, -1);
+
+ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
+@@ -954,8 +1155,7 @@
+ {
+ char *name;
+ grub_disk_t disk;
+- int fd;
+- struct hd_geometry hdg;
++ grub_disk_addr_t start;
+ int dos_part = -1;
+ int bsd_part = -1;
+ auto int find_partition (grub_disk_t disk,
+@@ -985,7 +1185,7 @@
+ partition->index, partition->start);
+ }
+
+- if (hdg.start == partition->start)
++ if (start == partition->start)
+ {
+ if (pcdata)
+ {
+@@ -1008,28 +1208,16 @@
+ if (MAJOR (st.st_rdev) == FLOPPY_MAJOR)
+ return name;
+
+- fd = open (os_dev, O_RDONLY);
+- if (fd == -1)
+- {
+- grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' while attempting to get disk geometry", os_dev);
+- free (name);
+- return 0;
+- }
+-
+- if (ioctl (fd, HDIO_GETGEO, &hdg))
++ start = find_partition_start (os_dev);
++ if (grub_errno != GRUB_ERR_NONE)
+ {
+- grub_error (GRUB_ERR_BAD_DEVICE,
+- "cannot get geometry of `%s'", os_dev);
+- close (fd);
+ free (name);
+ return 0;
+ }
+
+- close (fd);
+-
+- grub_util_info ("%s starts from %lu", os_dev, hdg.start);
++ grub_util_info ("%s starts from %lu", os_dev, start);
+
+- if (hdg.start == 0 && device_is_wholedisk (os_dev))
++ if (start == 0 && device_is_wholedisk (os_dev))
+ return name;
+
+ grub_util_info ("opening the device %s", name);
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/962_no_device_map.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/962_no_device_map.diff
new file mode 100644
index 00000000..c129254a
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/962_no_device_map.diff
@@ -0,0 +1,112 @@
+Ubuntu: Don't generate a device map by default.
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/grub-install.in grub2.new/util/grub-install.in
+--- grub2/util/grub-install.in 2010-03-22 14:11:42.000000000 +0000
++++ grub2.new/util/grub-install.in 2010-03-22 16:23:14.000000000 +0000
+@@ -39,7 +39,6 @@
+ else
+ grub_mkimage=${bindir}/`echo grub-mkelfimage | sed ${transform}`
+ fi
+-grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}`
+ grub_probe=${sbindir}/`echo grub-probe | sed ${transform}`
+ grub_editenv=${bindir}/`echo grub-editenv | sed ${transform}`
+ rootdir=
+@@ -74,7 +73,6 @@
+ instead of the root directory
+ --grub-setup=FILE use FILE as grub-setup
+ --grub-mkimage=FILE use FILE as grub-mkimage
+- --grub-mkdevicemap=FILE use FILE as grub-mkdevicemap
+ --grub-probe=FILE use FILE as grub-probe
+ --no-floppy do not probe any floppy drive
+ --recheck probe a device map even if it already exists
+@@ -124,7 +122,7 @@
+ --grub-mkimage=*)
+ grub_mkimage=`echo "$option" | sed 's/--grub-mkimage=//'` ;;
+ --grub-mkdevicemap=*)
+- grub_mkdevicemap=`echo "$option" | sed 's/--grub-mkdevicemap=//'` ;;
++ : ;; # compatibility only
+ --grub-probe=*)
+ grub_probe=`echo "$option" | sed 's/--grub-probe=//'` ;;
+ --no-floppy)
+@@ -209,14 +207,6 @@
+ exit 1
+ fi
+
+-set $grub_mkdevicemap dummy
+-if test -f "$1"; then
+- :
+-else
+- echo "$1: Not found." 1>&2
+- exit 1
+-fi
+-
+ # Create the GRUB directory if it is not present.
+ test -d "$bootdir" || mkdir "$bootdir" || exit 1
+ test -d "$grubdir" || mkdir "$grubdir" || exit 1
+@@ -226,22 +216,14 @@
+ rm -f $device_map
+ fi
+
+-# Create the device map file if it is not present.
++# Make sure that there is no duplicated entry in the device map.
+ if test -f "$device_map"; then
+- :
+-else
+- # Create a safe temporary file.
+- test -n "$mklog" && log_file=`$mklog`
+-
+- $grub_mkdevicemap --device-map=$device_map $no_floppy || exit 1
+-fi
+-
+-# Make sure that there is no duplicated entry.
+-tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' $device_map \
+- | sort | uniq -d | sed -n 1p`
+-if test -n "$tmp"; then
+- echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2
+- exit 1
++ tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' $device_map \
++ | sort | uniq -d | sed -n 1p`
++ if test -n "$tmp"; then
++ echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2
++ exit 1
++ fi
+ fi
+
+ # Copy the GRUB images to the GRUB directory.
+diff -Nur -x '*.orig' -x '*~' grub2/util/grub-mkconfig.in grub2.new/util/grub-mkconfig.in
+--- grub2/util/grub-mkconfig.in 2010-03-22 16:23:13.000000000 +0000
++++ grub2.new/util/grub-mkconfig.in 2010-03-22 16:23:57.000000000 +0000
+@@ -31,7 +31,6 @@
+ grub_cfg=""
+ grub_mkconfig_dir=${sysconfdir}/grub.d
+
+-grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}`
+ grub_probe=${sbindir}/`echo grub-probe | sed ${transform}`
+
+ # Usage: usage
+@@ -96,14 +95,6 @@
+ fi
+ fi
+
+-set $grub_mkdevicemap dummy
+-if test -f "$1"; then
+- :
+-else
+- echo "$1: Not found." 1>&2
+- exit 1
+-fi
+-
+ set $grub_probe dummy
+ if test -f "$1"; then
+ :
+@@ -114,10 +105,6 @@
+
+ mkdir -p ${grub_prefix}
+
+-if test -e ${grub_prefix}/device.map ; then : ; else
+- ${grub_mkdevicemap}
+-fi
+-
+ # Device containing our userland. Typically used for root= parameter.
+ GRUB_DEVICE="`${grub_probe} --target=device /`"
+ GRUB_DEVICE_UUID="`${grub_probe} --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`" || true
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/968_hostdisk_speedup.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/968_hostdisk_speedup.diff
new file mode 100644
index 00000000..30ebcbea
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/968_hostdisk_speedup.diff
@@ -0,0 +1,310 @@
+Upstream: http://lists.gnu.org/archive/html/grub-devel/2010-03/msg00008.html
+Description: Optimise hostdisk device handling
+ This substantially speeds up grub-probe filesystem reads.
+
+diff -Nur -x '*.orig' -x '*~' grub2/ChangeLog.hostdisk-speedup grub2.new/ChangeLog.hostdisk-speedup
+--- grub2/ChangeLog.hostdisk-speedup 1970-01-01 01:00:00.000000000 +0100
++++ grub2.new/ChangeLog.hostdisk-speedup 2010-03-03 10:43:43.000000000 +0000
+@@ -0,0 +1,18 @@
++2010-03-03 Colin Watson <cjwatson@ubuntu.com>
++
++ * util/hostdisk.c (struct grub_util_biosdisk_data): New structure.
++ (grub_util_biosdisk_open): Initialise disk->data.
++ (struct linux_partition_cache): New structure.
++ (linux_find_partition): Cache partition start positions; these are
++ expensive to compute on every read and write.
++ (open_device): Cache open file descriptor in disk->data, so that we
++ don't have to reopen it and flush the buffer cache for consecutive
++ operations on the same device.
++ (grub_util_biosdisk_close): New function.
++ (grub_util_biosdisk_dev): Set `close' member.
++
++ * conf/common.rmk (grub_probe_SOURCES): Add kern/list.c.
++ * conf/i386-efi.rmk (grub_setup_SOURCES): Likewise.
++ * conf/i386-pc.rmk (grub_setup_SOURCES): Likewise.
++ * conf/sparc64-ieee1275.rmk (grub_setup_SOURCES): Likewise.
++ * conf/x86_64-efi.rmk (grub_setup_SOURCES): Likewise.
+diff -Nur -x '*.orig' -x '*~' grub2/conf/common.rmk grub2.new/conf/common.rmk
+--- grub2/conf/common.rmk 2010-03-03 20:11:04.000000000 +0000
++++ grub2.new/conf/common.rmk 2010-03-03 20:11:05.000000000 +0000
+@@ -25,7 +25,7 @@
+ grub_probe_SOURCES = gnulib/progname.c util/grub-probe.c \
+ util/hostdisk.c util/misc.c util/getroot.c \
+ kern/device.c kern/disk.c kern/err.c kern/misc.c \
+- kern/parser.c kern/partition.c kern/file.c \
++ kern/parser.c kern/partition.c kern/file.c kern/list.c \
+ \
+ fs/affs.c fs/cpio.c fs/fat.c fs/ext2.c fs/hfs.c \
+ fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
+diff -Nur -x '*.orig' -x '*~' grub2/conf/i386-efi.rmk grub2.new/conf/i386-efi.rmk
+--- grub2/conf/i386-efi.rmk 2010-03-03 20:08:04.000000000 +0000
++++ grub2.new/conf/i386-efi.rmk 2010-03-03 20:11:05.000000000 +0000
+@@ -21,7 +21,7 @@
+ # kern/err.c kern/misc.c fs/fat.c fs/ext2.c fs/xfs.c fs/affs.c \
+ # fs/sfs.c kern/parser.c kern/partition.c partmap/msdos.c \
+ # fs/ufs.c fs/ufs2.c fs/minix.c fs/hfs.c fs/jfs.c fs/hfsplus.c kern/file.c \
+-# kern/fs.c kern/env.c fs/fshelp.c
++# kern/fs.c kern/env.c kern/list.c fs/fshelp.c
+
+ # Scripts.
+ sbin_SCRIPTS = grub-install
+diff -Nur -x '*.orig' -x '*~' grub2/conf/i386-pc.rmk grub2.new/conf/i386-pc.rmk
+--- grub2/conf/i386-pc.rmk 2010-03-03 20:08:04.000000000 +0000
++++ grub2.new/conf/i386-pc.rmk 2010-03-03 20:11:05.000000000 +0000
+@@ -96,7 +96,8 @@
+ util/i386/pc/grub-setup.c util/hostdisk.c \
+ util/misc.c util/getroot.c kern/device.c kern/disk.c \
+ kern/err.c kern/misc.c kern/parser.c kern/partition.c \
+- kern/file.c kern/fs.c kern/env.c fs/fshelp.c \
++ kern/file.c kern/fs.c kern/env.c kern/list.c \
++ fs/fshelp.c \
+ \
+ fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
+ fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
+diff -Nur -x '*.orig' -x '*~' grub2/conf/sparc64-ieee1275.rmk grub2.new/conf/sparc64-ieee1275.rmk
+--- grub2/conf/sparc64-ieee1275.rmk 2010-03-03 20:08:04.000000000 +0000
++++ grub2.new/conf/sparc64-ieee1275.rmk 2010-03-03 20:11:05.000000000 +0000
+@@ -70,7 +70,8 @@
+ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c \
+ util/misc.c util/getroot.c kern/device.c kern/disk.c \
+ kern/err.c kern/misc.c kern/parser.c kern/partition.c \
+- kern/file.c kern/fs.c kern/env.c fs/fshelp.c \
++ kern/file.c kern/fs.c kern/env.c kern/list.c \
++ fs/fshelp.c \
+ \
+ fs/affs.c fs/cpio.c fs/ext2.c fs/fat.c fs/hfs.c \
+ fs/hfsplus.c fs/iso9660.c fs/udf.c fs/jfs.c fs/minix.c \
+diff -Nur -x '*.orig' -x '*~' grub2/conf/x86_64-efi.rmk grub2.new/conf/x86_64-efi.rmk
+--- grub2/conf/x86_64-efi.rmk 2010-03-03 20:08:04.000000000 +0000
++++ grub2.new/conf/x86_64-efi.rmk 2010-03-03 20:11:05.000000000 +0000
+@@ -20,7 +20,7 @@
+ # kern/err.c kern/misc.c fs/fat.c fs/ext2.c fs/xfs.c fs/affs.c \
+ # fs/sfs.c kern/parser.c kern/partition.c partmap/msdos.c \
+ # fs/ufs.c fs/ufs2.c fs/minix.c fs/hfs.c fs/jfs.c fs/hfsplus.c kern/file.c \
+-# kern/fs.c kern/env.c fs/fshelp.c
++# kern/fs.c kern/env.c kern/list.c fs/fshelp.c
+
+ # Scripts.
+ sbin_SCRIPTS = grub-install
+diff -Nur -x '*.orig' -x '*~' grub2/util/hostdisk.c grub2.new/util/hostdisk.c
+--- grub2/util/hostdisk.c 2010-03-03 20:11:04.000000000 +0000
++++ grub2.new/util/hostdisk.c 2010-03-03 20:11:05.000000000 +0000
+@@ -26,6 +26,7 @@
+ #include <grub/util/hostdisk.h>
+ #include <grub/misc.h>
+ #include <grub/i18n.h>
++#include <grub/list.h>
+
+ #include <stdio.h>
+ #include <stdlib.h>
+@@ -107,6 +108,13 @@
+ char *device;
+ } map[256];
+
++struct grub_util_biosdisk_data
++{
++ char *dev;
++ int access_mode;
++ int fd;
++};
++
+ #ifdef __linux__
+ /* Check if we have devfs support. */
+ static int
+@@ -169,6 +177,7 @@
+ {
+ int drive;
+ struct stat st;
++ struct grub_util_biosdisk_data *data;
+
+ drive = find_grub_drive (name);
+ if (drive < 0)
+@@ -177,6 +186,10 @@
+
+ disk->has_partitions = 1;
+ disk->id = drive;
++ disk->data = data = xmalloc (sizeof (struct grub_util_biosdisk_data));
++ data->dev = NULL;
++ data->access_mode = 0;
++ data->fd = -1;
+
+ /* Get the size. */
+ #if defined(__MINGW32__)
+@@ -367,6 +380,17 @@
+ #endif /* __linux__ || __CYGWIN__ */
+
+ #ifdef __linux__
++/* Cache of partition start sectors for each disk. */
++struct linux_partition_cache
++{
++ struct linux_partition_cache *next;
++ char *dev;
++ unsigned long start;
++ int partno;
++};
++
++struct linux_partition_cache *linux_partition_cache_list;
++
+ static int
+ linux_find_partition (char *dev, unsigned long sector)
+ {
+@@ -375,6 +399,7 @@
+ char *p;
+ int i;
+ char real_dev[PATH_MAX];
++ struct linux_partition_cache *cache;
+
+ strcpy(real_dev, dev);
+
+@@ -394,6 +419,16 @@
+ format = "%d";
+ }
+
++ for (cache = linux_partition_cache_list; cache; cache = cache->next)
++ {
++ if (strcmp (cache->dev, dev) == 0 && cache->start == sector)
++ {
++ sprintf (p, format, cache->partno);
++ strcpy (dev, real_dev);
++ return 1;
++ }
++ }
++
+ for (i = 1; i < 10000; i++)
+ {
+ int fd;
+@@ -412,6 +447,15 @@
+
+ if (start == sector)
+ {
++ struct linux_partition_cache *new_cache_item;
++
++ new_cache_item = xmalloc (sizeof *new_cache_item);
++ new_cache_item->dev = xstrdup (dev);
++ new_cache_item->start = start;
++ new_cache_item->partno = i;
++ grub_list_push (GRUB_AS_LIST_P (&linux_partition_cache_list),
++ GRUB_AS_LIST (new_cache_item));
++
+ strcpy (dev, real_dev);
+ return 1;
+ }
+@@ -425,6 +469,7 @@
+ open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags)
+ {
+ int fd;
++ struct grub_util_biosdisk_data *data = disk->data;
+
+ #ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+@@ -451,18 +496,35 @@
+ && strncmp (map[disk->id].device, "/dev/", 5) == 0)
+ is_partition = linux_find_partition (dev, disk->partition->start);
+
+- /* Open the partition. */
+- grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
+- fd = open (dev, flags);
+- if (fd < 0)
++ if (data->dev && strcmp (data->dev, dev) == 0 &&
++ data->access_mode == (flags & O_ACCMODE))
+ {
+- grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", dev);
+- return -1;
++ grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev);
++ fd = data->fd;
+ }
++ else
++ {
++ free (data->dev);
++ if (data->fd != -1)
++ close (data->fd);
++
++ /* Open the partition. */
++ grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
++ fd = open (dev, flags);
++ if (fd < 0)
++ {
++ grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s'", dev);
++ return -1;
++ }
+
+- /* Flush the buffer cache to the physical disk.
+- XXX: This also empties the buffer cache. */
+- ioctl (fd, BLKFLSBUF, 0);
++ /* Flush the buffer cache to the physical disk.
++ XXX: This also empties the buffer cache. */
++ ioctl (fd, BLKFLSBUF, 0);
++
++ data->dev = xstrdup (dev);
++ data->access_mode = (flags & O_ACCMODE);
++ data->fd = fd;
++ }
+
+ if (is_partition)
+ sector -= disk->partition->start;
+@@ -486,7 +548,26 @@
+ }
+ #endif
+
+- fd = open (map[disk->id].device, flags);
++ if (data->dev && strcmp (data->dev, map[disk->id].device) == 0 &&
++ data->access_mode == (flags & O_ACCMODE))
++ {
++ grub_dprintf ("hostdisk", "reusing open device `%s'\n", data->dev);
++ fd = data->fd;
++ }
++ else
++ {
++ free (data->dev);
++ if (data->fd != -1)
++ close (data->fd);
++
++ fd = open (map[disk->id].device, flags);
++ if (fd >= 0)
++ {
++ data->dev = xstrdup (map[disk->id].device);
++ data->access_mode = (flags & O_ACCMODE);
++ data->fd = fd;
++ }
++ }
+
+ #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ if (! (sysctl_oldflags & 0x10)
+@@ -646,7 +727,6 @@
+ != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+ grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
+
+- close (fd);
+ return grub_errno;
+ }
+
+@@ -681,17 +761,27 @@
+ != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+ grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
+
+- close (fd);
+ return grub_errno;
+ }
+
++static void
++grub_util_biosdisk_close (struct grub_disk *disk)
++{
++ struct grub_util_biosdisk_data *data = disk->data;
++
++ free (data->dev);
++ if (data->fd != -1)
++ close (data->fd);
++ free (data);
++}
++
+ static struct grub_disk_dev grub_util_biosdisk_dev =
+ {
+ .name = "biosdisk",
+ .id = GRUB_DISK_DEVICE_BIOSDISK_ID,
+ .iterate = grub_util_biosdisk_iterate,
+ .open = grub_util_biosdisk_open,
+- .close = 0,
++ .close = grub_util_biosdisk_close,
+ .read = grub_util_biosdisk_read,
+ .write = grub_util_biosdisk_write,
+ .next = 0
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/969_lvm_raid_probe.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/969_lvm_raid_probe.diff
new file mode 100644
index 00000000..52a5c44b
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/969_lvm_raid_probe.diff
@@ -0,0 +1,227 @@
+Description: Fix LVM/RAID probing without device.map
+ When probing LVM or RAID without a device.map, probe all devices in order
+ that we will know about the underlying physical volumes.
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/525085
+Forwarded: http://lists.gnu.org/archive/html/grub-devel/2010-03/msg00084.html
+Last-Update: 2010-03-22
+
+diff -Nur -x '*.orig' -x '*~' grub2/conf/common.rmk grub2.new/conf/common.rmk
+--- grub2/conf/common.rmk 2010-03-22 13:49:14.000000000 +0000
++++ grub2.new/conf/common.rmk 2010-03-22 13:53:20.000000000 +0000
+@@ -24,6 +24,7 @@
+ util/grub-probe.c_DEPENDENCIES = grub_probe_init.h
+ grub_probe_SOURCES = gnulib/progname.c util/grub-probe.c \
+ util/hostdisk.c util/misc.c util/getroot.c \
++ util/deviceiter.c \
+ kern/device.c kern/disk.c kern/err.c kern/misc.c \
+ kern/parser.c kern/partition.c kern/file.c kern/list.c \
+ \
+diff -Nur -x '*.orig' -x '*~' grub2/conf/i386-pc.rmk grub2.new/conf/i386-pc.rmk
+--- grub2/conf/i386-pc.rmk 2010-03-22 13:49:14.000000000 +0000
++++ grub2.new/conf/i386-pc.rmk 2010-03-22 13:49:17.000000000 +0000
+@@ -94,7 +94,8 @@
+ util/i386/pc/grub-setup.c_DEPENDENCIES = grub_setup_init.h
+ grub_setup_SOURCES = gnulib/progname.c \
+ util/i386/pc/grub-setup.c util/hostdisk.c \
+- util/misc.c util/getroot.c kern/device.c kern/disk.c \
++ util/misc.c util/getroot.c util/deviceiter.c \
++ kern/device.c kern/disk.c \
+ kern/err.c kern/misc.c kern/parser.c kern/partition.c \
+ kern/file.c kern/fs.c kern/env.c kern/list.c \
+ fs/fshelp.c \
+diff -Nur -x '*.orig' -x '*~' grub2/conf/sparc64-ieee1275.rmk grub2.new/conf/sparc64-ieee1275.rmk
+--- grub2/conf/sparc64-ieee1275.rmk 2010-03-22 13:49:14.000000000 +0000
++++ grub2.new/conf/sparc64-ieee1275.rmk 2010-03-22 13:49:17.000000000 +0000
+@@ -68,7 +68,8 @@
+ # For grub-setup.
+ util/sparc64/ieee1275/grub-setup.c_DEPENDENCIES = grub_setup_init.h
+ grub_setup_SOURCES = util/sparc64/ieee1275/grub-setup.c util/hostdisk.c \
+- util/misc.c util/getroot.c kern/device.c kern/disk.c \
++ util/misc.c util/getroot.c util/deviceiter.c \
++ kern/device.c kern/disk.c \
+ kern/err.c kern/misc.c kern/parser.c kern/partition.c \
+ kern/file.c kern/fs.c kern/env.c kern/list.c \
+ fs/fshelp.c \
+diff -Nur -x '*.orig' -x '*~' grub2/include/grub/util/hostdisk.h grub2.new/include/grub/util/hostdisk.h
+--- grub2/include/grub/util/hostdisk.h 2010-03-22 13:47:27.000000000 +0000
++++ grub2.new/include/grub/util/hostdisk.h 2010-03-22 13:51:33.000000000 +0000
+@@ -22,6 +22,7 @@
+
+ void grub_util_biosdisk_init (const char *dev_map);
+ void grub_util_biosdisk_fini (void);
++int grub_util_biosdisk_probe_device (const char *name, int is_floppy);
+ char *grub_util_biosdisk_get_grub_dev (const char *os_dev);
+
+ #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */
+diff -Nur -x '*.orig' -x '*~' grub2/util/grub-probe.c grub2.new/util/grub-probe.c
+--- grub2/util/grub-probe.c 2010-03-22 13:47:27.000000000 +0000
++++ grub2.new/util/grub-probe.c 2010-03-22 13:53:10.000000000 +0000
+@@ -28,6 +28,7 @@
+ #include <grub/msdos_partition.h>
+ #include <grub/util/hostdisk.h>
+ #include <grub/util/getroot.h>
++#include <grub/util/deviceiter.h>
+ #include <grub/term.h>
+ #include <grub/env.h>
+ #include <grub/raid.h>
+@@ -106,13 +107,14 @@
+ }
+
+ static void
+-probe (const char *path, char *device_name)
++probe (const char *path, char *device_name, const char *dev_map)
+ {
+ char *drive_name = NULL;
+ char *grub_path = NULL;
+ char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL;
+ grub_device_t dev = NULL;
+ grub_fs_t fs;
++ struct stat dev_map_stat;
+
+ if (path == NULL)
+ {
+@@ -136,6 +138,22 @@
+ goto end;
+ }
+
++ if (stat (dev_map, &dev_map_stat) == -1 &&
++ grub_util_get_dev_abstraction (device_name) != GRUB_DEV_ABSTRACTION_NONE)
++ {
++ /* If we don't have a device map, then we won't yet know about the
++ physical volumes underlying this device, so probe all devices. */
++ grub_util_iterate_devices (grub_util_biosdisk_probe_device, 0);
++
++ /* Now reinitialise the higher layers. */
++ grub_lvm_fini ();
++ grub_mdraid_fini ();
++ grub_raid_fini ();
++ grub_raid_init ();
++ grub_mdraid_init ();
++ grub_lvm_init ();
++ }
++
+ drive_name = grub_util_get_grub_dev (device_name);
+ if (! drive_name)
+ grub_util_error ("cannot find a GRUB drive for %s. Check your device.map", device_name);
+@@ -428,9 +446,9 @@
+
+ /* Do it. */
+ if (argument_is_device)
+- probe (NULL, argument);
++ probe (NULL, argument, dev_map ? : DEFAULT_DEVICE_MAP);
+ else
+- probe (argument, NULL);
++ probe (argument, NULL, dev_map ? : DEFAULT_DEVICE_MAP);
+
+ /* Free resources. */
+ grub_fini_all ();
+diff -Nur -x '*.orig' -x '*~' grub2/util/hostdisk.c grub2.new/util/hostdisk.c
+--- grub2/util/hostdisk.c 2010-03-22 13:49:14.000000000 +0000
++++ grub2.new/util/hostdisk.c 2010-03-22 13:51:53.000000000 +0000
+@@ -1237,6 +1237,48 @@
+ return i;
+ }
+
++static void
++store_grub_dev (const char *grub_disk, const char *os_disk)
++{
++ unsigned int i;
++
++ for (i = 0; i < ARRAY_SIZE (map); i++)
++ if (! map[i].device)
++ break;
++ else if (strcmp (map[i].drive, grub_disk) == 0)
++ {
++ if (strcmp (map[i].device, os_disk) == 0)
++ return;
++ grub_util_error (_("drive `%s' already mapped to `%s'"),
++ map[i].drive, map[i].device);
++ }
++
++ if (i == ARRAY_SIZE (map))
++ grub_util_error (_("device count exceeds limit"));
++
++ map[i].drive = xstrdup (grub_disk);
++ map[i].device = xstrdup (os_disk);
++}
++
++static int num_hd = 0;
++static int num_fd = 0;
++
++int
++grub_util_biosdisk_probe_device (const char *name, int is_floppy)
++{
++ char *grub_disk;
++
++ if (is_floppy)
++ grub_disk = xasprintf ("fd%d", num_fd++);
++ else
++ grub_disk = xasprintf ("hd%d", num_hd++);
++
++ store_grub_dev (grub_disk, name);
++ free (grub_disk);
++
++ return 0;
++}
++
+ char *
+ grub_util_biosdisk_get_grub_dev (const char *os_dev)
+ {
+diff -Nur -x '*.orig' -x '*~' grub2/util/i386/pc/grub-setup.c grub2.new/util/i386/pc/grub-setup.c
+--- grub2/util/i386/pc/grub-setup.c 2010-03-22 13:49:13.000000000 +0000
++++ grub2.new/util/i386/pc/grub-setup.c 2010-03-22 13:53:10.000000000 +0000
+@@ -36,6 +36,7 @@
+ #include <grub/util/raid.h>
+ #include <grub/util/lvm.h>
+ #include <grub/util/getroot.h>
++#include <grub/util/deviceiter.h>
+
+ static const grub_gpt_part_type_t grub_gpt_partition_type_bios_boot = GRUB_GPT_PARTITION_TYPE_BIOS_BOOT;
+
+@@ -646,6 +647,7 @@
+ char *core_file = 0;
+ char *dir = 0;
+ char *dev_map = 0;
++ struct stat dev_map_stat;
+ char *root_dev = 0;
+ char *dest_dev;
+ int must_embed = 0, force = 0, fs_probe = 1;
+@@ -744,6 +746,9 @@
+ /* Initialize the emulated biosdisk driver. */
+ grub_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP);
+
++ if (stat (dev_map ? : DEFAULT_DEVICE_MAP, &dev_map_stat) == -1)
++ grub_util_iterate_devices (grub_util_biosdisk_probe_device, 0);
++
+ /* Initialize all modules. */
+ grub_init_all ();
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/sparc64/ieee1275/grub-setup.c grub2.new/util/sparc64/ieee1275/grub-setup.c
+--- grub2/util/sparc64/ieee1275/grub-setup.c 2010-03-22 13:47:27.000000000 +0000
++++ grub2.new/util/sparc64/ieee1275/grub-setup.c 2010-03-22 13:53:10.000000000 +0000
+@@ -46,6 +46,7 @@
+ #include <sys/stat.h>
+ #include <dirent.h>
+ #include <grub/util/getroot.h>
++#include <grub/util/deviceiter.h>
+
+ #define _GNU_SOURCE 1
+ #include <getopt.h>
+@@ -618,6 +619,7 @@
+ main (int argc, char *argv[])
+ {
+ struct grub_setup_info ginfo;
++ struct stat dev_map_stat;
+
+ set_program_name (argv[0]);
+
+@@ -630,6 +632,9 @@
+ /* Initialize the emulated biosdisk driver. */
+ grub_util_biosdisk_init (ginfo.dev_map ? ginfo.dev_map : DEFAULT_DEVICE_MAP);
+
++ if (stat (ginfo.dev_map ? : DEFAULT_DEVICE_MAP, &dev_map_stat) == -1)
++ grub_util_iterate_devices (grub_util_biosdisk_probe_device, 0);
++
+ /* Initialize all modules. */
+ grub_init_all ();
+
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/970_fix_locale_installation.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/970_fix_locale_installation.diff
new file mode 100644
index 00000000..ab202885
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/970_fix_locale_installation.diff
@@ -0,0 +1,55 @@
+Description: Copy .mo files from @datadir@/locale
+ This matches where 'make install' puts them.
+Origin: upstream, http://bazaar.launchpad.net/~vcs-imports/grub/grub2-bzr/revision/2265
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/537998
+Forwarded: http://lists.gnu.org/archive/html/grub-devel/2010-03/msg00074.html
+Last-Update: 2010-03-22
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/grub-install.in grub2.new/util/grub-install.in
+--- grub2/util/grub-install.in 2010-03-22 15:49:32.000000000 +0000
++++ grub2.new/util/grub-install.in 2010-03-22 15:54:31.000000000 +0000
+@@ -32,6 +32,7 @@
+ host_os=@host_os@
+ font=@datadir@/@PACKAGE_TARNAME@/ascii.pf2
+ pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}`
++localedir=@datadir@/locale
+
+ grub_setup=${sbindir}/`echo grub-setup | sed ${transform}`
+ if [ "${target_cpu}-${platform}" = "i386-pc" ] || [ "${target_cpu}-${platform}" = "sparc64-ieee1275" ] || [ "${target_cpu}-${platform}" = "mips-yeeloong" ] ; then
+@@ -245,9 +246,9 @@
+
+ # Copy gettext files
+ mkdir -p ${grubdir}/locale/
+-for file in ${grubdir}/locale/*.mo ${pkglibdir}/locale/*.mo; do
+- if test -f "$file"; then
+- cp -f "$file" ${grubdir}/locale/
++for dir in ${localedir}/*; do
++ if test -f "$dir/LC_MESSAGES/grub.mo"; then
++ cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo"
+ fi
+ done
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/i386/efi/grub-install.in grub2.new/util/i386/efi/grub-install.in
+--- grub2/util/i386/efi/grub-install.in 2010-03-09 16:14:00.000000000 +0000
++++ grub2.new/util/i386/efi/grub-install.in 2010-03-22 15:54:31.000000000 +0000
+@@ -31,6 +31,7 @@
+ platform=@platform@
+ host_os=@host_os@
+ pkglibdir=${libdir}/`echo ${PACKAGE_TARNAME}/${target_cpu}-${platform} | sed ${transform}`
++localedir=@datadir@/locale
+
+ grub_mkimage=${bindir}/`echo grub-mkimage | sed ${transform}`
+ grub_mkdevicemap=${sbindir}/`echo grub-mkdevicemap | sed ${transform}`
+@@ -182,9 +183,9 @@
+
+ # Copy gettext files
+ mkdir -p ${grubdir}/locale/
+-for file in ${grubdir}/locale/*.mo ${pkglibdir}/locale/*.mo; do
+- if test -f "$file"; then
+- cp -f "$file" ${grubdir}/locale/
++for dir in ${localedir}/*; do
++ if test -f "$dir/LC_MESSAGES/grub.mo"; then
++ cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo"
+ fi
+ done
+
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/971_langpacks.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/971_langpacks.diff
new file mode 100644
index 00000000..7e1cb897
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/971_langpacks.diff
@@ -0,0 +1,30 @@
+Description: Prefer translations from language packs
+Author: Colin Watson <cjwatson@ubuntu.com>
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/537998
+Forwarded: not-needed
+Last-Update: 2010-03-22
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/grub-install.in grub2.new/util/grub-install.in
+--- grub2/util/grub-install.in 2010-03-22 15:58:16.000000000 +0000
++++ grub2.new/util/grub-install.in 2010-03-22 15:59:04.000000000 +0000
+@@ -246,7 +246,7 @@
+
+ # Copy gettext files
+ mkdir -p ${grubdir}/locale/
+-for dir in ${localedir}/*; do
++for dir in ${localedir}/* ${localedir}-langpack/*; do
+ if test -f "$dir/LC_MESSAGES/grub.mo"; then
+ cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo"
+ fi
+diff -Nur -x '*.orig' -x '*~' grub2/util/i386/efi/grub-install.in grub2.new/util/i386/efi/grub-install.in
+--- grub2/util/i386/efi/grub-install.in 2010-03-22 15:58:16.000000000 +0000
++++ grub2.new/util/i386/efi/grub-install.in 2010-03-22 15:59:17.000000000 +0000
+@@ -183,7 +183,7 @@
+
+ # Copy gettext files
+ mkdir -p ${grubdir}/locale/
+-for dir in ${localedir}/*; do
++for dir in ${localedir}/* ${localedir}-langpack/*; do
+ if test -f "$dir/LC_MESSAGES/grub.mo"; then
+ cp -f "$dir/LC_MESSAGES/grub.mo" "${grubdir}/locale/${dir##*/}.mo"
+ fi
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/974_drive_probe.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/974_drive_probe.diff
new file mode 100644
index 00000000..0c9f3646
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/974_drive_probe.diff
@@ -0,0 +1,23 @@
+Description: Probe all devices if we've been asked for a drive name
+ This allows --target=drive to work properly even without a device.map.
+ .
+ Depends on 969_lvm_raid_probe.diff.
+Author: Colin Watson <cjwatson@ubuntu.com>
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/549980
+Forwarded: no
+Last-Update: 2010-04-08
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/grub-probe.c grub2.new/util/grub-probe.c
+--- grub2/util/grub-probe.c 2010-04-08 12:02:36.000000000 +0100
++++ grub2.new/util/grub-probe.c 2010-04-08 12:04:05.000000000 +0100
+@@ -139,7 +139,9 @@
+ }
+
+ if (stat (dev_map, &dev_map_stat) == -1 &&
+- grub_util_get_dev_abstraction (device_name) != GRUB_DEV_ABSTRACTION_NONE)
++ (print == PRINT_DRIVE ||
++ grub_util_get_dev_abstraction (device_name) !=
++ GRUB_DEV_ABSTRACTION_NONE))
+ {
+ /* If we don't have a device map, then we won't yet know about the
+ physical volumes underlying this device, so probe all devices. */
diff --git a/sys-boot/grub/files/ubuntu-upstream-1.98/975_hostdisk_hd.diff b/sys-boot/grub/files/ubuntu-upstream-1.98/975_hostdisk_hd.diff
new file mode 100644
index 00000000..7ea7f5f8
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream-1.98/975_hostdisk_hd.diff
@@ -0,0 +1,114 @@
+Description: Adjust hostdisk id for hard disks
+ This allows grub-setup to use its standard workaround for broken BIOSes.
+Author: Colin Watson <cjwatson@ubuntu.com>
+Bug: http://savannah.gnu.org/bugs/?29464
+Bug-Ubuntu: https://bugs.launchpad.net/bugs/555500
+Forwarded: http://savannah.gnu.org/bugs/?29464
+Last-Update: 2010-04-08
+
+diff -Nur -x '*.orig' -x '*~' grub2/util/hostdisk.c grub2.new/util/hostdisk.c
+--- grub2/util/hostdisk.c 2010-04-08 17:09:02.000000000 +0100
++++ grub2.new/util/hostdisk.c 2010-04-08 17:10:18.000000000 +0100
+@@ -186,6 +186,8 @@
+
+ disk->has_partitions = 1;
+ disk->id = drive;
++ if (strncmp (map[drive].drive, "hd", 2) == 0)
++ disk->id += 0x80;
+ disk->data = data = xmalloc (sizeof (struct grub_util_biosdisk_data));
+ data->dev = NULL;
+ data->access_mode = 0;
+@@ -491,9 +493,9 @@
+ int is_partition = 0;
+ char dev[PATH_MAX];
+
+- strcpy (dev, map[disk->id].device);
++ strcpy (dev, map[disk->id & 0x7f].device);
+ if (disk->partition && sector >= disk->partition->start
+- && strncmp (map[disk->id].device, "/dev/", 5) == 0)
++ && strncmp (map[disk->id & 0x7f].device, "/dev/", 5) == 0)
+ is_partition = linux_find_partition (dev, disk->partition->start);
+
+ if (data->dev && strcmp (data->dev, dev) == 0 &&
+@@ -548,7 +550,7 @@
+ }
+ #endif
+
+- if (data->dev && strcmp (data->dev, map[disk->id].device) == 0 &&
++ if (data->dev && strcmp (data->dev, map[disk->id & 0x7f].device) == 0 &&
+ data->access_mode == (flags & O_ACCMODE))
+ {
+ grub_dprintf ("hostdisk", "reusing open device `%s'\n", data->dev);
+@@ -560,10 +562,10 @@
+ if (data->fd != -1)
+ close (data->fd);
+
+- fd = open (map[disk->id].device, flags);
++ fd = open (map[disk->id & 0x7f].device, flags);
+ if (fd >= 0)
+ {
+- data->dev = xstrdup (map[disk->id].device);
++ data->dev = xstrdup (map[disk->id & 0x7f].device);
+ data->access_mode = (flags & O_ACCMODE);
+ data->fd = fd;
+ }
+@@ -581,12 +583,12 @@
+ #if defined(__APPLE__)
+ /* If we can't have exclusive access, try shared access */
+ if (fd < 0)
+- fd = open(map[disk->id].device, flags | O_SHLOCK);
++ fd = open(map[disk->id & 0x7f].device, flags | O_SHLOCK);
+ #endif
+
+ if (fd < 0)
+ {
+- grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' in open_device()", map[disk->id].device);
++ grub_error (GRUB_ERR_BAD_DEVICE, "cannot open `%s' in open_device()", map[disk->id & 0x7f].device);
+ return -1;
+ }
+ #endif /* ! __linux__ */
+@@ -604,7 +606,7 @@
+ offset = (loff_t) sector << GRUB_DISK_SECTOR_BITS;
+ if (_llseek (fd, offset >> 32, offset & 0xffffffff, &result, SEEK_SET))
+ {
+- grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
++ grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id & 0x7f].device);
+ close (fd);
+ return -1;
+ }
+@@ -615,7 +617,7 @@
+
+ if (lseek (fd, offset, SEEK_SET) != offset)
+ {
+- grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id].device);
++ grub_error (GRUB_ERR_BAD_DEVICE, "cannot seek `%s'", map[disk->id & 0x7f].device);
+ close (fd);
+ return -1;
+ }
+@@ -713,7 +715,7 @@
+ parts. -jochen */
+ if (nread (fd, buf, GRUB_DISK_SECTOR_SIZE) != GRUB_DISK_SECTOR_SIZE)
+ {
+- grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id].device);
++ grub_error (GRUB_ERR_READ_ERROR, "cannot read `%s'", map[disk->id & 0x7f].device);
+ close (fd);
+ return grub_errno;
+ }
+@@ -725,7 +727,7 @@
+
+ if (nread (fd, buf, size << GRUB_DISK_SECTOR_BITS)
+ != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+- grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id].device);
++ grub_error (GRUB_ERR_READ_ERROR, "cannot read from `%s'", map[disk->id & 0x7f].device);
+
+ return grub_errno;
+ }
+@@ -759,7 +761,7 @@
+
+ if (nwrite (fd, buf, size << GRUB_DISK_SECTOR_BITS)
+ != (ssize_t) (size << GRUB_DISK_SECTOR_BITS))
+- grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id].device);
++ grub_error (GRUB_ERR_WRITE_ERROR, "cannot write to `%s'", map[disk->id & 0x7f].device);
+
+ return grub_errno;
+ }
diff --git a/sys-boot/grub/files/ubuntu-upstream/01_uuids_and_lvm_dont_play_along_nicely.diff b/sys-boot/grub/files/ubuntu-upstream/01_uuids_and_lvm_dont_play_along_nicely.diff
new file mode 100644
index 00000000..c997b845
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream/01_uuids_and_lvm_dont_play_along_nicely.diff
@@ -0,0 +1,14 @@
+diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
+index c2da413..cbd9d6b 100644
+--- a/util/grub.d/10_linux.in
++++ b/util/grub.d/10_linux.in
+@@ -36,7 +36,8 @@ case ${GRUB_DEVICE} in
+ esac
+
+ if [ "x${GRUB_DEVICE_UUID}" = "x" ] || [ "x${GRUB_DISABLE_LINUX_UUID}" = "xtrue" ] \
+- || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" ; then
++ || ! test -e "/dev/disk/by-uuid/${GRUB_DEVICE_UUID}" \
++ || [ "`grub-probe -t abstraction --device ${GRUB_DEVICE} | sed -e 's,.*\(lvm\).*,\1,'`" = "lvm" ] ; then
+ LINUX_ROOT_DEVICE=${GRUB_DEVICE}
+ else
+ LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
diff --git a/sys-boot/grub/files/ubuntu-upstream/904_disable_floppies.diff b/sys-boot/grub/files/ubuntu-upstream/904_disable_floppies.diff
new file mode 100644
index 00000000..66a41cdc
--- /dev/null
+++ b/sys-boot/grub/files/ubuntu-upstream/904_disable_floppies.diff
@@ -0,0 +1,28 @@
+
+Author: Robert Millan
+
+An ugly kludge. Should this be merged upstream?
+
+Index: util/hostdisk.c
+===================================================================
+--- util/hostdisk.c (revision 1832)
++++ util/hostdisk.c (working copy)
+@@ -544,6 +544,18 @@
+ continue;
+ }
+
++ if (! strncmp (p, "/dev/fd", sizeof ("/dev/fd") - 1))
++ {
++ char *q = p + sizeof ("/dev/fd") - 1;
++ if (*q >= '0' && *q <= '9')
++ {
++ free (map[drive].drive);
++ map[drive].drive = NULL;
++ grub_util_info ("`%s' looks like a floppy drive, skipping", p);
++ continue;
++ }
++ }
++
+ #ifdef __linux__
+ /* On Linux, the devfs uses symbolic links horribly, and that
+ confuses the interface very much, so use realpath to expand