--- /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;
+}
