--- old/bootadm/bootadm.c	2012-08-31 05:08:45.067622085 +0400
+++ new/bootadm/bootadm.c	2012-08-31 05:08:45.155548371 +0400
@@ -21,6 +21,7 @@
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  * Copyright 2012 Milan Jurik. All rights reserved.
+ * Copyright 2012 Daniil Lunev. All rights reserved.
  */
 
 /*
@@ -118,8 +119,8 @@
 
 #define	GRUB_DIR		"/boot/grub"
 #define	GRUB_STAGE2		GRUB_DIR "/stage2"
-#define	GRUB_MENU		"/boot/grub/menu.lst"
-#define	MENU_TMP		"/boot/grub/menu.lst.tmp"
+#define	GRUB_MENU		"/boot/illumos.cfg"
+#define	MENU_TMP		"/boot/illumos.cfg.tmp"
 #define	GRUB_BACKUP_MENU	"/etc/lu/GRUB_backup_menu"
 #define	RAMDISK_SPECIAL		"/ramdisk"
 #define	STUBBOOT		"/stubboot"
@@ -178,20 +179,21 @@
  * menu_cmd_t and menu_cmds must be kept in sync
  */
 char *menu_cmds[] = {
-	"default",	/* DEFAULT_CMD */
+	"default_entry",/* DEFAULT_CMD */
 	"timeout",	/* TIMEOUT_CMD */
-	"title",	/* TITLE_CMD */
-	"root",		/* ROOT_CMD */
-	"kernel",	/* KERNEL_CMD */
-	"kernel$",	/* KERNEL_DOLLAR_CMD */
-	"module",	/* MODULE_CMD */
-	"module$",	/* MODULE_DOLLAR_CMD */
-	" ",		/* SEP_CMD */
+	"entry_name",	/* TITLE_CMD */
+	"pool_uuid",	/* ROOT_CMD */
+	"kernel_path$",	/* KERNEL_CMD */
+	"kernel_path",	/* KERNEL_DOLLAR_CMD */
+	"module$",	/* MODULE_CMD */
+	"module",	/* MODULE_DOLLAR_CMD */
+	"=",		/* SEP_CMD */
 	"#",		/* COMMENT_CMD */
 	"chainloader",	/* CHAINLOADER_CMD */
 	"args",		/* ARGS_CMD */
-	"findroot",	/* FINDROOT_CMD */
-	"bootfs",	/* BOOTFS_CMD */
+	"pool_label",	/* FINDROOT_CMD */
+	"data_set",	/* BOOTFS_CMD */
+	"kernel_options",/* KERNEL_OPTIONS_CMD */
 	NULL
 };
 
@@ -4690,6 +4692,7 @@
 	menu_cmd_t	k_cmd;
 	menu_cmd_t	m_cmd;
 	const char	*fcn = "add_boot_entry()";
+	char * options = NULL;
 
 	assert(mp);
 
@@ -4756,10 +4759,21 @@
 		line_parser(mp, linebuf, &lineNum, &entryNum);
 	}
 
-	(void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
-	    menu_cmds[k_cmd], menu_cmds[SEP_CMD], kernel);
+	options = strpbrk(kernel, " \t");
+	if (options)
+		++options;
+
+	(void) snprintf(linebuf, sizeof (linebuf), "%s%s",
+	    menu_cmds[k_cmd], menu_cmds[SEP_CMD]);
+	(void) strncat(linebuf, kernel, options - kernel);
 	line_parser(mp, linebuf, &lineNum, &entryNum);
 
+	if (options) {
+		(void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
+		    menu_cmds[KERNEL_OPTIONS_CMD], menu_cmds[SEP_CMD], options);
+		line_parser(mp, linebuf, &lineNum, &entryNum);
+	}
+
 	if (mod_kernel != NULL) {
 		(void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
 		    menu_cmds[m_cmd], menu_cmds[SEP_CMD], mod_kernel);
@@ -7112,18 +7126,19 @@
 	slice = strrchr(osdev, 's');
 
 	grubsign = s_calloc(1, MAXNAMELEN + 10);
-	if (slice) {
+/*	if (slice) {
 		(void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d,%c)",
 		    sign, fdiskpart, slice[1] + 'a' - '0');
 	} else
 		(void) snprintf(grubsign, MAXNAMELEN + 10, "(%s,%d)",
-		    sign, fdiskpart);
+		    sign, fdiskpart);*/
+	grubsign = strdup(sign);
 
 	free(sign);
 
 	BAM_DPRINTF((D_GET_GRUBSIGN_SUCCESS, fcn, grubsign));
 
-	return (grubsign);
+	return (strchr(grubsign,'_') + 1);
 }
 
 static char *
@@ -7812,7 +7827,7 @@
 				continue;
 			}
 			/* findroot command found, try match  */
-			if (strcmp(lp->arg, findroot) != 0) {
+			if (strncmp(lp->arg, strchr(findroot, '_') + 1, strlen(lp->arg)) != 0) {
 				BAM_DPRINTF((D_NOMATCH_FINDROOT,
 				    fcn, findroot, lp->arg));
 				continue;
@@ -7870,6 +7885,7 @@
 		 * For xpv entries, there are two module lines, so we
 		 * do the check twice.
 		 */
+		lp = lp->next;	/* advance to options line */
 		lp = lp->next;	/* advance to module line */
 		if (check_cmd(lp->cmd, MODULE_CMD, lp->arg, module) ||
 		    (((lp = lp->next) != NULL) &&
@@ -7911,6 +7927,7 @@
 	line_t		*tlp;
 	char		linebuf[BAM_MAXLINE];
 	const char	*fcn = "update_boot_entry()";
+	char 		*label;
 
 	/* note: don't match on title, it's updated on upgrade */
 	ent = find_boot_entry(mp, NULL, kernel, findroot, root, module,
@@ -7967,10 +7984,13 @@
 
 	lp->cmd = s_strdup(menu_cmds[FINDROOT_CMD]);
 	lp->sep = s_strdup(menu_cmds[SEP_CMD]);
-	lp->arg = s_strdup(findroot);
+	label = s_strdup(strchr(findroot, '_') + 1);
+	*(strchr(label,',')) = 0;
+	lp->arg = s_strdup(label);
 	(void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
-	    menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], findroot);
+	    menu_cmds[FINDROOT_CMD], menu_cmds[SEP_CMD], label);
 	lp->line = s_strdup(linebuf);
+	free(label);
 	BAM_DPRINTF((D_ADDING_FINDROOT_LINE, fcn, findroot));
 
 	/* kernel line */
@@ -7978,16 +7998,13 @@
 
 	if (ent->flags & BAM_ENTRY_UPGFSKERNEL) {
 		char		*params = NULL;
+		char		*opts = NULL;
 
-		params = strstr(lp->line, "-s");
-		if (params != NULL)
-			(void) snprintf(linebuf, sizeof (linebuf), "%s%s%s%s",
-			    menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
-			    kernel, params+2);
-		else
-			(void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
-			    menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
-			    kernel);
+		opts = strpbrk(kernel, " \t");
+		*opts++ = '\0';
+		(void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
+		    menu_cmds[KERNEL_DOLLAR_CMD], menu_cmds[SEP_CMD],
+		    kernel);
 
 		if (lp->cmd != NULL)
 			free(lp->cmd);
@@ -7999,12 +8016,28 @@
 		lp->line = s_strdup(linebuf);
 		ent->flags &= ~BAM_ENTRY_UPGFSKERNEL;
 		BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, lp->prev->cmd));
+
+		lp = lp->next;
+		params = strstr(lp->arg, "-s");
+		free(lp->arg);
+		free(lp->line);
+		if (params)
+			(void) snprintf(linebuf, sizeof(linebuf), "%s%s%s -s",
+				lp->cmd, menu_cmds[SEP_CMD],opts);
+		else
+			(void) snprintf(linebuf, sizeof(linebuf), "%s%s%s",
+				lp->cmd, menu_cmds[SEP_CMD],opts);
+		lp->line = s_strdup(linebuf);
+		lp->arg = s_strdup(strchr(linebuf, '=') + 1);
 	}
 
 	if (change_kernel) {
+		char		*opts = NULL;
 		/*
 		 * We're upgrading from multiboot to directboot.
 		 */
+		opts = strpbrk(kernel, " \t");
+		*opts++ = '\0';
 		if (lp->cmd != NULL &&
 		    strcmp(lp->cmd, menu_cmds[KERNEL_CMD]) == 0) {
 			(void) snprintf(linebuf, sizeof (linebuf), "%s%s%s",
@@ -8018,6 +8051,12 @@
 			lp->line = s_strdup(linebuf);
 			lp = lp->next;
 			BAM_DPRINTF((D_ADDING_KERNEL_DOLLAR, fcn, kernel));
+			(void) snprintf(linebuf, sizeof(linebuf), "%s%s%s",
+				lp->cmd, menu_cmds[SEP_CMD],opts);
+			free(lp->arg);
+			free(lp->line);
+			lp->line = s_strdup(linebuf);
+			lp->arg = s_strdup(strchr(linebuf, '=') + 1);
 		}
 		if (lp->cmd != NULL &&
 		    strcmp(lp->cmd, menu_cmds[MODULE_CMD]) == 0) {
@@ -8410,6 +8449,7 @@
 	}
 
 	sign = find_existing_sign("/", osdev, fstype);
+	sign = strchr(sign, '_') + 1;
 	INJECT_ERROR1("REBOOT_SIGN_NULL", sign = NULL);
 	if (sign == NULL) {
 		free(fstype);
@@ -8858,7 +8898,7 @@
 		for (ptr = entryp->start; ptr && ptr != entryp->end;
 		    ptr = ptr->next) {
 			if (strncmp(ptr->cmd, menu_cmds[KERNEL_CMD],
-			    sizeof (menu_cmds[KERNEL_CMD]) - 1) == 0) {
+			    sizeof (menu_cmds[KERNEL_CMD]) - 2) == 0) {
 				kernelp = ptr;
 				break;
 			}
@@ -8946,8 +8986,8 @@
 			new_str_len = (sizeof (DIRECT_BOOT_KERNEL) - 1) +
 			    strlen(old_args) + 2;
 			new_arg = s_calloc(1, new_str_len);
-			(void) snprintf(new_arg, new_str_len, "%s %s",
-			    DIRECT_BOOT_KERNEL, old_args);
+			(void) snprintf(new_arg, new_str_len, "%s",
+			    DIRECT_BOOT_KERNEL);
 			free(kernelp->arg);
 			kernelp->arg = new_arg;
 
@@ -9108,9 +9148,10 @@
 		BAM_DPRINTF((D_GET_SET_KERNEL_REPLACED_KERNEL_SAME_ARG, fcn,
 		    kernelp->arg));
 	} else {
-		new_str_len = old_kernel_len + strlen(path) + 8;
+		kernelp = kernelp->next;
+		new_str_len = strlen(kernelp->arg) + strlen(path) + 8;
 		new_arg = s_calloc(1, new_str_len);
-		(void) strncpy(new_arg, kernelp->arg, old_kernel_len);
+		(void) strncpy(new_arg, kernelp->arg, strlen(kernelp->arg));
 		(void) strlcat(new_arg, " ", new_str_len);
 		(void) strlcat(new_arg, path, new_str_len);
 		free(kernelp->arg);
--- old/bootadm/bootadm.h	2012-08-31 05:08:47.497329891 +0400
+++ new/bootadm/bootadm.h	2012-08-31 05:08:47.522789144 +0400
@@ -126,7 +126,8 @@
 	CHAINLOADER_CMD,
 	ARGS_CMD,
 	FINDROOT_CMD,
-	BOOTFS_CMD
+	BOOTFS_CMD,
+	KERNEL_OPTIONS_CMD,
 } menu_cmd_t;
 
 extern char *menu_cmds[];
@@ -217,7 +218,7 @@
 #define	NEW_HV_ENTRY	"Solaris xVM"
 
 /* ZFS boot option */
-#define	ZFS_BOOT	"-B $ZFS-BOOTFS"
+#define	ZFS_BOOT	"-B $ZFS_BOOTFS"
 
 /* multiboot */
 #define	MULTI_BOOT	"/platform/i86pc/multiboot"
--- old/bootadm/bootadm_hyper.c	2012-08-31 05:08:48.139702554 +0400
+++ new/bootadm/bootadm_hyper.c	2012-08-31 05:08:48.156871361 +0400
@@ -23,6 +23,10 @@
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
+/*
+ * Copyright 2012 Daniil Lunev. All rights reserved.
+ */
+
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
@@ -39,7 +43,7 @@
 #define	METAL_KERNEL_DIR 		"/platform/i86pc/kernel"
 
 #define	BOOTRC_FILE			"/boot/solaris/bootenv.rc"
-#define	ZFS_BOOTSTR			"$ZFS-BOOTFS"
+#define	ZFS_BOOTSTR			"$ZFS_BOOTFS"
 
 #define	BFLAG				"-B"
 #define	DEFAULT_SERIAL			"9600,8,n,1"
@@ -763,8 +767,10 @@
 	char *findroot = NULL;
 	char *bootfs = NULL;
 	char *kernel = NULL;
+	char *opts = NULL;
 	char *mod_kernel = NULL;
 	char *module = NULL;
+	char *tmp = NULL;
 
 	char *kern_path = NULL;
 	char *kern_bargs = NULL;
@@ -841,10 +847,12 @@
 		if (lp->flags == BAM_TITLE) {
 			title = strdupa(lp->arg);
 		} else if (lp->cmd != NULL) {
-			if (strcmp(lp->cmd, "findroot") == 0) {
+			if (strcmp(lp->cmd, "pool_label") == 0) {
 				findroot = strdupa(lp->arg);
-			} else if (strcmp(lp->cmd, "bootfs") == 0) {
+			} else if (strcmp(lp->cmd, "data_set") == 0) {
 				bootfs = strdupa(lp->arg);
+			} else if (strcmp(lp->cmd, "kernel_options") == 0) {
+				opts = strdupa(lp->arg);
 			} else if (strcmp(lp->cmd,
 			    menu_cmds[MODULE_DOLLAR_CMD]) == 0) {
 				module = strdupa(lp->arg);
@@ -866,6 +874,7 @@
 			break;
 	}
 
+	
 	/*
 	 * If findroot, module or kern_path are NULL, the boot entry is
 	 * malformed.
@@ -948,7 +957,10 @@
 	zfslen = (zfs_boot ? (WHITESPC(1) + strlen(ZFS_BOOT)) : 0);
 
 	mod_kernel = alloca(len + zfslen);
-	(void) snprintf(mod_kernel, len, "%s %s", kern_path, kern_path);
+	if (opts)
+		(void) snprintf(mod_kernel, len + strlen(opts) + 1, "%s %s %s", kern_path, kern_path, opts);
+	else
+		(void) snprintf(mod_kernel, len, "%s %s", kern_path, kern_path);
 
 	if (kp_allocated)
 		free(kern_path);
@@ -1062,9 +1074,9 @@
 		if (lp->flags == BAM_TITLE) {
 			title = strdupa(lp->arg);
 		} else if (lp->cmd != NULL) {
-			if (strcmp(lp->cmd, "findroot") == 0) {
+			if (strcmp(lp->cmd, "pool_label") == 0) {
 				findroot = strdupa(lp->arg);
-			} else if (strcmp(lp->cmd, "bootfs") == 0) {
+			} else if (strcmp(lp->cmd, "data_set") == 0) {
 				bootfs = strdupa(lp->arg);
 			} else if (strcmp(lp->cmd,
 			    menu_cmds[MODULE_DOLLAR_CMD]) == 0) {
--- old/grub/Makefile.util.def	2012-08-31 05:08:49.123997809 +0400
+++ new/grub/Makefile.util.def	2012-08-31 05:08:49.186444990 +0400
@@ -304,6 +304,21 @@
 };
 
 program = {
+  name = grub-solarislst2cfg;
+  installdir = sbin;
+  mansection = 8;
+  common = util/grub-solarislst2cfg.c;
+  common = util/ieee1275/ofpath.c;
+  common = grub-core/kern/emu/argp_common.c;
+
+  ldadd = libgrubmods.a;
+  ldadd = libgrubgcry.a;
+  ldadd = libgrubkern.a;
+  ldadd = grub-core/gnulib/libgnu.a;
+  ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+};
+
+program = {
   name = grub-bios-setup;
   installdir = sbin;
   mansection = 8;
--- old/grub/grub-core/Makefile.core.def	2012-08-31 05:08:49.854539106 +0400
+++ new/grub/grub-core/Makefile.core.def	2012-08-31 05:08:49.890410130 +0400
@@ -1484,6 +1484,16 @@
 };
 
 module = {
+  name = illumos_entries;
+  common = commands/illumos_entries.c;
+};
+
+module = {
+  name = solarislegacy;
+  common = commands/solarislegacy.c;
+};
+
+module = {
   name = part_acorn;
   common = partmap/acorn.c;
 };
--- /dev/null	2012-08-31 05:08:50.000000000 +0400
+++ new/grub/grub-core/commands/illumos_entries.c	2012-08-31 05:08:50.595738459 +0400
@@ -0,0 +1,197 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012 Daniil Lunev
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/normal.h>
+
+#include "menu_managing.c"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] = {
+  {0, 0, 0, 0, 0, 0}
+};
+
+static const char * globals[] = {
+  "default_entry",
+  "timeout",
+  "serial",
+  "terminal",
+  NULL
+};
+
+static grub_err_t
+get_value(char * buf, char ** value)
+{
+  *value = grub_strchr(buf, '=');
+  if (! *value)
+    return grub_error (GRUB_ERR_INVALID_COMMAND, N_("illumos syntax error"));
+  **value = '\0';
+  ++(*value);
+  return 0;
+}
+
+static int
+check_param(char * param)
+{
+  int i = 0;
+  
+  for (; params_list[i]; ++i)
+    if (!grub_strcmp(param, params_list[i]))
+      return i;
+  
+  return -1;
+}
+
+static int
+check_global(char * param)
+{
+  int i = 0;
+  
+  for (; globals[i]; ++i)
+    if (!grub_strcmp(param, globals[i]))
+      return i;
+  
+  return -1;
+}
+
+static grub_err_t
+parse_config(grub_file_t file, entries * entry_list)
+{
+  char * param;
+  char * value;
+  entries * current_entry = NULL;
+  int param_id = 0;
+  int global_id = 0;
+  grub_err_t err;
+  
+  for(;;) {
+    param = grub_file_getline(file);
+    if (! param)
+      return grub_errno;
+
+    if ((*param == '#') || (*param == ' ') || 
+      (*param == '\t') || (*param == '\n') ||
+      (*param == 0)) {
+      grub_free(param);
+      continue;
+    }
+    global_id = -1;
+      
+    err = get_value(param, &value);
+    if (err)
+      return err;
+
+    param_id = check_param(param);
+    if (param_id < 0) {
+      global_id = check_global(param);
+      if (global_id < 0) {
+        grub_free(param);
+        return grub_error (GRUB_ERR_INVALID_COMMAND, N_("illumos syntax error"));
+      }
+    }
+    if (err)
+      return err;
+    if (!value[0])
+      return grub_error (GRUB_ERR_INVALID_COMMAND, N_("illumos syntax error"));
+    if (global_id < 0) {
+      if (param_id == 0) {
+        current_entry = new_entry(value, entry_list);
+        if (! current_entry) {
+          grub_free(param);
+          return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory can not be allocated"));
+        }
+      } else {
+        grub_strcpy(current_entry->entry_info[param_id], value);
+      }
+    } else {
+      char line[512];
+      switch (global_id) {
+      case 0:
+        grub_env_set("default", value);
+        break;
+      case 1:
+        grub_env_set("timeout", value);
+        break;
+      case 2:
+        grub_strcpy(line, "serial ");
+        grub_strcat(line, value);
+        grub_normal_parse_line(line, NULL);
+        break;
+      case 3:
+        grub_strcpy(line, "terminal_input ");
+        grub_strcat(line, value);
+        grub_strcat(line, "; terminal_output ");
+        grub_strcat(line, value);
+        grub_normal_parse_line(line, NULL);
+        break;
+      default:
+        break;
+      }
+    }
+    grub_free(param);
+  }    
+  return 0;
+}
+
+static grub_err_t
+grub_cmd_illumos_entries (grub_extcmd_context_t ctxt __attribute__ ((unused)), int argc, char **args)
+{
+  grub_file_t file;
+  entries * menu_entries = NULL;
+  
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+  
+  file = grub_file_open(args[0]);
+  
+  if (!file)
+    return grub_errno;
+    
+  init_entries(&menu_entries);
+  
+  if (parse_config(file, menu_entries) == 0) {
+    add_entries(menu_entries);
+  }  
+  clear_entries(menu_entries);
+  
+  grub_refresh();
+  grub_file_close(file);
+
+  return 0;
+}
+
+static grub_extcmd_t illumos_entries;
+
+GRUB_MOD_INIT(illumos_entries)
+{
+  illumos_entries = grub_register_extcmd ("illumos_entries", grub_cmd_illumos_entries, 0,
+            N_("FILE"), N_("Define an illumos menu entries."), options);
+}
+
+GRUB_MOD_FINI(illumos_entries)
+{
+  grub_unregister_extcmd (illumos_entries);
+}
--- /dev/null	2012-08-31 05:08:50.000000000 +0400
+++ new/grub/grub-core/commands/menu_managing.c	2012-08-31 05:08:50.915580323 +0400
@@ -0,0 +1,200 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012 Daniil Lunev
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define VALUE_SIZE 512
+
+typedef struct entries entries;
+struct entries {
+  entries *next;
+  char ** entry_info;
+};
+
+enum param_consts {
+  ENTRY_NAME,
+  POOL_UUID,
+  POOL_LABEL,
+  DATA_SET,
+  KERNEL_PATH,
+  KERNEL_OPTIONS,
+  BA_PATH,
+  DOLLAR_KERNEL_PATH,
+  DOLLAR_BA_PATH,
+};
+
+static const char * params_list[] = {
+  "entry_name",
+  "pool_uuid",
+  "pool_label",
+  "data_set",
+  "kernel_path",
+  "kernel_options",
+  "module",
+  "kernel_path$",
+  "module$",
+  NULL
+};
+
+static grub_err_t
+init_entries(entries ** menu_entries)
+{
+  (*menu_entries) = (entries*) grub_zalloc(sizeof (menu_entries));
+  if (! *menu_entries)
+    return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory can not be allocated"));
+  return 0;
+}
+
+static entries * 
+new_entry(char * name, entries * entry_list)
+{
+  unsigned int i;
+
+  if (entry_list->next)
+    do {
+      entry_list = entry_list->next;
+      if (!grub_strcmp(name, entry_list->entry_info[0]))
+        return entry_list;
+    } while (entry_list->next);
+  entry_list->next = (entries*) grub_zalloc(sizeof(entries));
+  if (! entry_list->next)
+    return NULL;
+  entry_list = entry_list->next;
+  entry_list->entry_info = (char**) grub_zalloc(sizeof(params_list));
+  for (i = 0; i < sizeof(params_list) / sizeof(*params_list); i++) {
+    entry_list->entry_info[i] = (char *) grub_zalloc(VALUE_SIZE);
+    if (! entry_list->entry_info[i]) 
+      return NULL;
+  }
+  grub_strcpy(entry_list->entry_info[0], name);
+  return entry_list;
+}
+
+static void
+clear_entries(entries * entry_list)
+{
+  entries * next;
+  unsigned int i;
+
+  next = entry_list->next;
+  grub_free(entry_list);
+  entry_list = next;
+
+  while (entry_list) {
+    next = entry_list->next;
+    if (entry_list->entry_info) {
+      for (i = 0; i < sizeof(params_list) / sizeof(*params_list); i++)
+        if (entry_list->entry_info[i])
+          grub_free(entry_list->entry_info[i]);
+      grub_free(entry_list->entry_info);
+    }
+    grub_free(entry_list);
+    entry_list = next;
+  }
+}
+
+static grub_err_t
+add_entries(entries * menu_entries)
+{
+  grub_err_t err;
+  char cl1[] = "os";
+  char cl2[] = "illumos";
+  char * class[] = {cl1, cl2, NULL};
+  char * argv[] = { NULL, NULL };
+  char id[512];
+  char * entry_source = NULL;
+  char * data_set;
+  char entry_template[] = 
+    "insmod part_sunpc\n"
+    "insmod part_msdos\n"
+    "insmod zfs\n"
+    "insmod gzio\n"
+    "if cpuid -l ; then\n"
+    "  ISADIR=amd64\n"
+    "else\n"
+    "  ISADIR=\n"
+    "fi\n";
+
+  menu_entries = menu_entries->next;
+  while (menu_entries) {
+    argv[0] = grub_strdup(menu_entries->entry_info[ENTRY_NAME]);
+    if (!argv[0])
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory can not be allocated"));
+    entry_source = (char*) grub_zalloc(2048);
+
+    if (!entry_source)
+      return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("memory can not be allocated"));
+
+    if (menu_entries->entry_info[DATA_SET][0] != 0)
+      data_set = grub_strchr(menu_entries->entry_info[DATA_SET], '/');
+    else
+      data_set = grub_strdup("$ZFS_DATASET");
+    grub_strcpy(entry_source, entry_template);
+    if (menu_entries->entry_info[POOL_UUID][0]) {
+      grub_strcat(entry_source, "search --no-floppy --zfs-mirror --fs-uuid --set=root ");
+      grub_strcat(entry_source, menu_entries->entry_info[POOL_UUID]);
+    } else {
+      grub_strcat(entry_source, "search --no-floppy --zfs-mirror --label --set=root ");
+      grub_strcat(entry_source, menu_entries->entry_info[POOL_LABEL]);
+    }
+    grub_strcat(entry_source, "\n");
+    grub_strcat(entry_source, "zfs-bootfs ($root)");
+    if (menu_entries->entry_info[DATA_SET][0] != 0) {
+      grub_strcat(entry_source, data_set);
+      grub_strcat(entry_source, " ZFS_BOOTFS\n");
+    } else {
+      grub_strcat(entry_source, "default ZFS_BOOTFS ZFS_DATASET\n");
+    }
+    grub_strcat(entry_source, "multiboot ($root)");
+    if (! menu_entries->entry_info[DOLLAR_KERNEL_PATH][0]) {
+      grub_strcat(entry_source, data_set);
+      grub_strcat(entry_source, "/@");
+      grub_strcat(entry_source, menu_entries->entry_info[KERNEL_PATH]);
+      grub_strcat(entry_source, " ");
+      grub_strcat(entry_source, menu_entries->entry_info[KERNEL_PATH]);
+    } else {
+      grub_strcat(entry_source, menu_entries->entry_info[DOLLAR_KERNEL_PATH]);
+    }
+    grub_strcat(entry_source, " ");
+    grub_strcat(entry_source, menu_entries->entry_info[KERNEL_OPTIONS]);
+    grub_strcat(entry_source, "\n");
+    grub_strcat(entry_source, "module ($root)");
+    if (! menu_entries->entry_info[DOLLAR_KERNEL_PATH][0]) {
+      grub_strcat(entry_source, data_set);
+      grub_strcat(entry_source, "/@");
+      grub_strcat(entry_source, menu_entries->entry_info[BA_PATH]);
+      grub_strcat(entry_source, " ");
+      grub_strcat(entry_source, menu_entries->entry_info[BA_PATH]);
+    } else {
+      grub_strcat(entry_source, menu_entries->entry_info[DOLLAR_BA_PATH]);
+    }
+
+    grub_strcpy(id, argv[0]);
+    grub_strcat(id, "-");
+    grub_strcat(id, menu_entries->entry_info[POOL_UUID]);
+
+    err = grub_normal_add_menu_entry (2, (const char **) argv, class, id,
+                NULL,  NULL,  NULL, entry_source, 0);
+
+    if (err)
+      return err;
+    
+    grub_free(argv[0]);
+    menu_entries = menu_entries->next;
+  }
+  grub_free(entry_source);
+  return 0;
+}
--- old/grub/grub-core/commands/search.c	2012-08-31 05:08:51.218990708 +0400
+++ new/grub/grub-core/commands/search.c	2012-08-31 05:08:51.245945407 +0400
@@ -22,6 +22,7 @@
 #include <grub/mm.h>
 #include <grub/err.h>
 #include <grub/dl.h>
+#include <grub/zfs/zfs.h>
 #include <grub/device.h>
 #include <grub/file.h>
 #include <grub/env.h>
@@ -44,10 +45,11 @@
 
 void
 FUNC_NAME (const char *key, const char *var, int no_floppy,
-	   char **hints, unsigned nhints)
+	   char **hints, unsigned nhints, int mirror)
 {
   int count = 0;
   int is_cache = 0;
+  grub_uint64_t txg = 0;
   grub_fs_autoload_hook_t saved_autoload;
 
   auto int iterate_device (const char *name);
@@ -148,14 +150,35 @@
     if (found)
       {
 	count++;
-	if (var)
-	  grub_env_set (var, name);
-	else
+	if (var) {
+          if (! mirror) {
+	    grub_env_set (var, name);
+          } else {
+            grub_uint64_t tmp_txg = 0;
+            char * nvlist = NULL;
+            grub_device_t dev = grub_device_open (name);
+            if (! dev) {
+              grub_errno = GRUB_ERR_BAD_DEVICE;
+              return 0;
+            }
+            grub_errno = grub_zfs_fetch_nvlist (dev, &nvlist);
+            grub_device_close (dev);
+            if (grub_errno)
+              return 0;
+            grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_POOL_TXG, &tmp_txg);
+            if (tmp_txg > txg) {
+	      grub_env_set (var, name);
+              txg = tmp_txg;
+            }
+            grub_free (nvlist);
+          }
+	} else {
 	  grub_printf (" %s", name);
+        }
       }
 
     grub_errno = GRUB_ERR_NONE;
-    return (found && var);
+    return (found && var && !mirror);
   }
 
   auto int part_hook (grub_disk_t disk, const grub_partition_t partition);
@@ -280,7 +303,7 @@
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
 
   FUNC_NAME (args[0], argc == 1 ? 0 : args[1], 0, (args + 2),
-	     argc > 2 ? argc - 2 : 0);
+	     argc > 2 ? argc - 2 : 0, 0);
 
   return grub_errno;
 }
--- old/grub/grub-core/commands/search_wrap.c	2012-08-31 05:08:51.868877048 +0400
+++ new/grub/grub-core/commands/search_wrap.c	2012-08-31 05:08:51.884072587 +0400
@@ -63,6 +63,7 @@
      N_("First try the device HINT if currently running on ARC."
 	" If HINT ends in comma, also try subpartitions"),
      N_("HINT"), ARG_TYPE_STRING},
+    {"zfs-mirror", 'z', 0, N_("Handle zfs-mirror disk"), 0, 0},
     {0, 0, 0, 0, 0, 0}
   };
 
@@ -79,6 +80,7 @@
     SEARCH_HINT_BAREMETAL,
     SEARCH_HINT_EFI,
     SEARCH_HINT_ARC,
+    SEARCH_ZFS_MIRROR,
  };
 
 static grub_err_t
@@ -89,6 +91,7 @@
   const char *id = 0;
   int i = 0, j = 0, nhints = 0;
   char **hints = NULL;
+  int mirror_mode = 0;
 
   if (state[SEARCH_HINT].set)
     for (i = 0; state[SEARCH_HINT].args[i]; i++)
@@ -177,15 +180,18 @@
   else
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
 
+  if (state[SEARCH_ZFS_MIRROR].set)
+    mirror_mode = 1;
+
   if (state[SEARCH_LABEL].set)
     grub_search_label (id, var, state[SEARCH_NO_FLOPPY].set, 
-		       hints, nhints);
+		       hints, nhints, mirror_mode);
   else if (state[SEARCH_FS_UUID].set)
     grub_search_fs_uuid (id, var, state[SEARCH_NO_FLOPPY].set,
-			 hints, nhints);
+			 hints, nhints, mirror_mode);
   else if (state[SEARCH_FILE].set)
     grub_search_fs_file (id, var, state[SEARCH_NO_FLOPPY].set, 
-			 hints, nhints);
+			 hints, nhints, mirror_mode);
   else
     return grub_error (GRUB_ERR_INVALID_COMMAND, "unspecified search type");
 
--- /dev/null	2012-08-31 05:08:52.000000000 +0400
+++ new/grub/grub-core/commands/solarislegacy.c	2012-08-31 05:08:52.513929459 +0400
@@ -0,0 +1,213 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012 Daniil Lunev
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/normal.h>
+#include <grub/script_sh.h>
+#include <grub/i18n.h>
+#include <grub/term.h>
+#include <grub/legacy_parse.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/disk.h>
+#include <grub/partition.h>
+
+#include "menu_managing.c"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static entries *
+parse_entries(grub_file_t file)
+{
+  entries * list = NULL;
+  entries * current = NULL;
+  init_entries(&list);
+  for(;;) {
+    char * buf = grub_file_getline(file);
+    char * param = buf;
+    char * value;
+    
+    if (! buf) 
+      break;
+  
+    if ((buf[0] == '#') || (buf[0] == ' ') ||
+      (buf[0] == '\t') || (buf[0] == '\n')) {
+      grub_free(buf);
+      continue;
+    }
+
+    while ((*param == ' ') || (*param == '\t'))
+      ++param;
+
+    value = grub_strchr(param, ' ');
+    if (! value)
+      value = grub_strchr(param, '\t');
+
+    if (! value) {
+      grub_free(buf);
+      continue;
+    }
+
+    *value++ = 0;
+    while ((*value == ' ') || (*value == '\t'))
+      ++value;
+
+    if ((*value == '\0') || (*value == '\n')) {
+      grub_free(buf);
+      continue;
+    }
+    
+    if (! grub_strcmp(param, "default")) {
+    } else if (! grub_strcmp(param, "timeout")) {
+    } else if (! grub_strcmp(param, "serial")) {
+    } else if (! grub_strcmp(param, "terminal")) {
+    } else if (! grub_strcmp(param, "title")) {
+      current = new_entry(value, list);
+    } else if (! grub_strcmp(param, "bootfs")) {
+      char * lpath;
+      if (! current) {
+        grub_free(buf);
+        grub_error (GRUB_ERR_INVALID_COMMAND, N_("illumos syntax error"));
+        return NULL;
+      }
+      lpath = grub_strchr(value, '/');
+      *lpath = 0;
+      grub_strcpy(current->entry_info[POOL_LABEL], value);
+      *lpath = '/';
+      grub_strcpy(current->entry_info[DATA_SET], lpath);
+    } else if (! grub_strcmp(param, "kernel$")) {
+      char * ender;
+      ender = grub_strchr(value, ' ');
+      if (! ender)  
+        ender = grub_strchr(value, '\t');
+      if (ender)
+        *ender = 0;
+      grub_strcpy(current->entry_info[KERNEL_PATH], value);
+      if (ender) {
+        ++ender;
+        while ((*ender == ' ') || (*ender == '\t'))
+          ++ender;
+        grub_strcpy(current->entry_info[KERNEL_OPTIONS], ender);
+      }
+    } else if (! grub_strcmp(param, "module$")) {
+      grub_strcpy(current->entry_info[BA_PATH], value);
+    } else {
+      grub_free(buf);
+      continue;
+    }
+    grub_free(buf);
+  }
+  return list;
+}
+
+static grub_err_t
+grub_solaris_legacy_cmd(struct grub_command *cmd,
+      int argc, char **args)
+{
+  int new_env, extractor;
+  extractor = (cmd->name[0] == 'e');
+  new_env = (cmd->name[extractor ? (sizeof ("extract_slegacy_entries_") - 1)
+           : (sizeof ("slegacy_") - 1)] == 'c');
+
+
+  if (argc != 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+  grub_file_t file = grub_file_open(args[0]);
+
+  if (new_env)
+    grub_cls ();
+
+  if (new_env && !extractor)
+    grub_env_context_open ();
+  if (extractor)
+    grub_env_extractor_open (!new_env);
+
+  if (! file)
+    return grub_errno;
+
+  entries * list = parse_entries(file);
+
+  if (! list) {
+    return grub_error (GRUB_ERR_INVALID_COMMAND, N_("illumos syntax error"));
+  }
+  
+  add_entries(list);
+
+  if (new_env)
+  {
+    grub_menu_t menu;
+    menu = grub_env_get_menu ();
+    if (menu && menu->size)
+    grub_show_menu (menu, 1, 0);
+    if (!extractor)
+      grub_env_context_close ();
+  }
+  if (extractor)
+    grub_env_extractor_close (!new_env);
+
+  clear_entries(list);
+
+  grub_file_close(file);
+  return 0;
+}
+
+static grub_command_t cmd_source, cmd_configfile;
+static grub_command_t cmd_source_extract, cmd_configfile_extract;
+
+GRUB_MOD_INIT(solaris_legacy)
+{  
+  cmd_source
+    = grub_register_command ("slegacy_source",
+           grub_solaris_legacy_cmd,
+           N_("FILE"),
+           /* TRANSLATORS: "legacy config" means
+        "config as used by grub-legacy".  */
+           N_("Parse legacy config in same context"));
+  cmd_configfile
+    = grub_register_command ("slegacy_configfile",
+           grub_solaris_legacy_cmd,
+           N_("FILE"),
+           N_("Parse legacy config in new context"));
+  cmd_source_extract
+    = grub_register_command ("extract_slegacy_entries_source",
+           grub_solaris_legacy_cmd,
+           N_("FILE"),
+           N_("Parse legacy config in same context taking only menu entries"));
+  cmd_configfile_extract
+    = grub_register_command ("extract_slegacy_entries_configfile",
+           grub_solaris_legacy_cmd,
+           N_("FILE"),
+           N_("Parse legacy config in new context taking only menu entries"));
+
+
+}
+
+GRUB_MOD_FINI(solaris_legacy) 
+{
+  grub_unregister_command (cmd_source);
+  grub_unregister_command (cmd_configfile);
+  grub_unregister_command (cmd_source_extract);
+  grub_unregister_command (cmd_configfile_extract);
+}
--- old/grub/grub-core/fs/zfs/zfs.c	2012-08-31 05:08:52.910868093 +0400
+++ new/grub/grub-core/fs/zfs/zfs.c	2012-08-31 05:08:52.975514462 +0400
@@ -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 2012  Daniil Lunev
  *
  *  GRUB is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -224,6 +225,20 @@
   } *keyring;
 };
 
+static const char * feature_list[] = {
+  "localhost:unknown_feature",
+  NULL,
+};
+
+typedef enum zfs_feature_id {
+  ZFS_FEATURE_UNKNOWN,
+} zfs_feature_id_t;
+
+struct enabled_feature_list {
+  struct enabled_feature_list * next;
+  zfs_feature_id_t id;
+};
+
 struct grub_zfs_data
 {
   /* cache for a file block of the currently zfs_open()-ed file */
@@ -249,6 +264,8 @@
 
   uberblock_t current_uberblock;
 
+  struct enabled_feature_list * feature_list;
+  
   int mounted;
   grub_uint64_t guid;
 };
@@ -482,15 +499,11 @@
 
   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)
+      && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_LITTLE_ENDIAN) > 0)
     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)
+      && grub_zfs_to_cpu64 (uber->ub_version, GRUB_ZFS_BIG_ENDIAN) > 0)
     endian = GRUB_ZFS_BIG_ENDIAN;
 
   if (endian == GRUB_ZFS_UNKNOWN_ENDIAN)
@@ -836,15 +849,6 @@
       return grub_errno;
     }
   grub_dprintf ("zfs", "check 8 passed\n");
-
-  if (version > SPA_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);
-    }
   grub_dprintf ("zfs", "check 9 passed\n");
 
   found = grub_zfs_nvlist_lookup_uint64 (nvlist, ZPOOL_CONFIG_GUID,
@@ -1774,11 +1778,11 @@
   for (i = 0; i < chunks; i++)
     {
       if (case_insensitive ? (grub_strcasecmp (mzap_ent[i].mze_name, name) == 0)
-	  : (grub_strcmp (mzap_ent[i].mze_name, name) == 0))
-	{
-	  *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian);
-	  return GRUB_ERR_NONE;
-	}
+    	    : (grub_strcmp (mzap_ent[i].mze_name, name) == 0))
+ 	  {
+	    *value = grub_zfs_to_cpu64 (mzap_ent[i].mze_value, endian);
+	    return GRUB_ERR_NONE;
+	  }
     }
 
   return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("file `%s' not found"), name);
@@ -2670,56 +2674,49 @@
   return err;
 }
 
-#if 0
+#if 1
 /*
  * Get the default 'bootfs' property value from the rootpool.
  *
  */
 static grub_err_t
-get_default_bootfsobj (dnode_phys_t * mosmdn, grub_uint64_t * obj,
+get_default_bootfsobj (dnode_end_t * mosmdn, grub_uint64_t * obj,
 		       struct grub_zfs_data *data)
 {
   grub_uint64_t objnum = 0;
-  dnode_phys_t *dn;
-  if (!dn)
-    return grub_errno;
+  dnode_end_t dn;
 
   if ((grub_errno = dnode_get (mosmdn, DMU_POOL_DIRECTORY_OBJECT,
-			       DMU_OT_OBJECT_DIRECTORY, dn, data)))
+			       DMU_OT_OBJECT_DIRECTORY, &dn, data)))
     {
-      grub_free (dn);
       return (grub_errno);
     }
-
   /*
    * find the object number for 'pool_props', and get the dnode
    * of the 'pool_props'.
    */
-  if (zap_lookup (dn, DMU_POOL_PROPS, &objnum, data))
+  if (zap_lookup (&dn, DMU_POOL_PROPS, &objnum, data, 0))
     {
-      grub_free (dn);
       return (GRUB_ERR_BAD_FS);
     }
-  if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, dn, data)))
+  if ((grub_errno = dnode_get (mosmdn, objnum, DMU_OT_POOL_PROPS, &dn, data)))
     {
-      grub_free (dn);
       return (grub_errno);
     }
-  if (zap_lookup (dn, ZPOOL_PROP_BOOTFS, &objnum, data))
+  if (zap_lookup (&dn, ZPOOL_PROP_BOOTFS, &objnum, data,0))
     {
-      grub_free (dn);
       return (GRUB_ERR_BAD_FS);
     }
 
   if (!objnum)
     {
-      grub_free (dn);
       return (GRUB_ERR_BAD_FS);
     }
 
   *obj = objnum;
   return (0);
 }
+
 #endif
 /*
  * Given a MOS metadnode, get the metadnode of a given filesystem name (fsname),
@@ -3320,9 +3317,117 @@
   for (i = 0; i < data->subvol.nkeys; i++)
     grub_crypto_cipher_close (data->subvol.keyring[i].cipher);
   grub_free (data->subvol.keyring);
+  while (data->feature_list) {
+    struct enabled_feature_list * tmp = data->feature_list;
+    data->feature_list = data->feature_list->next;
+    grub_free(tmp);
+  }
   grub_free (data);
 }
 
+static int 
+add_feature (struct grub_zfs_data * data, zfs_feature_id_t id)
+{
+  struct enabled_feature_list * list = data->feature_list;
+  
+  while (list->next) {
+    if (list->next->id == id)
+      return id;
+    list = list->next;
+  }
+  
+  list->next = (struct enabled_feature_list *) grub_zalloc (sizeof (struct enabled_feature_list)); 
+  
+  if (! list->next)
+    return (-1);
+
+  list->next->id = id;
+  list->next->next = NULL;
+  
+  return 0;
+}
+
+static zfs_feature_id_t
+check_feature (const char * feature)
+{
+  int i = 0;
+  for ( ; i < ZFS_FEATURE_UNKNOWN; ++i)
+    if (! grub_strcmp (feature, feature_list[i]))
+	  return i;
+
+  return ZFS_FEATURE_UNKNOWN;
+}
+
+/*
+ * zfs_get_features_list() get feature list and check compatability
+ */
+static grub_err_t
+zfs_get_features_list (struct grub_zfs_data * data)
+{
+  dnode_end_t dn;
+  dnode_end_t * mos = &(data->mos);
+  grub_err_t err;
+  grub_uint64_t objnum;
+  int ret;
+  
+  int NESTED_FUNC_ATTR feature_hook (const char * cname, grub_uint64_t val)
+  {
+    grub_err_t iret = 0;
+
+    zfs_feature_id_t id;
+
+    if (! (*cname))
+      goto out;
+
+    // retrieve feature number
+    id = check_feature (cname);
+
+    // if grub doesn't support such feature, return error
+    if (id == ZFS_FEATURE_UNKNOWN) {
+      if (val == 0) {
+        grub_error(GRUB_ERR_BAD_FS, 
+              "Unsupported feature %s was enabled,"
+              " but haven't been activated yet. You will not be able to boot"
+              " if this feature are activated.", cname);
+      } else {
+        grub_error(GRUB_ERR_BAD_FS, 
+            "Unsupported feature %s is activated. Booting failed",cname);
+        iret = 1;
+      }
+      goto out;
+    }
+	
+    // add feature to list
+    iret = add_feature(data, id);
+	
+  out:
+    return iret;
+  }
+  
+  // get object directory
+  err = dnode_get (mos, DMU_POOL_DIRECTORY_OBJECT,
+            DMU_OT_OBJECT_DIRECTORY, &dn, data);
+  if (err)
+    return err;
+
+  // retrieve pool properties object numer
+  err = zap_lookup (&dn, DMU_POOL_FEATURES_FOR_READ, &objnum, data, 0);
+  if (err)
+    return err;
+  
+  // get "features for read" zap dnode
+  err = dnode_get (mos, objnum, DMU_OTN_ZAP_METADATA, &dn, data);
+  if (err)
+    return err;
+  
+  // itterate zap to fetch feature list
+  ret = zap_iterate_u64 (&dn, feature_hook, data);
+  if (ret)
+    return grub_error(GRUB_ERR_BAD_FS, "There are enabled unsupported features");
+    	
+  return GRUB_ERR_NONE;
+} 
+
 /*
  * zfs_mount() locates a valid uberblock of the root pool and read in its MOS
  * to the memory address MOS.
@@ -3354,6 +3459,7 @@
     grub_memset (&current_uberblock, 0, sizeof (uberblock_t));
 #endif
 
+  data->feature_list = NULL;
   data->n_devices_allocated = 16;
   data->devices_attached = grub_malloc (sizeof (data->devices_attached[0])
 					* data->n_devices_allocated);
@@ -3392,12 +3498,116 @@
   data->mos.endian = (grub_zfs_to_cpu64 (ub->ub_rootbp.blk_prop,
 					 ub_endian) >> 63) & 1;
   grub_free (osp);
-
+  
   data->mounted = 1;
 
+  if (grub_zfs_to_cpu64(ub->ub_version, ub_endian) == SPA_FEATURE_VERSION) {
+    data->feature_list = (struct enabled_feature_list*) grub_zalloc (
+                                                  sizeof (struct enabled_feature_list));
+    data->feature_list->next = NULL;
+    err = zfs_get_features_list(data);
+  
+    if (err) {
+      data->mounted = 0;
+      zfs_unmount (data);
+      return NULL;
+    }
+  }
+
   return data;
 }
 
+static grub_err_t
+find_default_dataset_path(char * path, grub_uint64_t * mdnobj, struct grub_zfs_data *data)
+{
+  grub_uint64_t obj, pobj, zobj;
+  grub_err_t err;
+  dnode_end_t mdn, *mosmdn;
+  char buf[512];
+
+  int NESTED_FUNC_ATTR hook (const char * name, grub_uint64_t val) {
+    if (val == obj) {
+      grub_strcpy(buf, name);
+      return 1;
+    }
+    return 0;
+  }
+
+  obj = *mdnobj;
+  mosmdn = &(data->mos);
+  buf[0] = '\0';
+  path[0] = '\0';
+
+  // get object's data dir
+  err = dnode_get(mosmdn, obj, DMU_OT_DSL_DATASET, &mdn, data);
+  if (err)
+    return err;
+  obj = grub_zfs_to_cpu64((((dsl_dataset_phys_t*)DN_BONUS (&mdn.dn)))->ds_dir_obj, mdn.endian);
+  
+  for (;;) {
+    // get object dnode
+    err = dnode_get(mosmdn, obj, DMU_OT_DSL_DIR, &mdn, data);
+    if (err)
+      return err;
+
+    // find out its parent's objnum
+    pobj = grub_zfs_to_cpu64((((dsl_dir_phys_t*)DN_BONUS (&mdn.dn)))->dd_parent_obj, mdn.endian);
+    if (obj == pobj)
+      break;
+
+    // if pobj is 0 then we have reached top dataset
+    if (! pobj)
+      break;
+
+    // get object's parent dnode
+    err = dnode_get(mosmdn, pobj, DMU_OT_DSL_DIR, &mdn, data);
+    if (err)
+      return err;
+
+    // find out parent's zap objnum
+    zobj = grub_zfs_to_cpu64((((dsl_dir_phys_t*)DN_BONUS (&mdn.dn)))->dd_child_dir_zapobj, mdn.endian);
+
+    // get zap's dnode
+    err = dnode_get(mosmdn, zobj, DMU_OT_DSL_DIR_CHILD_MAP, &mdn, data);
+    if (err)
+      return err;
+
+    // lookup zap to get name
+    err = zap_iterate_u64(&mdn, hook, data); 
+    if (err == 0)
+      return err;
+
+    // pobj becomes obj now
+    obj = pobj;
+
+    // append new intermediate dnode to path
+    grub_strcat(buf, path);
+    grub_strcpy(path, "/");
+    grub_strcat(path, buf);
+  } 
+	
+  return GRUB_ERR_NONE;
+}
+
+grub_err_t
+get_default_bootfs_obj(grub_device_t dev, char * path, grub_uint64_t * mdnobj)
+{
+  struct grub_zfs_data * data;
+  grub_err_t err = 0;
+  data = zfs_mount(dev);
+  if (data) {
+    err = get_default_bootfsobj(&(data->mos), mdnobj, data);
+    if (err)
+      return err;
+    err = find_default_dataset_path(path, mdnobj, data);
+    zfs_unmount(data);
+    return err;
+  } else {
+    return grub_errno;
+  }
+  return 0;
+}
+
 grub_err_t
 grub_zfs_fetch_nvlist (grub_device_t dev, char **nvlist)
 {
--- old/grub/grub-core/fs/zfs/zfsinfo.c	2012-08-31 05:08:54.303066896 +0400
+++ new/grub/grub-core/fs/zfs/zfsinfo.c	2012-08-31 05:08:54.339887022 +0400
@@ -184,9 +184,10 @@
 }
 
 static grub_err_t
-get_bootpath (char *nvlist, char **bootpath, char **devid)
+get_bootpath (char *nvlist, char **bootpath, char **devid, grub_uint64_t inguid)
 {
   char *type = 0;
+  grub_uint64_t diskguid = 0;
 
   type = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_TYPE);
 
@@ -195,10 +196,11 @@
 
   if (grub_strcmp (type, VDEV_TYPE_DISK) == 0)
     {
+      grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &diskguid);
       *bootpath = grub_zfs_nvlist_lookup_string (nvlist,
 						 ZPOOL_CONFIG_PHYS_PATH);
       *devid = grub_zfs_nvlist_lookup_string (nvlist, ZPOOL_CONFIG_DEVID);
-      if (!*bootpath || !*devid)
+      if (!*bootpath || !*devid || (diskguid != inguid))
 	{
 	  grub_free (*bootpath);
 	  grub_free (*devid);
@@ -223,7 +225,7 @@
 						       ZPOOL_CONFIG_CHILDREN,
 						       i);
 
-	  get_bootpath (child, bootpath, devid);
+	  get_bootpath (child, bootpath, devid, inguid);
 
 	  grub_free (child);
 
@@ -340,12 +342,16 @@
   char *fsname;
   char *bootfs;
   char *poolname;
-  grub_uint64_t mdnobj;
+  char def_path[512];
+  struct grub_zfs_data * data;
+  grub_uint64_t mdnobj, guid;
+  int def = 0;
 
-  if (argc < 1)
+  if (argc <  1) 
     return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
 
   devname = grub_file_get_device_name (args[0]);
+
   if (grub_errno)
     return grub_errno;
 
@@ -362,8 +368,14 @@
   else
     fsname = args[0];
 
-  if (!err)
+  if (grub_strcmp(fsname, "default") == 0)
+    ++def;
+
+  if (! def) {
     err = grub_zfs_getmdnobj (dev, fsname, &mdnobj);
+  } else {
+    err = get_default_bootfs_obj(dev, def_path, &mdnobj);
+  }
 
   grub_device_close (dev);
 
@@ -379,9 +391,10 @@
     }
 
   nv = grub_zfs_nvlist_lookup_nvlist (nvlist, ZPOOL_CONFIG_VDEV_TREE);
+  grub_zfs_nvlist_lookup_uint64 (nvlist, "guid", &guid);
 
-  if (nv)
-    get_bootpath (nv, &bootpath, &devid);
+  if (nv && guid)
+    get_bootpath (nv, &bootpath, &devid, guid);
 
   grub_free (nv);
   grub_free (nvlist);
@@ -401,6 +414,11 @@
   else
     grub_printf ("%s\n", bootfs);
 
+  if ((def) && (argc >= 3))
+    grub_env_set(args[2], def_path);
+  else if (def)
+    grub_printf("%s\n", def_path);
+
   grub_free (bootfs);
   grub_free (poolname);
   grub_free (bootpath);
--- old/grub/grub-core/partmap/sun.c	2012-08-31 05:08:54.982485828 +0400
+++ new/grub/grub-core/partmap/sun.c	2012-08-31 05:08:55.030532646 +0400
@@ -92,7 +92,7 @@
   struct grub_partition p;
   union
   {
-    struct grub_sun_block sun;
+    struct grub_sun_block sunb;
     grub_uint16_t raw[0];
   } block;
   int partnum;
@@ -104,7 +104,7 @@
   if (err)
     return err;
 
-  if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.sun.magic))
+  if (GRUB_PARTMAP_SUN_MAGIC != grub_be_to_cpu16 (block.sunb.magic))
     return grub_error (GRUB_ERR_BAD_PART_TABLE, "not a sun partition table");
 
   if (! grub_sun_is_valid (block.raw))
@@ -116,14 +116,14 @@
     {
       struct grub_sun_partition_descriptor *desc;
 
-      if (block.sun.infos[partnum].id == 0
-	  || block.sun.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID)
+      if (block.sunb.infos[partnum].id == 0
+	  || block.sunb.infos[partnum].id == GRUB_PARTMAP_SUN_WHOLE_DISK_ID)
 	continue;
 
-      desc = &block.sun.partitions[partnum];
+      desc = &block.sunb.partitions[partnum];
       p.start = ((grub_uint64_t) grub_be_to_cpu32 (desc->start_cylinder)
-		  * grub_be_to_cpu16 (block.sun.ntrks)
-		  * grub_be_to_cpu16 (block.sun.nsect));
+		  * grub_be_to_cpu16 (block.sunb.ntrks)
+		  * grub_be_to_cpu16 (block.sunb.nsect));
       p.len = grub_be_to_cpu32 (desc->num_sectors);
       p.number = p.index = partnum;
       if (p.len)
--- old/grub/grub-core/partmap/sunpc.c	2012-08-31 05:08:55.614401454 +0400
+++ new/grub/grub-core/partmap/sunpc.c	2012-08-31 05:08:55.653055529 +0400
@@ -74,7 +74,7 @@
   grub_partition_t p;
   union
   {
-    struct grub_sun_pc_block sun;
+    struct grub_sun_pc_block sunb;
     grub_uint16_t raw[0];
   } block;
   int partnum;
@@ -92,7 +92,7 @@
       return err;
     }
   
-  if (GRUB_PARTMAP_SUN_PC_MAGIC != grub_le_to_cpu16 (block.sun.magic))
+  if (GRUB_PARTMAP_SUN_PC_MAGIC != grub_le_to_cpu16 (block.sunb.magic))
     {
       grub_free (p);
       return grub_error (GRUB_ERR_BAD_PART_TABLE, 
@@ -111,12 +111,12 @@
     {
       struct grub_sun_pc_partition_descriptor *desc;
 
-      if (block.sun.partitions[partnum].id == 0
-	  || block.sun.partitions[partnum].id
+      if (block.sunb.partitions[partnum].id == 0
+	  || block.sunb.partitions[partnum].id
 	  == GRUB_PARTMAP_SUN_PC_WHOLE_DISK_ID)
 	continue;
 
-      desc = &block.sun.partitions[partnum];
+      desc = &block.sunb.partitions[partnum];
       p->start = grub_le_to_cpu32 (desc->start_sector);
       p->len = grub_le_to_cpu32 (desc->num_sectors);
       p->number = partnum;
--- old/grub/include/grub/search.h	2012-08-31 05:08:56.261951310 +0400
+++ new/grub/include/grub/search.h	2012-08-31 05:08:56.292524608 +0400
@@ -20,10 +20,10 @@
 #define GRUB_SEARCH_HEADER 1
 
 void grub_search_fs_file (const char *key, const char *var, int no_floppy,
-			  char **hints, unsigned nhints);
+			  char **hints, unsigned nhints, int mirror);
 void grub_search_fs_uuid (const char *key, const char *var, int no_floppy,
-			  char **hints, unsigned nhints);
+			  char **hints, unsigned nhints, int mirror);
 void grub_search_label (const char *key, const char *var, int no_floppy,
-			char **hints, unsigned nhints);
+			char **hints, unsigned nhints, int mirror);
 
 #endif
--- old/grub/include/grub/zfs/dmu.h	2012-08-31 05:08:56.896674744 +0400
+++ new/grub/include/grub/zfs/dmu.h	2012-08-31 05:08:56.925737526 +0400
@@ -19,6 +19,9 @@
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
+/*
+ *  Copyright 2012, Daniil Lunev
+ */
 
 #ifndef	_SYS_DMU_H
 #define	_SYS_DMU_H
@@ -30,6 +33,41 @@
  * The DMU also interacts with the SPA.  That interface is described in
  * dmu_spa.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;
+
 typedef enum dmu_object_type {
 	DMU_OT_NONE,
 	/* general: */
@@ -89,7 +127,9 @@
 	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_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE),
 } dmu_object_type_t;
 
 typedef enum dmu_objset_type {
@@ -116,5 +156,6 @@
 #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 */
--- old/grub/include/grub/zfs/zfs.h	2012-08-31 05:08:57.526925138 +0400
+++ new/grub/include/grub/zfs/zfs.h	2012-08-31 05:08:57.561499945 +0400
@@ -18,6 +18,9 @@
  /*
   * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   */
+/*
+ *  Copyright 2012, Daniil Lunev
+ */
 
 #ifndef	GRUB_ZFS_HEADER
 #define	GRUB_ZFS_HEADER 1
@@ -37,6 +40,7 @@
  * On-disk version number.
  */
 #define	SPA_VERSION			33ULL
+#define	SPA_FEATURE_VERSION		5000ULL
 
 /*
  * The following are configuration names used in the nvlist describing a pool's
@@ -134,6 +138,8 @@
 		  grub_size_t keylen,
 		  int passphrase);
 
+grub_err_t
+get_default_bootfs_obj(grub_device_t dev, char * path, grub_uint64_t * mdnobj);
 extern grub_err_t (*grub_zfs_decrypt) (grub_crypto_cipher_handle_t cipher,
 				       grub_uint64_t algo,
 				       void *nonce,
--- /dev/null	2012-08-31 05:08:58.000000000 +0400
+++ new/grub/util/grub-solarislst2cfg.c	2012-08-31 05:08:58.176823035 +0400
@@ -0,0 +1,274 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2012 Daniil Lunev
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/getroot.h>
+#include <grub/fs.h>
+#include <grub/device.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define BUFFER_SIZE 512
+
+struct commands {
+  const char * lst;
+  const char * cfg;
+};
+
+void
+get_uuid_by_path(char * path, char ** uuid)
+{
+  char ** devices = NULL;
+  char * drive = NULL;
+  grub_device_t dev = NULL;
+  grub_fs_t fs = NULL;
+  char * grub_path = NULL;
+
+  grub_path = canonicalize_file_name(path);
+  if (! grub_path)
+    grub_util_error("Can't canonicalize path");
+  
+  devices = grub_guess_root_devices(grub_path);
+  if (! devices) 
+    grub_util_error("Can't find device");
+  
+  drive = grub_util_get_grub_dev(devices[0]);
+  if (! drive)
+    grub_util_error("Can't get drive");
+    
+  dev = grub_device_open(drive);
+  if (! dev) 
+    grub_util_error("Can't open device");
+
+  fs = grub_fs_probe(dev);
+  if (! fs) 
+    grub_util_error("Probing fs error");
+
+  if (! fs->uuid) 
+    grub_util_error("This fs doesn't support uuid");
+
+  if (fs->uuid(dev, uuid) != GRUB_ERR_NONE) 
+    grub_util_error("%s", grub_errmsg);
+
+  free(grub_path);
+  if (dev) 
+    grub_device_close(dev);
+
+  return;
+}
+
+struct commands com[] = {
+  {"title", "entry_name"},
+  {"findroot", "pool"},
+  {"bootfs", "data_set"},
+  {"kernel$", "kernel_path"},
+  {"module$", "module"},
+  {"default", "default_entry"},
+  {"timeout", "timeout"},
+  {"serial", "serial"},
+  {"terminal", "terminal"},
+  {0, 0},
+};
+
+int
+get_command_id(char * command)
+{
+  int i = 0;
+  for (; com[i].lst; ++i)
+    if (!strcmp(com[i].lst, command))
+      return i;
+  return -1;
+}
+
+char *
+retrive_value(char * val)
+{
+  char * str; 
+  int quote_flag = 0;;
+
+  while ((*val == ' ') || (*val == '\t'))
+    ++val;
+
+  if (*val == '"') {
+    ++val;
+    ++quote_flag;  
+  }
+  
+  str = val;
+  
+  for (;;) {
+    if (quote_flag) {
+      if (*val == '"') 
+        break;
+      if (*val == '\0')
+        return NULL;
+    } else {
+      if ((*val == ' ') || (*val == '\t') || (*val == '\0'))
+        break;
+    }
+    ++val;
+  }
+  *val = '\0';
+
+  return str;
+}
+
+int
+parse_menulst(FILE * in_file, FILE * out_file)
+{
+  char line[BUFFER_SIZE];
+  char * command;
+  char * value;
+  char * label = NULL;
+  char bootfs[BUFFER_SIZE];
+  char pool[BUFFER_SIZE];
+  char * uuid;
+  char * c;
+  int com_id;
+
+  for (;;) {
+    command = fgets(line, BUFFER_SIZE, in_file);
+    if (! command)
+      return 0;
+
+    c = command + strlen(command) - 1;
+    if ((*c != '\n') && (fgets(line, BUFFER_SIZE, in_file)))
+      return 1;
+
+    if ((*command == '#') || (*command == ' ') 
+       || (*command == '\t') || (*command == '\n'))
+      continue;
+
+    if (*c == '\n')
+      *c = '\0';
+    value = strchr(line, ' ');
+    if (! value)
+      continue;
+
+    *value++ = '\0';
+    
+    com_id = get_command_id(command);
+    if (com_id < 0)
+      continue;
+
+    switch (com_id) {
+    case 0:
+      fprintf(out_file,"\n%s=%s\n", com[com_id].cfg, value);
+      break;
+    case 1:
+      label = strdup(strchr(value, '_') + 1);
+      c = strchr(label, ',');
+      if (c)
+        *c = 0;
+      continue;
+    case 2:
+      c = strchr(value, '/');
+      if (c != NULL) {
+        strcpy(bootfs, c);
+        *c = '\0';
+        strcpy(pool + 1, value);
+        *pool = '/';
+        uuid = NULL;
+        get_uuid_by_path(pool, &uuid);
+        if (! uuid)
+          return 1;
+      
+        fprintf(out_file,"pool_uuid=%s\n", uuid);
+        
+      } 
+      *c = '/';
+      fprintf(out_file,"data_set=%s\n", value);
+      if (label) {
+        free(label);
+        label = NULL;
+      }
+      break;
+    case 3:
+    case 4:
+      if (label) {
+        fprintf(out_file,"pool_label=%s\n", label);
+        free(label);
+        label = NULL;
+      }
+      if (com_id == 3)
+        c = strchr (value, ' ');
+        if (c)
+          *c = '\0';
+      if (! value)
+        return 1;
+      
+      fprintf(out_file,"%s=%s\n", com[com_id].cfg, value);
+
+      if ((com_id == 3) && (c)) {
+        char * tmp;
+        value = c + 1;
+        tmp = strstr(value, "ZFS-BOOTFS");
+        if (tmp)
+          *(tmp + 3) = '_';
+        fprintf(out_file,"kernel_options=%s\n", value);
+      }
+
+      break;
+    default:
+      fprintf(out_file,"%s=%s\n", com[com_id].cfg, value);
+      break;
+    }
+  }
+  return 0;
+}
+
+int
+main(int argc, char ** argv)
+{
+  FILE * lst_file;
+  FILE * cfg_file;
+  int err = 0;
+
+  if (argc != 3) {
+    printf("grub-solarislst2cfg lst_file cfg_file\n");
+    return 1;
+  }
+
+  lst_file = fopen(argv[1], "r");
+  if (! lst_file)
+    return 1;
+
+  cfg_file = fopen(argv[2], "w");
+  if (! cfg_file) {
+    fclose(lst_file);
+    return 1;
+  }
+
+  grub_util_init_nls();
+  grub_util_biosdisk_init(DEFAULT_DEVICE_MAP);
+  grub_init_all();
+  
+  err = parse_menulst(lst_file, cfg_file);
+
+  grub_fini_all();
+
+  fclose(lst_file);
+  fclose(cfg_file);
+
+  if (err)
+    remove(argv[2]);
+  return err;
+}
--- old/grub/util/grub.d/10_illumos.in	2012-08-31 05:08:58.478939825 +0400
+++ new/grub/util/grub.d/10_illumos.in	2012-08-31 05:08:58.513972802 +0400
@@ -49,4 +49,8 @@
 	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
 }
+
+submenu 'Illumos-entries' {
+	illumos_entries /@/boot/illumos.cfg 
+}
 EOF
--- /dev/null	2012-08-31 05:08:59.000000000 +0400
+++ new/grubadm/error.c	2012-08-31 05:08:59.539344413 +0400
@@ -0,0 +1,64 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2012, Daniil Lunev. All rights reserved.
+ */
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "grubadm.h"
+#include "error.h"
+
+char * DEBUG;
+
+void
+debug_print (const char * fmt, ...)
+{
+	va_list args;
+	if (DEBUG) {
+		va_start (args, fmt);
+		vfprintf (stderr, fmt, args);
+		va_end (args);
+	}
+}
+
+void
+print_system_error ()
+{
+	perror(APP_NAME);
+}
+
+void
+print_error (const char * fmt, ...)
+{
+	va_list args;
+	fprintf (stderr, "%s: ", APP_NAME);
+	va_start (args, fmt);
+	vfprintf (stderr, fmt, args);
+	va_end (args);
+	fprintf (stderr, "\n");
+}
+
+void
+check_debug ()
+{
+	DEBUG = getenv("DEBUG");
+}
--- /dev/null	2012-08-31 05:08:59.000000000 +0400
+++ new/grubadm/error.h	2012-08-31 05:08:59.867668369 +0400
@@ -0,0 +1,36 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2012, Daniil Lunev. All rights reserved.
+ */
+extern char * DEBUG;
+
+void
+debug_print (const char * fmt, ...);
+
+void
+print_system_error ();
+
+void
+print_error (const char * fmt, ...);
+
+void
+check_debug ();
--- /dev/null	2012-08-31 05:09:00.000000000 +0400
+++ new/grubadm/grubadm.1m	2012-08-31 05:09:00.187999388 +0400
@@ -0,0 +1,554 @@
+'\" te
+.\" Copyright 2012, Daniil Lunev. All rights reserved.
+.TH GRUBADM 1M "July 25, 2012"
+.SH NAME
+grubadm \- GRUB2 Illumos bootmenu manager
+.SH SYNOPSIS
+.LP
+.nf
+\fBgrubadm\fR [\fB--clone\fR] [\fB--new\fR] [\fB--delete\fR] [\fB--list\fR]
+[\fB\--helpfR] [\fB--all\fR] [\fB--enable-hyper\fR] [\fB--disable-hyper\fR]
+[\fB--get-name\fR] [\fB--get-uuid\fR] [\fB--get-pool\fR][\fB--get-dataset\fR]
+[\fBget-kernel\fR] [\fB--get-opts\fR] [\fB--get-modules\fR] [\fB--get-default\fR]
+[\fB--get-timeout\fR] [\fB--get-terminal\fR] [\fB--get-serial\fR] [\fB--get-all\fR]
+[\fB--default\fR] [\fB--set-name\fR \fIname\fR] [\fB--set-uuid\fR \fIuuid\fR]
+[\fB--set-pool\fR \fIpool\fR] [\fB--set-dataset\fR \fIdataset\fR]
+[\fB--set-kernel\fR \fIkernel\fR] [\fB--set-opts\fR \fIoptions\fR]
+[\fB--set-module\fR \fImodule\fR] [\fB--set-default\fR \fIdefault entry numder\fR]
+[\fB--set-timeout\fR \fItimeout\fR] [\fB--set-terminal\fR \fIterminals\fR]
+[\fB--set-serial\fR \fIserial\fR] [\fB--name\fR \fIname\fR] [\fB--uuid\fR \fIuuid\fR]
+[\fB--pool\fR \fIpool\fR] [\fB--dataset\fR \fIdataset\fR] [\fB--kernel\fR \fIkernel\fR]
+[\fB--module\fR \fImodule\fR] [\fB--number\fR \fInumber\fR]
+[\fB--alt-root\fR \fIalt-root\fR] [\fB--clear\fR]
+.fi
+
+.SH DESCRIPTION
+.sp
+.LP
+The command \fBgrubadm\fR is used to manipulate GRUB2 Illumos entries and GRUB2
+booting parameters. It modify only \fBillumos.cfg\fR and don't influence on entries
+that placed in different locations. If you want to see illumos entries in
+the GRUB2 boot menu, be sure that \fBgrub.cfg\fR contain line "illumos_entries 
+/@/boot/illumos.cfg".
+.SH OPTIONS
+.LP
+The following options are supported:
+.sp
+.ne 2
+.na
+\fB\fB--list\fR\fR
+.ad
+.sp .6
+.RS 4n
+List names of all entries and global parameters values
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--delete\fR\fR
+.ad
+.sp .6
+.RS 4n
+Delete entry (don't stack with --clone, --new, --get-*, --set-*, 
+--enable-hyper, --disable-hyper)
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--new\fR\fR
+.ad
+.sp .6
+.RS 4n
+Add new entry (don't stack with --clone, --delete, --all)
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--default\fR\fR
+.ad
+.sp .6
+.RS 4n
+Fill entry with default values
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--clone\fR\fR
+.ad
+.sp .6
+.RS 4n
+Clone existing entry (don't stack with --delete, --new, --all)
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--clear\fR\fR
+.ad
+.sp .6
+.RS 4n
+Delete all entries
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--help\fR\fR
+.ad
+.sp .6
+.RS 4n
+Show usage
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--all\fR\fR
+.ad
+.sp .6
+.RS 4n
+Apply action to all appropriate entries
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--number\fR\fR \fInumber\fR
+.ad
+.sp .6
+.RS 4n
+Get entry by number. If an unappropriate value are passed,
+default entry will be getted.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--name\fR\fR \fIname\fR
+.ad
+.sp .6
+.RS 4n
+Find entry by name
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--uuid\fR\fR \fIuuid\fR
+.ad
+.sp .6
+.RS 4n
+Find entry by pool uuid
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--pool\fR\fR \fIpool\fR
+.ad
+.sp .6
+.RS 4n
+Find entry by pool name
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--dataset\fR\fR \fIdataset\fR
+.ad
+.sp .6
+.RS 4n
+Find entry by dataset
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--kernel\fR\fR \fIkernel\fR
+.ad
+.sp .6
+.RS 4n
+Find entry by kernel
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--module\fR\fR \fImodule\fR
+.ad
+.sp .6
+.RS 4n
+Find entry by module
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-name\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get entry name
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-pool\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get entry pool name
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-uuid\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get entry pool uuid
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-dataset\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get entry dataset
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-kernel\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get entry kernel line
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-opts\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get entry kernele opts
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-modules\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get entry modules
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-default\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get default entry number
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-timeout\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get timeout
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-serial\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get serial port configureation info
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-terminal\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get terminal
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--get-all\fR\fR
+.ad
+.sp .6
+.RS 4n
+Get all information about appropriate entries
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-name\fR\fR \fIname\fR
+.ad
+.sp .6
+.RS 4n
+Set entry name
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-pool\fR\fR \fIpool\fR
+.ad
+.sp .6
+.RS 4n
+Set entry pool name
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-uuid\fR\fR \fIuuid\fR
+.ad
+.sp .6
+.RS 4n
+Set entry pool uuid
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-dataset\fR\fR \fIdataset\fR
+.ad
+.sp .6
+.RS 4n
+Set entry dataset
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-kernel\fR\fR \fIkernel\fR
+.ad
+.sp .6
+.RS 4n
+Set entry kernel line
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-opts\fR\fR \fIoptions\fR
+.ad
+.sp .6
+.RS 4n
+Set entry kernele opts
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-module\fR\fR \fImodule\fR
+.ad
+.sp .6
+.RS 4n
+Set entry module (all earlier specified modules will be deleted,
+if you want to specify multiple modules, use several --set-module
+in a single command)
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-default\fR\fR \fIdefault entry number\fR
+.ad
+.sp .6
+.RS 4n
+Set default entry number
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-timeout\fR\fR \fItimeout\fR
+.ad
+.sp .6
+.RS 4n
+Set timeout
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-serial\fR\fR \fIserial_port_params\fR
+.ad
+.sp .6
+.RS 4n
+Set serial port configureation info
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--set-terminal\fR\fR \fIterminal\fR
+.ad
+.sp .6
+.RS 4n
+Set terminal
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--enable-hyper\fR\fR
+.ad
+.sp .6
+.RS 4n
+Convert entry to boot with xen
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB--disable-hyper\fR\fR
+.ad
+.sp .6
+.RS 4n
+Convert entry from xen-mode to normal boot mod
+.RE
+
+.SH EXAMPLES
+.LP
+\fBExample 1\fR
+.sp
+.LP
+List all entries
+
+.sp
+.in +2
+.nf
+example% \fBgrubadm --list\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 2\fR
+.sp
+.LP
+Add new entry with default paramters
+
+.sp
+.in +2
+.nf
+example% \fBgrubadm --new --default --set-name test\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 3\fR
+.sp
+.LP
+Delete all entries with specified dataset
+
+.sp
+.in +2
+.nf
+example% \fBgrubadm --delete --all --dataset "rpool/ROOT/test_pool"\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 4\fR
+.sp
+.LP
+Clone entry and set diffrent kernel options
+
+.sp
+.in +2
+.nf
+example% \fBgrubadm --clone --name test --set-name new_test --set-opt "-s"\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 5\fR
+.sp
+.LP
+Change kernel and convert entry to hypervisor
+
+.sp
+.in +2
+.nf
+example% \fBgrubadm --name test --set-kernel "/platform/i86pc/kernel/unix" --enable-hyper\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 6\fR
+.sp
+.LP
+Set up serial console
+
+.sp
+.in +2
+.nf
+example% \fBgrubadm --set-serial "--unit=0 --speed=9600" --set-terminal "serial"\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 7\fR
+.sp
+.LP
+Get default entry number
+
+.sp
+.in +2
+.nf
+example% \fBgrubadm --get-default\fR
+.fi
+.in -2
+.sp
+
+.SH FILES
+.sp
+.ne 2
+.na
+/pool/boot/illumos.cfg
+.ad
+.sp .6
+.RS 4n
+Bootmenu file.
+.RE
+
+.SH NOTES
+grubadm is replacement of bootadm boot menu functionality for grub2. You can't
+use bootadm menu functionality on with GRUB2 as well as you can't use grubadm
+with GRUB-legacy.
+
--- /dev/null	2012-08-31 05:09:00.000000000 +0400
+++ new/grubadm/grubadm.c	2012-08-31 05:09:00.516467524 +0400
@@ -0,0 +1,615 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2012, Daniil Lunev. All rights reserved.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <assert.h>
+#include "grubadm.h"
+#include "error.h"
+#include "menu.h"
+
+menu_list get_arg = { 0 };
+menu_list find_arg = { 0 };
+menu_list set_arg = { 0 };
+int get_timeout = 0;
+int get_default = 0;
+int get_serial = 0;
+int get_terminal = 0;
+int lst_flag = 0;
+int new_flag = 0;
+int all_flag = 0;
+int del_flag = 0;
+int fnd_flag = 0;
+int hlp_flag = 0;
+int get_flag = 0;
+int set_flag = 0;
+int cln_flag = 0;
+int clr_flag = 0;
+int enh_flag = 0;
+int dih_flag = 0;
+int num_flag = 0;
+int number;
+char * set_timeout = NULL;
+char * set_default = NULL;
+char * set_serial = NULL;
+char * set_terminal = NULL;
+char * alt_root = NULL;
+
+static char opt_string[] = "landh?R:";
+static const struct option options[] = {
+	{ "list", no_argument, NULL, 'l' },
+	{ "all", no_argument, NULL, 'a' },
+	{ "new", no_argument, NULL, 'n' },
+	{ "delete", no_argument, NULL, 'd' },
+	{ "help", no_argument, NULL, 'h' },
+	{ "name", required_argument, NULL, 4 },
+	{ "pool", required_argument, NULL, 5 },
+	{ "uuid", required_argument, NULL, 6 },
+	{ "dataset", required_argument, NULL, 7 },
+	{ "kernel", required_argument, NULL, 8 },
+	{ "module", required_argument, NULL, 9 },
+	{ "set-name", required_argument, NULL, 10 },
+	{ "set-pool", required_argument, NULL, 11 },
+	{ "set-uuid", required_argument, NULL, 12 },
+	{ "set-dataset", required_argument, NULL, 13 },
+	{ "set-kernel", required_argument, NULL, 14 },
+	{ "set-opts", required_argument, NULL, 15 },
+	{ "set-module", required_argument, NULL, 16 },
+	{ "set-default", required_argument, NULL, 17 },
+	{ "set-timeout", required_argument, NULL, 18 },
+	{ "get-name", no_argument, NULL, 19 },
+	{ "get-pool", no_argument, NULL, 20 },
+	{ "get-uuid", no_argument, NULL, 21 },
+	{ "get-dataset", no_argument, NULL, 22 },
+	{ "get-kernel", no_argument, NULL, 23 },
+	{ "get-opts", no_argument, NULL, 24 },
+	{ "get-modules", no_argument, NULL, 25 },
+	{ "get-default", no_argument, NULL, 26 },
+	{ "get-timeout", no_argument, NULL, 27 },
+	{ "get-all", no_argument, NULL, 28 },
+	{ "alt-root", required_argument, NULL, 'R' },
+	{ "default", no_argument, NULL, 30 },
+	{ "set-serial", required_argument, NULL, 31 },
+	{ "set-terminal", required_argument, NULL, 32 },
+	{ "get-serial", no_argument, NULL, 33 },
+	{ "get-terminal", no_argument, NULL, 34 },
+	{ "clone", no_argument, NULL, 35 },
+	{ "enable-hyper", no_argument, NULL, 36 },
+	{ "disable-hyper", no_argument, NULL, 37 },
+	{ "clear", no_argument, NULL, 38 },
+	{ "number", required_argument, NULL, 39 },
+	{ NULL, no_argument, NULL, 0 },
+};
+
+static void
+usage ()
+{
+	printf (
+		"Usage:\n"
+		"--list list all entries\n"
+		"--all apply actions to all appropriate entries\n"
+		"--new create new entry\n"
+		"--delete delete entry\n"
+		"--clone clone existing entry\n"
+		"--default set default entry properties\n"
+		"--help show this message\n"
+		"--number <opt> find entry by number (-1 = default entry)\n"
+		"--name <opt> find entry by name\n"
+		"--pool <opt> by pool name\n"
+		"--uuid <opt> by uuid\n"
+		"--dataset <opt> by dataset\n"
+		"--kernel <opt> by kernel\n"
+		"--module <opt> by module\n"
+		"--set-name <opt> set new name to entry\n"
+		"--set-pool <opt>\n"
+		"--set-uuid <opt>\n"
+		"--set-kernel <opt>\n"
+		"--set-opts <opt>\n"
+		"--set-module <opt>\n"
+		"--set-default <opt>\n"
+		"--set-timeout <opt>\n"
+		"--get-name get entry name\n"
+		"--get-pool\n"
+		"--get-uuid\n"
+		"--get-kernel\n"
+		"--get-opts\n"
+		"--get-module\n"
+		"--get-default\n"
+		"--get-timeout\n"
+		"--get-all retrieve all params of entry\n"
+		"--alt-root <opt> alternate root directory\n"
+		"--default set default fields value to entry\n"
+		"--set-serial set params of serial port\n"
+		"--set-terminal set default terminal\n"
+		"--get-serial get params of serial port"
+		"--get-terminal get default terminal\n"
+		"--enable-hyper convert entry to boot with xen\n"
+		"--disable-hyper convert entry to normal boot\n"
+		"--clear delete all entries\n"
+	);
+}
+
+static char * 
+get_pool (const char * file)
+{
+	char buf[MAX_STRING_SIZE];
+	char * tmp;
+	FILE * pipe;
+
+	const char fnc[] = "get_pool";
+
+	debug_print ("%s\narg: %s\n", fnc, file);
+
+	strcpy (buf, "/usr/bin/df -h ");
+	strcat (buf, file);
+	
+	pipe = popen (buf, "r");
+	if (! pipe)
+		return NULL;
+
+	fgets (buf, MAX_STRING_SIZE, pipe);
+	if (! fgets (buf, MAX_STRING_SIZE, pipe)) {
+		pclose (pipe);
+		return NULL;
+	}
+
+	pclose (pipe);
+	tmp = strchr (buf, '/');
+	*tmp = 0;
+	tmp = strdup (buf);
+	return tmp;
+}
+
+static int
+parse_args (int argc, char ** argv)
+{
+	int opt = 0;
+	int index;
+	
+	const char fnc[] = "parse_args";
+
+	debug_print ("%s\n", fnc);
+
+	while ((opt = getopt_long (argc, argv, opt_string, options, &index)) != -1) {
+		switch (opt) {
+		case 'a':
+			++all_flag;
+			break;
+		case 'd':
+			++del_flag;
+			break;
+		case 'l':
+			++lst_flag;
+			break;
+		case 'n':
+			++new_flag;
+			break;
+		case 'h':
+		case '?':
+			++hlp_flag;
+			break;
+		case 4:
+			++fnd_flag;
+			strcpy (find_arg.entry.entry_name, optarg);
+			break;
+		case 5:
+			++fnd_flag;
+			strcpy (find_arg.entry.pool_label, optarg);
+			break;
+		case 6:
+			++fnd_flag;
+			strcpy (find_arg.entry.pool_uuid, optarg);
+			break;
+		case 7:
+			++fnd_flag;
+			strcpy (find_arg.entry.dataset, optarg);
+			break;
+		case 8:
+			++fnd_flag;
+			strcpy (find_arg.entry.kernel, optarg);
+			break;
+		case 9:
+			++fnd_flag;
+			find_arg.entry.modules[(find_arg.entry.modules_amount)++] = strdup (optarg);
+			break;
+		case 10:
+			++set_flag;
+			strcpy (set_arg.entry.entry_name, optarg);
+			break;
+		case 11:
+			++set_flag;
+			strcpy (set_arg.entry.pool_label, optarg);
+			break;
+		case 12:
+			++set_flag;
+			strcpy (set_arg.entry.pool_uuid, optarg);
+			break;
+		case 13:
+			++set_flag;
+			strcpy (set_arg.entry.dataset, optarg);
+			break;
+		case 14:
+			++set_flag;
+			strcpy (set_arg.entry.kernel, optarg);
+			break;
+		case 15:
+			++set_flag;
+			strcpy (set_arg.entry.kernel_opts, optarg);
+			break;
+		case 16:
+			++set_flag;
+			set_arg.entry.modules[(set_arg.entry.modules_amount)++] = strdup (optarg);
+			break;
+		case 17:
+			set_default = strdup (optarg);
+			break;
+		case 18:
+			set_timeout = strdup (optarg);
+			break;
+		case 19:
+			++get_flag;
+			get_arg.entry.entry_name[0] = 1;
+			break;
+		case 20:
+			++get_flag;
+			get_arg.entry.pool_label[0] = 1;
+			break;
+		case 21:
+			++get_flag;
+			get_arg.entry.pool_uuid[0] = 1;
+			break;
+		case 22:
+			++get_flag;
+			get_arg.entry.dataset[0] = 1;
+			break;
+		case 23:
+			++get_flag;
+			get_arg.entry.kernel[0] = 1;
+			break;
+		case 24:
+			++get_flag;
+			get_arg.entry.kernel_opts[0] = 1;
+			break;
+		case 25:
+			++get_flag;
+			get_arg.entry.modules = (char**) 1;
+			break;
+		case 26:
+			++get_default;
+			break;
+		case 27:
+			++get_timeout;
+			break;
+		case 28:
+			++get_flag;
+			memset (&(get_arg.entry), 0xFF, sizeof (menu_entry));
+			break;
+		case 'R':
+			alt_root = strdup (optarg);
+			break;
+		case 30:
+			++set_flag;
+			strcpy (set_arg.entry.entry_name, "Menuadm default");
+			strcpy (set_arg.entry.pool_label, get_pool ("/"));
+			strcpy (set_arg.entry.kernel, "/platform/i86pc/kernel/$ISADIR/unix");
+			strcpy (set_arg.entry.kernel_opts, "-B $ZFS_BOOTFS");
+			set_arg.entry.modules[0] = strdup ("/platform/i86pc/$ISADIR/boot_archive");
+			set_arg.entry.modules_amount = 1;
+			break;
+		case 31:
+			set_serial = strdup (optarg);
+			break;
+		case 32:
+			set_terminal = strdup (optarg);
+			break;
+		case 33:
+			++get_serial;
+			break;
+		case 34:
+			++get_terminal;
+			break;
+		case 35:
+			++cln_flag;
+			break;
+		case 36:
+			++enh_flag;
+			break;
+		case 37:
+			++dih_flag;
+			break;
+		case 38:
+			++clr_flag;
+			break;
+		case 39:
+			++num_flag;
+			sscanf (optarg, "%d", &number);
+			break;
+		default:
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static int
+check_flags ()
+{
+	const char fnc[] = "check_flags";
+
+	debug_print ("%s\n", fnc);
+
+	if (new_flag)
+		if (del_flag || all_flag || cln_flag || fnd_flag || num_flag)
+			return 0;
+
+	if (del_flag)
+		if ((! fnd_flag && ! num_flag) || set_flag || get_flag || cln_flag || enh_flag || dih_flag)
+			return 0;
+
+	if (cln_flag)
+		if (! fnd_flag || all_flag)
+			return 0; 
+
+	if (fnd_flag)
+		if (num_flag)
+			return 0;
+	return 1;
+}
+
+static void
+apply_set (menu_list * entry, menu_list * set)
+{
+	unsigned int i = 0;
+
+	const char fnc[] = "apply_set";
+
+	debug_print ("%s\n", fnc);
+
+	if (set->entry.entry_name[0])
+		strcpy (entry->entry.entry_name, set->entry.entry_name);
+
+	if (set->entry.pool_label[0])
+		strcpy (entry->entry.pool_label, set->entry.pool_label);
+
+	if (set->entry.pool_uuid[0])
+		strcpy (entry->entry.pool_uuid, set->entry.pool_uuid);
+
+	if (set->entry.dataset[0])
+		strcpy (entry->entry.dataset, set->entry.dataset);
+
+	if (set->entry.kernel[0])
+		strcpy (entry->entry.kernel, set->entry.kernel);
+
+	if (set->entry.kernel_opts[0])
+		strcpy (entry->entry.kernel_opts, set->entry.kernel_opts);
+
+	if (set->entry.modules_amount) {
+		for (i = 0; i < entry->entry.modules_amount; ++i)
+			free (entry->entry.modules[i]);
+
+		for (i = 0; i < set->entry.modules_amount; ++i)
+			entry->entry.modules[i] = strdup (set->entry.modules[i]);
+
+		entry->entry.modules_amount = set->entry.modules_amount;
+	}
+}
+
+static void
+output_entry (menu_list * entry, menu_list * get)
+{
+	unsigned int i = 0;
+
+	const char fnc[] = "output_entry";
+
+	debug_print ("%s\n", fnc);
+
+	if (get->entry.entry_name[0])
+		printf("%s\n", entry->entry.entry_name);
+
+	if (get->entry.pool_label[0])
+		printf("%s\n", entry->entry.pool_label);
+
+	if (get->entry.pool_uuid[0])
+		printf("%s\n", entry->entry.pool_uuid);
+
+	if (get->entry.dataset[0])
+		printf("%s\n", entry->entry.dataset);
+
+	if (get->entry.kernel[0])
+		printf("%s\n", entry->entry.kernel);
+
+	if (get->entry.kernel_opts[0])
+		printf("%s\n", entry->entry.kernel_opts);
+
+	if (get->entry.modules)
+		for (i = 0; i < entry->entry.modules_amount; ++i)
+			printf("%s\n", entry->entry.modules[i]);
+
+	printf("-----------------------------------------\n");
+}
+
+int
+main (int argc, char ** argv)
+{
+	char * pool;
+	char config[MAX_STRING_SIZE];
+	char tmp_config[MAX_STRING_SIZE];
+	menu_list * menu;
+	menu_list * tmp;
+	menu_list * entry;
+	int entries_amount;
+	int d_num;
+
+	check_debug ();
+
+	if (argc < 2)
+		++lst_flag;
+
+	set_arg.entry.modules = (char **) calloc (MAX_MODULE_AMOUNT, sizeof (char *));
+	find_arg.entry.modules = (char **) calloc (MAX_MODULE_AMOUNT, sizeof (char *));
+	if (! parse_args (argc, argv))
+		return 1;
+
+	if (hlp_flag) {
+		usage ();
+		return 0;
+	}
+
+	if (! check_flags ()) {
+		print_error ("wrong option set, check \"man grubadm\"");
+		return 1;
+	}
+
+	pool = get_pool (alt_root ?: "/");
+	strcpy (config, "/");
+	if (alt_root)
+		strcat (config, alt_root);
+	strcat (config, "/");
+	strcat (config, pool);
+	strcat (config, "/");
+	strcpy (tmp_config, config);
+	strcat (config, CONFIG_PATH);
+	strcat (tmp_config, TMP_CONFIG_PATH);
+
+	menu = parse_file (config, &entries_amount);
+	if (entries_amount == -1) {
+		return 1;
+	}
+
+	tmp = menu;
+	entry = NULL;
+
+	do {
+		if (clr_flag) {
+			menu = NULL;
+			break;
+		}
+
+		if (set_default) {
+			sscanf (set_default, "%d", &d_num);
+			if (d_num < entries_amount)
+				strcpy (default_entry, set_default);
+		}
+	
+		if (set_timeout)
+			strcpy (timeout, set_timeout);
+
+		if (set_serial)
+			strcpy (serial, set_serial);
+
+		if (set_terminal)
+			strcpy (terminal, set_terminal);
+
+		if (fnd_flag) { 
+			entry = find_entry (tmp, &find_arg);
+			if (! entry) {
+				print_error (MSG_ERR_NO_ENTRY);
+				break;
+			}
+		}
+
+		if (num_flag) {
+			if ((number < 0) || (number >= entries_amount)) {
+				if (! default_entry[0]) {
+					number = 0;
+				} else {
+					sscanf (default_entry, "%d", &number);
+				}
+			}
+			if (number >= entries_amount)
+				number = 0;
+			entry = get_entry_by_number (menu, number);
+			if (! entry) {
+				print_error (MSG_ERR_NO_ENTRY);
+				break;
+			}
+		}
+
+		if (cln_flag) {
+			entry = clone_entry (entry);
+			if (! entry) {
+				print_error (MSG_ERR_NO_ENTRY);
+				break;
+			}
+		}
+
+		if (set_flag) {
+			if (entry)
+				apply_set (entry, &set_arg);
+			else if (new_flag)
+				add_entry (&menu, &set_arg);
+			else
+				return 1;
+		}
+
+		if (enh_flag)
+			if (! enable_hyper (entry)) {
+				print_error (MSG_ERR_HYPER);
+				break;
+			}
+		
+		if (dih_flag)
+			if (! disable_hyper (entry)) {
+				print_error (MSG_ERR_HYPER);
+				break;
+			}
+
+		if (cln_flag)
+			add_entry (&menu, entry);
+
+		if (get_flag)
+			if (entry)
+				output_entry (entry, &get_arg);
+
+		if (all_flag)
+			tmp = entry->next;
+		else
+			tmp = NULL;
+
+		if (del_flag)
+			delete_entry (&menu, entry);
+	} while (tmp);
+
+	if (get_default) 
+		printf ("%s%s%s\n", cmd_list[CMD_DEFAULT], SEPARATOR, default_entry);
+
+	if (get_timeout)
+		printf ("%s%s%s\n", cmd_list[CMD_TIMEOUT], SEPARATOR, timeout);
+
+	if (get_serial)
+		printf ("%s%s%s\n", cmd_list[CMD_SERIAL], SEPARATOR, serial);
+
+	if (get_terminal)
+		printf ("%s%s%s\n", cmd_list[CMD_TERMINAL], SEPARATOR, terminal);
+
+	if (lst_flag) {
+		list_menu (menu);
+	}	
+
+	write_menu (config, tmp_config, menu);
+	free_menu (&menu);
+	return 0;
+}
--- /dev/null	2012-08-31 05:09:00.000000000 +0400
+++ new/grubadm/grubadm.h	2012-08-31 05:09:00.821177696 +0400
@@ -0,0 +1,38 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2012, Daniil Lunev. All rights reserved.
+ */
+#define APP_NAME "grubadm"
+#define CONFIG_PATH "/boot/illumos.cfg"
+#define TMP_CONFIG_PATH "/boot/illumos.cfg.tmp"
+
+#define HYPER_KERNEL "/boot/$ISADIR/xen.gz"
+#define HYPER_KERNEL_OPTS "console=vga"
+
+#define MAX_STRING_SIZE 1024
+#define MAX_MODULE_AMOUNT 8
+
+#define MSG_ERR_LONG_LINE "Too long line"
+#define MSG_ERR_WRONG_SYNTAX "Syntax error"
+#define MSG_ERR_SAME_NAME "Duplicate entry definition"
+#define MSG_ERR_NO_ENTRY "Entry with defined parameters can not be found"
+#define MSG_ERR_HYPER "Hyper operation failed"
--- /dev/null	2012-08-31 05:09:01.000000000 +0400
+++ new/grubadm/menu.c	2012-08-31 05:09:01.141666449 +0400
@@ -0,0 +1,581 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2012, Daniil Lunev. All rights reserved.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "grubadm.h"
+#include "error.h"
+#include "menu.h"
+
+char default_entry[MAX_STRING_SIZE] = { 0 };
+char timeout[MAX_STRING_SIZE] = { 0 };
+char serial[MAX_STRING_SIZE] = { 0 };
+char terminal[MAX_STRING_SIZE] = { 0 };
+
+const char * cmd_list[] = {
+	"entry_name",
+	"pool_label",
+	"pool_uuid",
+	"data_set",
+	"kernel_path",
+	"kernel_options",
+	"module",
+	"default_entry",
+	"timeout",
+	"serial",
+	"terminal",
+	NULL
+};
+
+void
+free_menu (menu_list ** menu)
+{
+	unsigned int i;
+	menu_list * iter = *menu;
+	menu_list * tmp = *menu;
+
+	const char fnc[] = "free_menu";
+
+	debug_print ("%s\n", fnc);
+
+	while (iter) {
+		if (iter->entry.modules_amount)
+			for (i = 0; i < iter->entry.modules_amount; ++i)
+				free (iter->entry.modules[i]);
+		free (iter->entry.modules);
+		tmp = iter;
+		iter = iter->next;
+		free (tmp);
+	}
+
+	*menu = NULL;
+}
+
+static menu_list *
+new_entry (menu_list ** menu, const char * entry_name, const unsigned int num)
+{
+	menu_list * added_entry;
+	menu_list * iter;
+
+	const char fnc[] = "new_entry";
+
+	debug_print ("%s\nargs : %s | %u\n", fnc, entry_name, num);
+
+	added_entry = (menu_list *) calloc (1, sizeof (menu_list));
+	if (! added_entry) {
+		print_system_error ();
+		return NULL;
+	}
+
+	memset ((void *) added_entry, 0, sizeof (menu_list));
+	added_entry->entry_number = num;
+	strcpy (added_entry->entry.entry_name, entry_name);
+	added_entry->entry.modules = 
+		(char **) calloc (MAX_MODULE_AMOUNT, sizeof (char *));
+
+	if (! added_entry->entry.modules) {
+		free_menu (&added_entry);
+		print_system_error ();
+		return NULL;
+	}
+
+	if (! *menu) {
+		*menu = added_entry;
+	} else {
+		for (iter = *menu; iter->next; iter = iter->next) 
+			if (! strcmp (iter->entry.entry_name, entry_name)) {
+				print_error ("%s %s", MSG_ERR_SAME_NAME, entry_name);
+				free_menu (&added_entry);
+				return NULL;
+			}
+		if (! strcmp (iter->entry.entry_name, entry_name)) {
+			print_error ("%s %s", MSG_ERR_SAME_NAME, entry_name);
+			free_menu (&added_entry);
+			return NULL;
+		}	
+		iter->next = added_entry;
+	}
+
+	return added_entry;
+}
+
+menu_list *
+add_entry (menu_list ** menu, menu_list * entry)
+{
+	menu_list * iter;
+
+	const char fnc[] = "add_entry";
+
+	debug_print ("%s\n", fnc);
+
+	if (! entry)
+		return NULL;
+
+	if (! *menu) {
+		entry->entry_number = 0;
+		*menu = entry;
+		return entry;
+	}
+
+	for (iter = * menu; iter->next; iter = iter->next)
+		if (! strcmp (iter->entry.entry_name, entry->entry.entry_name))
+			return NULL;
+		
+	if (! strcmp (iter->entry.entry_name, entry->entry.entry_name))
+		return NULL;
+
+	iter->next = entry;
+	entry->entry_number = iter->entry_number + 1;
+	return entry;
+}
+
+menu_list *
+clone_entry (menu_list * entry)
+{
+	unsigned int i;
+
+	char fnc[] = "clone_entry";
+
+	debug_print ("%s\n", fnc);
+
+	if (! entry)
+		return NULL;
+	menu_list * clone = (menu_list *) calloc (1, sizeof (menu_list));
+	memcpy ((void *) clone, (void *) entry, sizeof (menu_list));
+	clone->next = NULL;
+	clone->entry.modules = (char **) calloc (MAX_MODULE_AMOUNT, sizeof (char *));
+	for (i = 0; i < clone->entry.modules_amount; ++i)
+		clone->entry.modules[i] = strdup (entry->entry.modules[i]);
+	return clone;
+}
+
+menu_list * 
+enable_hyper (menu_list * entry)
+{
+	unsigned int i;
+	char kernel_mod[MAX_STRING_SIZE];
+
+	char fnc[] = "enable_hyper";
+
+	debug_print ("%s\n", fnc);
+
+	if (! entry)
+		return NULL;
+	
+	strcpy (kernel_mod, entry->entry.kernel);
+	strcat (kernel_mod, " ");
+	strcat (kernel_mod, entry->entry.kernel);
+	strcat (kernel_mod, " ");
+	strcat (kernel_mod, entry->entry.kernel_opts);
+
+	strcpy (entry->entry.kernel, HYPER_KERNEL);
+	strcpy (entry->entry.kernel_opts, HYPER_KERNEL_OPTS);
+	
+	for (i = entry->entry.modules_amount; i > 0; --i) 
+		entry->entry.modules[i] = entry->entry.modules[i-1];
+	entry->entry.modules[0] = strdup (kernel_mod);
+	++(entry->entry.modules_amount);
+
+	return entry;
+}
+
+menu_list *
+disable_hyper (menu_list * entry)
+{
+	unsigned int i;
+	char * tmp;
+
+	char fnc[] = "disable_hyper";
+
+	debug_print ("%s\n", fnc);
+
+	if (! entry)
+		return NULL;
+
+	tmp = strchr (entry->entry.modules[0], ' ');
+	if (! tmp)
+		return NULL;
+
+	*tmp++ = '\0';
+
+	strcpy (entry->entry.kernel, entry->entry.modules[0]);
+	
+	entry->entry.kernel_opts[0] = '\0';
+	tmp = strchr(tmp, ' ');
+	if (tmp && *(++tmp)) {
+		strcpy (entry->entry.kernel_opts, tmp);
+	}
+	free (entry->entry.modules[0]);
+	--(entry->entry.modules_amount);
+
+	for (i = 0; i < entry->entry.modules_amount; ++i)
+		entry->entry.modules[i] = entry->entry.modules[i + 1];
+
+	return entry;
+}
+
+int
+delete_entry (menu_list ** menu, menu_list * del)
+{
+	menu_list * iter = *menu;
+	int d_num, i_num;
+
+	const char fnc[] = "delete_entry";
+
+	debug_print ("%s\n", fnc);
+
+	if (! menu || ! del)
+		return 0;
+
+	i_num = del->entry_number;
+
+	if (iter == del) {
+		*menu = (*menu)->next;
+		iter->next = NULL;
+		free_menu (&iter);
+	} else {
+		while (iter->next) {
+			if (iter->next == del) {
+				iter->next = del->next;
+				del->next = NULL;
+				free_menu (&del);
+				break;
+			}
+			iter = iter->next;
+		}
+	}
+
+	sscanf (default_entry, "%d", &d_num);
+
+	if (i_num <= d_num) {
+		d_num = d_num ? d_num - 1 : 0;
+		sprintf (default_entry, "%d", d_num);
+	}
+
+	return 0;
+}
+
+static menu_list *
+add_param (menu_list ** menu, 
+		const cmd_id id,
+		const char * value, 
+		unsigned int * num)
+{
+	menu_list * iter;
+	char * tmp;
+
+	const char fnc[] = "add_param";
+
+	debug_print ("%s\narg: %u | %s | %u\n", fnc, (unsigned int) id, value, *num);
+
+	if (id == CMD_ENTRY_NAME)
+		return new_entry (menu, value, (*num)++);
+
+	if (! *menu) {
+		print_error ("%s, %s", MSG_ERR_WRONG_SYNTAX, "entry isn't defined");
+	}
+
+	for (iter = * menu; iter->next; iter = iter->next)
+		;
+
+	switch (id) {
+	case CMD_POOL_LABEL:
+		strcpy (iter->entry.pool_label, value);
+		break;
+	case CMD_POOL_UUID:
+		strcpy (iter->entry.pool_uuid, value);
+		break;
+	case CMD_DATA_SET:
+		strcpy (iter->entry.dataset, value);
+		break;
+	case CMD_KERNEL_PATH:
+		strcpy (iter->entry.kernel, value);
+		break;
+	case CMD_KERNEL_OPTIONS:
+		strcpy (iter->entry.kernel_opts, value);
+		break;
+	case CMD_BA_PATH:
+		if (iter->entry.modules_amount >= MAX_MODULE_AMOUNT)
+			return NULL; 
+		iter->entry.modules[iter->entry.modules_amount] = 
+			(char *) malloc (MAX_STRING_SIZE);
+		if (! iter->entry.modules[iter->entry.modules_amount])
+			return NULL;
+		strcpy (iter->entry.modules[iter->entry.modules_amount], value);
+		++(iter->entry.modules_amount);
+		break;
+	default:
+		return NULL;
+	}
+	return iter;
+}
+
+void
+list_menu (menu_list * menu)
+{
+	const char fnc[] = "list_menu";
+
+	debug_print ("%s\n", fnc);
+
+	if (*default_entry)
+		printf ("%s%s%s\n", cmd_list[CMD_DEFAULT], SEPARATOR, default_entry);
+
+	if (*timeout) 
+		printf ("%s%s%s\n", cmd_list[CMD_TIMEOUT], SEPARATOR, timeout);
+
+	if (*serial)
+		printf ("%s%s%s\n", cmd_list[CMD_SERIAL], SEPARATOR, serial);
+
+	if (*terminal)
+		printf ("%s%s%s\n", cmd_list[CMD_TERMINAL], SEPARATOR, terminal);
+
+	while (menu) {
+		printf("%u : %s\n", menu->entry_number, menu->entry.entry_name);
+		menu = menu->next;
+	}
+}
+
+menu_list *
+find_entry (menu_list * menu, menu_list * find)
+{
+	unsigned int i = 0;
+	const char fnc[] = "find_entry";
+
+	debug_print ("%s\n", fnc);
+
+	if (! menu || ! find)
+		return NULL;
+
+	while (menu) {
+		if (find->entry.entry_name[0])
+			if (strcmp (menu->entry.entry_name, find->entry.entry_name))
+				goto out;
+		if (find->entry.pool_label[0])
+			if (strcmp (menu->entry.pool_label, find->entry.pool_label))
+				goto out;
+		if (find->entry.pool_uuid[0])
+			if (strcmp (menu->entry.pool_uuid, find->entry.pool_uuid))
+				goto out;
+		if (find->entry.dataset[0])
+			if (strcmp (menu->entry.dataset, find->entry.dataset))
+				goto out;
+		if (find->entry.kernel[0])
+			if (strcmp (menu->entry.kernel, find->entry.kernel))
+				goto out;
+
+		if (find->entry.modules_amount) {
+			for (i = 0; i < menu->entry.modules_amount; ++i)
+				if (! strcmp (menu->entry.modules[i], find->entry.modules[0]))
+					return menu;
+			goto out;
+		}
+
+		return menu;
+out:
+		menu = menu->next;
+	}
+
+	return NULL;
+}
+
+menu_list *
+get_entry_by_number (menu_list * menu, int number)
+{
+	while (menu) 
+		if (menu->entry_number == number)
+			return menu;
+		else
+			menu = menu->next;
+	return NULL;
+}
+
+static size_t
+get_line (FILE * menu_file, char * line)
+{
+	const char fnc[] = "get_line";
+	
+	debug_print ("%s\n", fnc);
+
+	if (! fgets (line, MAX_STRING_SIZE, menu_file)) {
+		if (! feof (menu_file))
+			print_system_error ();
+		return -1;
+	}
+
+	if ((line[strlen (line) - 1] != '\n') && (! feof (menu_file))) {
+		print_error ("%s (> %d)", MSG_ERR_LONG_LINE, MAX_STRING_SIZE);
+		return -1;
+	}
+
+	line[strlen (line) - 1] = '\0';
+
+	return strlen (line);
+}
+
+static cmd_id
+get_param_id (const char * param)
+{
+	unsigned int id;
+
+	const char fnc[] = "get_param_id";
+
+	debug_print ("%s\narg : %s\n", fnc, param);
+
+	for (id = 0; cmd_list[id]; ++id)
+		if (! strcmp (cmd_list[id], param))
+			break;
+
+	return id;		
+}
+
+menu_list *
+parse_file (const char * file_name, int * entries_amount)
+{
+	FILE * menu_file = NULL;
+	unsigned int counter = 0;
+	menu_list * menu = NULL;
+	char line[MAX_STRING_SIZE];
+	char * param;
+	char * value;
+	cmd_id id;
+	
+	const char fnc[] = "parse_file";
+
+	debug_print ("%s\narg : %s\n", fnc, file_name);
+
+	menu_file = fopen (file_name, "r");
+	if (! menu_file) {
+		print_system_error ();
+		goto out;
+	}
+
+	for (;;) {
+		if (get_line (menu_file, line) == -1) {
+			if (feof (menu_file))
+				break;
+			free_menu (&menu);
+			counter = -1;
+			goto out;
+		}
+
+		if (line[0] == '#')
+			continue;
+		
+		param = line;
+		while ((*param == ' ') || (*param == '\t'))
+			++ param;
+		if (*param == '\0')
+			continue;
+
+		value = strchr (line, '=');
+		if (! value) {
+			print_error ("%s at line '%s'", MSG_ERR_WRONG_SYNTAX, line);
+			free_menu (&menu);
+			counter = -1;
+			goto out;
+		} 
+		*value++ = '\0';
+
+		id = get_param_id (param);
+		if (id == CMD_UNKNOWN) {
+			print_error ("%s at line '%s'", MSG_ERR_WRONG_SYNTAX, line);
+			free_menu (&menu);
+			counter = -1;
+			goto out;
+		}
+
+		if (id == CMD_DEFAULT) {
+			strcpy (default_entry, value);
+		} else if (id == CMD_TIMEOUT) {
+			strcpy (timeout, value);
+		} else if (id == CMD_SERIAL) {
+			strcpy (serial, value);
+		} else if (id == CMD_TERMINAL) {
+			strcpy (terminal, value);
+		} else if (! add_param (&menu, id, value, &counter)) {
+			free_menu (&menu);
+			counter = -1;
+			goto out;
+		}
+	}
+
+out:
+	if (menu_file)
+		fclose (menu_file);
+
+	*entries_amount = counter;
+
+	return menu;
+}
+
+int
+write_menu (const char * config, const char * tmp_config, menu_list * menu)
+{
+	FILE * tmp_menu = fopen (tmp_config, "w");
+	unsigned int i = 0;
+
+	const char fnc[] = "write_menu";
+
+	debug_print ("%s\n", fnc);
+
+	if (! tmp_menu) {
+		print_system_error();
+		return 0;
+	}
+	
+	if (default_entry[0])
+		fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_DEFAULT], SEPARATOR, default_entry);
+	if (timeout[0])
+		fprintf (tmp_menu, "%s%s%s\n\n", cmd_list[CMD_TIMEOUT], SEPARATOR, timeout);
+	if (serial[0])
+		fprintf (tmp_menu, "%s%s%s\n\n", cmd_list[CMD_SERIAL], SEPARATOR, serial);
+	if (terminal[0])
+		fprintf (tmp_menu, "%s%s%s\n\n", cmd_list[CMD_TERMINAL], SEPARATOR, terminal);
+
+	while (menu) {
+		fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_ENTRY_NAME], SEPARATOR, menu->entry.entry_name);
+		if (menu->entry.pool_label[0])
+			fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_POOL_LABEL], SEPARATOR, menu->entry.pool_label);
+		if (menu->entry.pool_uuid[0])
+			fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_POOL_UUID], SEPARATOR, menu->entry.pool_uuid);
+		if (menu->entry.dataset[0])
+			fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_DATA_SET], SEPARATOR, menu->entry.dataset);
+		if (menu->entry.kernel[0])
+			fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_KERNEL_PATH], SEPARATOR, menu->entry.kernel);
+		if (menu->entry.kernel_opts[0])
+			fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_KERNEL_OPTIONS], SEPARATOR, menu->entry.kernel_opts);
+		if (menu->entry.modules_amount)
+			for (i = 0; i < menu->entry.modules_amount; ++i)
+				fprintf (tmp_menu, "%s%s%s\n", cmd_list[CMD_BA_PATH], SEPARATOR, menu->entry.modules[i]);
+		fprintf (tmp_menu, "#----------------------------------------------------\n");
+		menu = menu->next;
+	}
+
+	fclose (tmp_menu);
+
+	remove (config);
+	rename (tmp_config, config);
+
+	return 1;
+}
--- /dev/null	2012-08-31 05:09:01.000000000 +0400
+++ new/grubadm/menu.h	2012-08-31 05:09:01.443277154 +0400
@@ -0,0 +1,98 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2012, Daniil Lunev. All rights reserved.
+ */
+
+#define SEPARATOR "="
+
+typedef struct menu_entry menu_entry;
+typedef struct menu_list menu_list;
+typedef enum cmd_id cmd_id;
+
+struct menu_entry {
+	char entry_name[MAX_STRING_SIZE];
+	char pool_label[MAX_STRING_SIZE];
+	char pool_uuid[MAX_STRING_SIZE];
+	char dataset[MAX_STRING_SIZE];
+	char kernel[MAX_STRING_SIZE];
+	char kernel_opts[MAX_STRING_SIZE];
+	unsigned int modules_amount;
+	char ** modules;
+};
+
+extern char default_entry[MAX_STRING_SIZE];
+extern char timeout[MAX_STRING_SIZE];
+extern char serial[MAX_STRING_SIZE];
+extern char terminal[MAX_STRING_SIZE];
+
+struct menu_list {
+	unsigned int entry_number;
+	menu_entry entry;
+	menu_list * next;
+};
+
+enum cmd_id {
+	CMD_ENTRY_NAME,
+	CMD_POOL_LABEL,
+	CMD_POOL_UUID,
+	CMD_DATA_SET,
+	CMD_KERNEL_PATH,
+	CMD_KERNEL_OPTIONS,
+	CMD_BA_PATH,
+	CMD_DEFAULT,
+	CMD_TIMEOUT,
+	CMD_SERIAL,
+	CMD_TERMINAL,
+	CMD_UNKNOWN
+};
+
+extern const char * cmd_list[];
+
+void
+free_menu (menu_list ** menu);
+
+menu_list *
+parse_file (const char * file_name, int * entries_amount);
+
+void
+list_menu (menu_list * menu);
+
+menu_list *
+add_entry (menu_list ** menu, menu_list * entry);
+
+menu_list *
+clone_entry (menu_list  *entry);
+
+int
+delete_entry (menu_list ** menu, menu_list * del);
+
+menu_list *
+find_entry (menu_list * menu, menu_list * find);
+
+menu_list *
+enable_hyper (menu_list * entry);
+
+menu_list *
+disable_hyper (menu_list * entry);
+
+menu_list *
+get_entry_by_number (menu_list * menu, int number);
--- old/libbe/common/be_utils.c	2012-08-31 05:09:01.777503166 +0400
+++ new/libbe/common/be_utils.c	2012-08-31 05:09:01.806511114 +0400
@@ -461,11 +461,11 @@
 		char *tok = NULL;
 
 		(void) strlcpy(temp_line, line, BUFSIZ);
-		tok = strtok(line, BE_WHITE_SPACE);
+		tok = strtok(line, "=\n");
 
 		if (tok == NULL || tok[0] == '#') {
 			continue;
-		} else if (strcmp(tok, "title") == 0) {
+		} else if (strcmp(tok, "entry_name") == 0) {
 			collect_lines = B_FALSE;
 			if ((tok = strtok(NULL, "\n")) == NULL)
 				(void) strlcpy(title, "", sizeof (title));
@@ -480,7 +480,7 @@
 				}
 				num_tmp_lines = 0;
 			}
-		} else if (strcmp(tok, "bootfs") == 0) {
+		} else if (strcmp(tok, "data_set") == 0) {
 			char *bootfs = strtok(NULL, BE_WHITE_SPACE);
 			found_title = B_FALSE;
 			if (bootfs == NULL)
@@ -500,7 +500,7 @@
 				/*
 				 * Store the new title line
 				 */
-				(void) snprintf(str, BUFSIZ, "title %s\n",
+				(void) snprintf(str, BUFSIZ, "entry_name=%s\n",
 				    description ? description : be_name);
 				entries[num_lines] = strdup(str);
 				num_lines++;
@@ -514,11 +514,31 @@
 					tmp_entries[i] = NULL;
 					num_lines++;
 				}
-				num_tmp_lines = 0;
+
+				zprop_get_cbdata_t cb = { 0 };
+				zprop_source_t src;
+				char * bc = strchr(be_root_ds, '/');
+				char sguid[] = "guid";
+
+				*bc = '\0';
+				cb.cb_first = B_TRUE;
+				cb.cb_sources = ZPROP_SRC_ALL;
+				cb.cb_type = ZFS_TYPE_POOL;
+				zprop_get_list(g_zfs, sguid, &cb.cb_proplist, ZFS_TYPE_POOL);
+				zpool_handle_t * z_hndl = zpool_open(g_zfs, be_root_ds);
+				*bc = '/';
+				if (z_hndl) {
+					uint64_t guid = zpool_get_prop_int(z_hndl, cb.cb_proplist->pl_prop, &src);
+					(void) snprintf(str, BUFSIZ, "pool_uuid=%llx\n", guid);
+					entries[num_lines] = strdup(str);
+					num_lines++;
+					zpool_close(z_hndl);
+				}
+num_tmp_lines = 0;
 				/*
 				 * Store the new bootfs line.
 				 */
-				(void) snprintf(str, BUFSIZ, "bootfs %s\n",
+				(void) snprintf(str, BUFSIZ, "data_set=%s\n",
 				    be_root_ds);
 				entries[num_lines] = strdup(str);
 				num_lines++;
@@ -536,6 +556,19 @@
 				entries[num_lines] =
 				    strdup("splashimage "
 				    "/boot/splashimage.xpm\n");
+			} else if ((strcmp(tok, "kernel_path") == 0) || 
+				(strcmp(tok, "module") == 0)) 
+			{
+				char * path;
+				char * st_path;
+				
+				st_path = strtok(NULL, "\n");
+				path = (char *) malloc(512);
+				strcpy(path, tok);
+				strcat(path, "=");
+				strcat(path, st_path);
+				strcat(path, "\n");
+				entries[num_lines] = path;
 			} else {
 				entries[num_lines] = strdup(temp_line);
 			}
@@ -598,18 +631,36 @@
 			(void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
 		ret = BE_SUCCESS;
 	} else {
-		(void) fprintf(menu_fp, "title %s\n",
+		zprop_get_cbdata_t cb = { 0 };
+		zprop_source_t src;
+		char * bc = strchr(be_root_ds, '/');
+		char sguid[] = "guid";
+
+		(void) fprintf(menu_fp, "entry_name=%s\n",
 		    description ? description : be_name);
-		(void) fprintf(menu_fp, "bootfs %s\n", be_root_ds);
+		*bc = '\0';
+		cb.cb_first = B_TRUE;
+		cb.cb_sources = ZPROP_SRC_ALL;
+		cb.cb_type = ZFS_TYPE_POOL;
+		zprop_get_list(g_zfs, sguid, &cb.cb_proplist, ZFS_TYPE_POOL);
+		zpool_handle_t * z_hndl = zpool_open(g_zfs, be_root_ds);
+		*bc = '/';
+		if (z_hndl) {
+			uint64_t guid = zpool_get_prop_int(z_hndl, cb.cb_proplist->pl_prop, &src);
+			(void) fprintf(menu_fp, "pool_uuid=%llx\n", guid);
+			zpool_close(z_hndl);
+		}
+		(void) fprintf(menu_fp, "data_set=%s\n", be_root_ds);
 
 		/*
 		 * Check to see if this system supports grub
 		 */
 		if (be_has_grub()) {
-			(void) fprintf(menu_fp, "kernel$ "
-			    "/platform/i86pc/kernel/$ISADIR/unix -B "
-			    "$ZFS-BOOTFS\n");
-			(void) fprintf(menu_fp, "module$ "
+			(void) fprintf(menu_fp, "kernel_path="
+			    "/platform/i86pc/kernel/$ISADIR/unix\n");
+			(void) fprintf(menu_fp, "kernel_options="
+			    "-B $ZFS_BOOTFS,console=graphic\n");
+			(void) fprintf(menu_fp, "module="
 			    "/platform/i86pc/$ISADIR/boot_archive\n");
 			(void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
 		}
@@ -789,7 +840,7 @@
 		(void) strlcpy(tline, menu_buf, sizeof (tline));
 
 		/* Tokenize line */
-		tok = strtok(tline, BE_WHITE_SPACE);
+		tok = strtok(tline, "=\n");
 
 		if (tok == NULL || tok[0] == '#') {
 			/* Found empty line or comment line */
@@ -811,7 +862,7 @@
 				/* Write this line out */
 				(void) fputs(menu_buf, tmp_menu_fp);
 			}
-		} else if (strcmp(tok, "default") == 0) {
+		} else if (strcmp(tok, "default_entry") == 0) {
 			/*
 			 * Record what 'default' is set to because we might
 			 * need to adjust this upon deleting an entry.
@@ -823,7 +874,7 @@
 			}
 
 			(void) fputs(menu_buf, tmp_menu_fp);
-		} else if (strcmp(tok, "title") == 0) {
+		} else if (strcmp(tok, "entry_name") == 0) {
 			/*
 			 * If we've reached a 'title' line and do_buffer is
 			 * is true, that means we've just buffered an entire
@@ -859,7 +910,7 @@
 				goto cleanup;
 			}
 
-		} else if (strcmp(tok, "bootfs") == 0) {
+		} else if (strcmp(tok, "data_set") == 0) {
 			char *bootfs = NULL;
 
 			/*
@@ -1020,15 +1071,15 @@
 				(void) strlcpy(tline, menu_buf, sizeof (tline));
 
 				/* Tokenize line */
-				tok = strtok(tline, BE_WHITE_SPACE);
+				tok = strtok(tline, "=\n");
 
 				if (tok == NULL) {
 					/* Found empty line, write it out */
 					(void) fputs(menu_buf, tmp_menu_fp);
-				} else if (strcmp(tok, "default") == 0) {
+				} else if (strcmp(tok, "default_entry") == 0) {
 					/* Found the default line, adjust it */
 					(void) snprintf(tline, sizeof (tline),
-					    "default %d\n", default_entry);
+					    "default_entry=%d\n", default_entry);
 
 					(void) fputs(tline, tmp_menu_fp);
 				} else {
@@ -1187,11 +1238,11 @@
 	pool_mntpnt = NULL;
 
 	while (fgets(line, BUFSIZ, menu_fp)) {
-		char *tok = strtok(line, BE_WHITE_SPACE);
+		char *tok = strtok(line, "=\n");
 
 		if (tok != NULL && tok[0] != '#') {
 			if (!found_default) {
-				if (strcmp(tok, "default") == 0) {
+				if (strcmp(tok, "default_entry") == 0) {
 					tok = strtok(NULL, BE_WHITE_SPACE);
 					if (tok != NULL) {
 						default_entry = atoi(tok);
@@ -1201,10 +1252,10 @@
 				}
 				continue;
 			}
-			if (strcmp(tok, "title") == 0) {
+			if (strcmp(tok, "entry_name") == 0) {
 				entries++;
 			} else if (default_entry == entries - 1) {
-				if (strcmp(tok, "bootfs") == 0) {
+				if (strcmp(tok, "data_set") == 0) {
 					tok = strtok(NULL, BE_WHITE_SPACE);
 					(void) fclose(menu_fp);
 
@@ -1387,14 +1438,14 @@
 	}
 
 	while (fgets(line, BUFSIZ, grub_fp)) {
-		char *tok = strtok(line, BE_WHITE_SPACE);
+		char *tok = strtok(line, "=\n");
 
 		if (tok == NULL || tok[0] == '#') {
 			continue;
-		} else if (strcmp(tok, "title") == 0) {
+		} else if (strcmp(tok, "entry_name") == 0) {
 			entries++;
 			continue;
-		} else if (strcmp(tok, "bootfs") == 0) {
+		} else if (strcmp(tok, "data_set") == 0) {
 			char *bootfs = strtok(NULL, BE_WHITE_SPACE);
 			if (bootfs == NULL)
 				continue;
@@ -1416,16 +1467,16 @@
 
 	rewind(grub_fp);
 
+	(void) snprintf(temp_line, BUFSIZ, "default_entry=%d\n",
+	    entries - 1 >= 0 ? entries - 1 : 0);
+	(void) fputs(temp_line, temp_fp);
 	while (fgets(line, BUFSIZ, grub_fp)) {
 		char *tok = NULL;
 
 		(void) strncpy(temp_line, line, BUFSIZ);
 
-		if ((tok = strtok(temp_line, BE_WHITE_SPACE)) != NULL &&
-		    strcmp(tok, "default") == 0) {
-			(void) snprintf(temp_line, BUFSIZ, "default %d\n",
-			    entries - 1 >= 0 ? entries - 1 : 0);
-			(void) fputs(temp_line, temp_fp);
+		if ((tok = strtok(temp_line, "=\n")) != NULL &&
+		    strcmp(tok, "default_entry") == 0) {
 		} else {
 			(void) fputs(line, temp_fp);
 		}
@@ -1520,6 +1571,7 @@
 	int temp_menu_len = 0;
 	int tmp_fd;
 	int ret = BE_SUCCESS;
+	int flag = 0;
 	int err = 0;
 	boolean_t pool_mounted = B_FALSE;
 
@@ -1636,7 +1688,7 @@
 		(void) strlcpy(tline, line, sizeof (tline));
 
 		/* Tokenize line */
-		c = strtok(tline, BE_WHITE_SPACE);
+		c = strtok(tline, "=\n");
 
 		if (c == NULL) {
 			/* Found empty line, write it out. */
@@ -1644,7 +1696,7 @@
 		} else if (c[0] == '#') {
 			/* Found a comment line, write it out. */
 			(void) fputs(line, new_fp);
-		} else if (strcmp(c, "title") == 0) {
+		} else if (strcmp(c, "entry_name") == 0) {
 			char *name = NULL;
 			char *desc = NULL;
 
@@ -1652,6 +1704,7 @@
 			 * Found a 'title' line, parse out BE name or
 			 * the description.
 			 */
+			flag = 0;
 			name = strtok(NULL, BE_WHITE_SPACE);
 
 			if (name == NULL) {
@@ -1675,15 +1728,16 @@
 					 * along with the remainder of
 					 * description if there is one.
 					 */
+					++flag;
 					if (desc) {
 						(void) snprintf(new_line,
 						    sizeof (new_line),
-						    "title %s %s\n",
+						    "entry_name=%s %s\n",
 						    be_new_name, desc);
 					} else {
 						(void) snprintf(new_line,
 						    sizeof (new_line),
-						    "title %s\n", be_new_name);
+						    "entry_name=%s\n", be_new_name);
 					}
 
 					(void) fputs(new_line, new_fp);
@@ -1691,7 +1745,7 @@
 					(void) fputs(line, new_fp);
 				}
 			}
-		} else if (strcmp(c, "bootfs") == 0) {
+		} else if (strcmp(c, "data_set") == 0) {
 			/*
 			 * Found a 'bootfs' line, parse out the BE root
 			 * dataset value.
@@ -1710,8 +1764,9 @@
 				 * write out the new root dataset value
 				 */
 				if (strcmp(root_ds, be_root_ds) == 0) {
+					++flag;
 					(void) snprintf(new_line,
-					    sizeof (new_line), "bootfs %s\n",
+					    sizeof (new_line), "data_set=%s\n",
 					    be_new_root_ds);
 
 					(void) fputs(new_line, new_fp);
@@ -1853,10 +1908,10 @@
 	rpool_mntpnt = NULL;
 
 	while (fgets(line, BUFSIZ, menu_fp)) {
-		char *tok = strtok_r(line, BE_WHITE_SPACE, &last);
+		char *tok = strtok_r(line, "=\n", &last);
 
 		if (tok != NULL && tok[0] != '#') {
-			if (strcmp(tok, "bootfs") == 0) {
+			if (strcmp(tok, "data_set") == 0) {
 				tok = strtok_r(last, BE_WHITE_SPACE, &last);
 				if (tok != NULL && strcmp(tok,
 				    be_dataset) == 0) {
@@ -1873,7 +1928,7 @@
 					ret = B_TRUE;
 					goto cleanup;
 				}
-			} else if (strcmp(tok, "title") == 0)
+			} else if (strcmp(tok, "entry_name") == 0)
 				ent_num++;
 		}
 	}
@@ -3639,14 +3694,14 @@
 			if (strncmp(console, "text", strlen("text")) == 0 ||
 			    strncmp(console, "graphics",
 			    strlen("graphics")) == 0) {
-
+/*
 				(void) fprintf(temp_fp, "%s\n", BE_GRUB_SPLASH);
 				(void) fprintf(temp_fp, "%s\n",
 				    BE_GRUB_FOREGROUND);
 				(void) fprintf(temp_fp, "%s\n",
 				    BE_GRUB_BACKGROUND);
 				(void) fprintf(temp_fp, "%s\n",
-				    BE_GRUB_DEFAULT);
+				    BE_GRUB_DEFAULT);*/
 			} else {
 				be_print_err(gettext("be_create_menu: "
 				    "console on serial line, "
@@ -3654,7 +3709,7 @@
 			}
 		}
 
-		(void) fprintf(temp_fp,	"timeout 30\n");
+		(void) fprintf(temp_fp,	"timeout=30\n");
 		(void) fclose(temp_fp);
 
 	} else {
