1c262cbbcSToomas Soome /*
2c262cbbcSToomas Soome  * CDDL HEADER START
3c262cbbcSToomas Soome  *
4c262cbbcSToomas Soome  * The contents of this file are subject to the terms of the
5c262cbbcSToomas Soome  * Common Development and Distribution License (the "License").
6c262cbbcSToomas Soome  * You may not use this file except in compliance with the License.
7c262cbbcSToomas Soome  *
8c262cbbcSToomas Soome  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c262cbbcSToomas Soome  * or http://www.opensolaris.org/os/licensing.
10c262cbbcSToomas Soome  * See the License for the specific language governing permissions
11c262cbbcSToomas Soome  * and limitations under the License.
12c262cbbcSToomas Soome  *
13c262cbbcSToomas Soome  * When distributing Covered Code, include this CDDL HEADER in each
14c262cbbcSToomas Soome  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c262cbbcSToomas Soome  * If applicable, add the following below this CDDL HEADER, with the
16c262cbbcSToomas Soome  * fields enclosed by brackets "[]" replaced with your own identifying
17c262cbbcSToomas Soome  * information: Portions Copyright [yyyy] [name of copyright owner]
18c262cbbcSToomas Soome  *
19c262cbbcSToomas Soome  * CDDL HEADER END
20c262cbbcSToomas Soome  */
21c262cbbcSToomas Soome /*
22c262cbbcSToomas Soome  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23c262cbbcSToomas Soome  * Copyright 2012 Milan Jurik. All rights reserved.
24c262cbbcSToomas Soome  */
25c262cbbcSToomas Soome 
26c262cbbcSToomas Soome /*
27c262cbbcSToomas Soome  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28c262cbbcSToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
29e39d8488SAndy Fiddaman  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
30f13f1998SAlexander Eremin  * Copyright 2020 2020 Data Direct Networks.
31c262cbbcSToomas Soome  */
32c262cbbcSToomas Soome 
33c262cbbcSToomas Soome /*
34c262cbbcSToomas Soome  * Loader menu management.
35c262cbbcSToomas Soome  */
36c262cbbcSToomas Soome 
37c262cbbcSToomas Soome #include <stdio.h>
38c262cbbcSToomas Soome #include <stdlib.h>
39c262cbbcSToomas Soome #include <string.h>
40c262cbbcSToomas Soome #include <wchar.h>
41c262cbbcSToomas Soome #include <errno.h>
42c262cbbcSToomas Soome #include <limits.h>
43c262cbbcSToomas Soome #include <alloca.h>
44c262cbbcSToomas Soome #include <unistd.h>
45c262cbbcSToomas Soome #include <sys/types.h>
46c262cbbcSToomas Soome #include <sys/stat.h>
47c262cbbcSToomas Soome #include <sys/queue.h>
48c262cbbcSToomas Soome #include <libbe.h>
49c262cbbcSToomas Soome #include <ficl.h>
50c262cbbcSToomas Soome #include <ficlplatform/emu.h>
51760a3dc4SToomas Soome #include <ofmt.h>
52c262cbbcSToomas Soome 
53c262cbbcSToomas Soome #include "bootadm.h"
54c262cbbcSToomas Soome 
55c262cbbcSToomas Soome extern int bam_rootlen;
56c262cbbcSToomas Soome extern int bam_alt_root;
57c262cbbcSToomas Soome extern char *rootbuf;
58c262cbbcSToomas Soome extern char *bam_root;
59c262cbbcSToomas Soome 
60c262cbbcSToomas Soome #define	BOOT_DIR	"/boot"
61c262cbbcSToomas Soome #define	CONF_DIR	BOOT_DIR "/conf.d"
62c262cbbcSToomas Soome #define	MENU		BOOT_DIR "/menu.lst"
63c262cbbcSToomas Soome #define	TRANSIENT	BOOT_DIR "/transient.conf"
64c262cbbcSToomas Soome #define	XEN_CONFIG	CONF_DIR "/xen"
65c262cbbcSToomas Soome 
66760a3dc4SToomas Soome typedef struct menu_entry {
67760a3dc4SToomas Soome 	int me_idx;
68760a3dc4SToomas Soome 	boolean_t me_active;
69b713c91eSToomas Soome 	boolean_t me_active_next;
70760a3dc4SToomas Soome 	char *me_title;
71760a3dc4SToomas Soome 	char *me_type;
72760a3dc4SToomas Soome 	char *me_bootfs;
73760a3dc4SToomas Soome 	STAILQ_ENTRY(menu_entry) me_next;
74760a3dc4SToomas Soome } menu_entry_t;
75c262cbbcSToomas Soome STAILQ_HEAD(menu_lst, menu_entry);
76c262cbbcSToomas Soome 
77c262cbbcSToomas Soome static error_t set_option(struct menu_lst *, char *, char *);
78c262cbbcSToomas Soome static error_t list_entry(struct menu_lst *, char *, char *);
79c262cbbcSToomas Soome static error_t update_entry(struct menu_lst *, char *, char *);
80c262cbbcSToomas Soome static error_t update_temp(struct menu_lst *, char *, char *);
81c262cbbcSToomas Soome static error_t list_setting(struct menu_lst *menu, char *, char *);
82c262cbbcSToomas Soome static error_t disable_hyper(struct menu_lst *, char *, char *);
83c262cbbcSToomas Soome static error_t enable_hyper(struct menu_lst *, char *, char *);
84c262cbbcSToomas Soome 
85c262cbbcSToomas Soome /* Menu related sub commands */
86c262cbbcSToomas Soome static subcmd_defn_t menu_subcmds[] = {
87c262cbbcSToomas Soome 	"set_option",		OPT_ABSENT,	set_option, 0,	/* PUB */
88c262cbbcSToomas Soome 	"list_entry",		OPT_OPTIONAL,	list_entry, 1,	/* PUB */
89c262cbbcSToomas Soome 	"update_entry",		OPT_REQ,	update_entry, 0, /* menu */
90c262cbbcSToomas Soome 	"update_temp",		OPT_OPTIONAL,	update_temp, 0,	/* reboot */
91c262cbbcSToomas Soome 	"list_setting",		OPT_OPTIONAL,	list_setting, 1, /* menu */
92c262cbbcSToomas Soome 	"disable_hypervisor",	OPT_ABSENT,	disable_hyper, 0, /* menu */
93c262cbbcSToomas Soome 	"enable_hypervisor",	OPT_ABSENT,	enable_hyper, 0, /* menu */
94c262cbbcSToomas Soome 	NULL,			0,		NULL, 0 /* must be last */
95c262cbbcSToomas Soome };
96c262cbbcSToomas Soome 
97760a3dc4SToomas Soome #define	NUM_COLS	(5)
98c262cbbcSToomas Soome 
99760a3dc4SToomas Soome static boolean_t
print_menu_cb(ofmt_arg_t * ofarg,char * buf,uint_t bufsize)100760a3dc4SToomas Soome print_menu_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
101c262cbbcSToomas Soome {
102760a3dc4SToomas Soome 	menu_entry_t *entry = ofarg->ofmt_cbarg;
103760a3dc4SToomas Soome 
104760a3dc4SToomas Soome 	switch (ofarg->ofmt_id) {
105760a3dc4SToomas Soome 	case 0:
106760a3dc4SToomas Soome 		(void) snprintf(buf, bufsize, "%d", entry->me_idx);
107760a3dc4SToomas Soome 		break;
108760a3dc4SToomas Soome 	case 1:
109760a3dc4SToomas Soome 		(void) snprintf(buf, bufsize, "%s", entry->me_title);
110760a3dc4SToomas Soome 		break;
111760a3dc4SToomas Soome 	case 2:
112760a3dc4SToomas Soome 		(void) snprintf(buf, bufsize, "%s", entry->me_bootfs);
113760a3dc4SToomas Soome 		break;
114760a3dc4SToomas Soome 	case 3:
115760a3dc4SToomas Soome 		(void) snprintf(buf, bufsize, "%s", entry->me_type);
116760a3dc4SToomas Soome 		break;
117760a3dc4SToomas Soome 	case 4:
118b713c91eSToomas Soome 		if (entry->me_active_next == B_TRUE) {
119b713c91eSToomas Soome 			(void) snprintf(buf, bufsize, "   T");
120b713c91eSToomas Soome 			break;
121b713c91eSToomas Soome 		}
122760a3dc4SToomas Soome 		if (entry->me_active == B_TRUE)
123760a3dc4SToomas Soome 			(void) snprintf(buf, bufsize, "   *");
124760a3dc4SToomas Soome 		else
125760a3dc4SToomas Soome 			(void) snprintf(buf, bufsize, "   -");
126760a3dc4SToomas Soome 		break;
127760a3dc4SToomas Soome 	default:
128760a3dc4SToomas Soome 		return (B_FALSE);
129c262cbbcSToomas Soome 	}
130760a3dc4SToomas Soome 	return (B_TRUE);
131c262cbbcSToomas Soome }
132c262cbbcSToomas Soome 
133c262cbbcSToomas Soome static void
init_hdr_cols(ofmt_field_t * hdr)134760a3dc4SToomas Soome init_hdr_cols(ofmt_field_t *hdr)
135c262cbbcSToomas Soome {
136760a3dc4SToomas Soome 	uint_t i;
137c262cbbcSToomas Soome 
138c262cbbcSToomas Soome 	for (i = 0; i < NUM_COLS; i++) {
139760a3dc4SToomas Soome 		char *name = NULL;
140760a3dc4SToomas Soome 
141760a3dc4SToomas Soome 		switch (i) {
142760a3dc4SToomas Soome 		case 0:
143760a3dc4SToomas Soome 			name = _("INDEX");
144760a3dc4SToomas Soome 			break;
145760a3dc4SToomas Soome 		case 1:
146760a3dc4SToomas Soome 			name = _("NAME");
147760a3dc4SToomas Soome 			break;
148760a3dc4SToomas Soome 		case 2:
149760a3dc4SToomas Soome 			name = _("DEVICE");
150760a3dc4SToomas Soome 			break;
151760a3dc4SToomas Soome 		case 3:
152760a3dc4SToomas Soome 			name = _("TYPE");
153760a3dc4SToomas Soome 			break;
154760a3dc4SToomas Soome 		case 4:
155760a3dc4SToomas Soome 			name = _("DEFAULT");
156760a3dc4SToomas Soome 			break;
157760a3dc4SToomas Soome 		}
158760a3dc4SToomas Soome 
159760a3dc4SToomas Soome 		hdr[i].of_name = name;
160760a3dc4SToomas Soome 		hdr[i].of_id = i;
161760a3dc4SToomas Soome 		hdr[i].of_cb = print_menu_cb;
162c262cbbcSToomas Soome 
163c262cbbcSToomas Soome 		if (name != NULL) {
164c262cbbcSToomas Soome 			wchar_t wname[128];
165c262cbbcSToomas Soome 			size_t sz = mbstowcs(wname, name, sizeof (wname) /
166c262cbbcSToomas Soome 			    sizeof (wchar_t));
167c262cbbcSToomas Soome 			if (sz > 0) {
168c262cbbcSToomas Soome 				int wcsw = wcswidth(wname, sz);
169c262cbbcSToomas Soome 				if (wcsw > 0)
170760a3dc4SToomas Soome 					hdr[i].of_width = wcsw;
171c262cbbcSToomas Soome 				else
172760a3dc4SToomas Soome 					hdr[i].of_width = sz;
173c262cbbcSToomas Soome 			} else {
174760a3dc4SToomas Soome 				hdr[i].of_width = strlen(name);
175c262cbbcSToomas Soome 			}
176c262cbbcSToomas Soome 		}
177c262cbbcSToomas Soome 	}
178c262cbbcSToomas Soome }
179c262cbbcSToomas Soome 
180c262cbbcSToomas Soome static void
menu_update_widths(ofmt_field_t * hdr,struct menu_lst * menu)181760a3dc4SToomas Soome menu_update_widths(ofmt_field_t *hdr, struct menu_lst *menu)
182c262cbbcSToomas Soome {
183c262cbbcSToomas Soome 	size_t len[NUM_COLS];
184760a3dc4SToomas Soome 	menu_entry_t *entry;
185c262cbbcSToomas Soome 	int i;
186c262cbbcSToomas Soome 
187c262cbbcSToomas Soome 	for (i = 0; i < NUM_COLS; i++)
188760a3dc4SToomas Soome 		len[i] = hdr[i].of_width + 1;
189760a3dc4SToomas Soome 
190760a3dc4SToomas Soome 	STAILQ_FOREACH(entry, menu, me_next) {
191760a3dc4SToomas Soome 		size_t entry_len;
192760a3dc4SToomas Soome 
193760a3dc4SToomas Soome 		entry_len = strlen(entry->me_title) + 1;
194760a3dc4SToomas Soome 		if (entry_len > len[1])
195760a3dc4SToomas Soome 			len[1] = entry_len;
196c262cbbcSToomas Soome 
197760a3dc4SToomas Soome 		entry_len = strlen(entry->me_bootfs) + 1;
198760a3dc4SToomas Soome 		if (entry_len > len[2])
199760a3dc4SToomas Soome 			len[2] = entry_len;
200760a3dc4SToomas Soome 
201760a3dc4SToomas Soome 		entry_len = strlen(entry->me_type) + 1;
202760a3dc4SToomas Soome 		if (entry_len > len[3])
203760a3dc4SToomas Soome 			len[3] = entry_len;
204c262cbbcSToomas Soome 	}
205c262cbbcSToomas Soome 
206c262cbbcSToomas Soome 	for (i = 0; i < NUM_COLS; i++)
207760a3dc4SToomas Soome 		hdr[i].of_width = len[i];
208760a3dc4SToomas Soome }
209760a3dc4SToomas Soome 
210760a3dc4SToomas Soome static ofmt_field_t *
init_menu_template(struct menu_lst * menu)211760a3dc4SToomas Soome init_menu_template(struct menu_lst *menu)
212760a3dc4SToomas Soome {
213760a3dc4SToomas Soome 	ofmt_field_t *temp;
214760a3dc4SToomas Soome 
215760a3dc4SToomas Soome 	if ((temp = calloc(NUM_COLS + 1, sizeof (ofmt_field_t))) == NULL)
216760a3dc4SToomas Soome 		return (temp);
217760a3dc4SToomas Soome 
218760a3dc4SToomas Soome 	init_hdr_cols(temp);
219760a3dc4SToomas Soome 	menu_update_widths(temp, menu);
220760a3dc4SToomas Soome 	return (temp);
221c262cbbcSToomas Soome }
222c262cbbcSToomas Soome 
223c262cbbcSToomas Soome static void
print_nodes(boolean_t parsable,struct menu_lst * menu)224760a3dc4SToomas Soome print_nodes(boolean_t parsable, struct menu_lst *menu)
225c262cbbcSToomas Soome {
226760a3dc4SToomas Soome 	ofmt_status_t oferr;
227760a3dc4SToomas Soome 	ofmt_handle_t ofmt;
228760a3dc4SToomas Soome 	uint_t ofmtflags = 0;
229760a3dc4SToomas Soome 	ofmt_field_t *menu_template;
230760a3dc4SToomas Soome 	menu_entry_t  *entry;
231c262cbbcSToomas Soome 
232760a3dc4SToomas Soome 	if (parsable == B_TRUE)
233760a3dc4SToomas Soome 		ofmtflags = OFMT_PARSABLE;
234c262cbbcSToomas Soome 
235760a3dc4SToomas Soome 	menu_template = init_menu_template(menu);
236760a3dc4SToomas Soome 	oferr = ofmt_open(NULL, menu_template, ofmtflags, 0, &ofmt);
237c262cbbcSToomas Soome 
238760a3dc4SToomas Soome 	if (oferr != OFMT_SUCCESS) {
239760a3dc4SToomas Soome 		char buf[OFMT_BUFSIZE];
240760a3dc4SToomas Soome 
241760a3dc4SToomas Soome 		(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
242760a3dc4SToomas Soome 		(void) printf("bootadm: %s\n", buf);
243760a3dc4SToomas Soome 		free(menu_template);
244760a3dc4SToomas Soome 		return;
245c262cbbcSToomas Soome 	}
246760a3dc4SToomas Soome 
247760a3dc4SToomas Soome 	STAILQ_FOREACH(entry, menu, me_next)
248760a3dc4SToomas Soome 		ofmt_print(ofmt, entry);
249760a3dc4SToomas Soome 
250760a3dc4SToomas Soome 	ofmt_close(ofmt);
251760a3dc4SToomas Soome 	free(menu_template);
252c262cbbcSToomas Soome }
253c262cbbcSToomas Soome 
254760a3dc4SToomas Soome /*
255760a3dc4SToomas Soome  * Get the be_active_on_boot for bootfs.
256760a3dc4SToomas Soome  */
257760a3dc4SToomas Soome static boolean_t
menu_active_on_boot(be_node_list_t * be_nodes,const char * bootfs)258760a3dc4SToomas Soome menu_active_on_boot(be_node_list_t *be_nodes, const char *bootfs)
259c262cbbcSToomas Soome {
260760a3dc4SToomas Soome 	be_node_list_t *be_node;
261760a3dc4SToomas Soome 	boolean_t rv = B_FALSE;
262c262cbbcSToomas Soome 
263760a3dc4SToomas Soome 	for (be_node = be_nodes; be_node != NULL;
264760a3dc4SToomas Soome 	    be_node = be_node->be_next_node) {
265760a3dc4SToomas Soome 		if (strcmp(be_node->be_root_ds, bootfs) == 0) {
266760a3dc4SToomas Soome 			rv = be_node->be_active_on_boot;
267760a3dc4SToomas Soome 			break;
268760a3dc4SToomas Soome 		}
269c262cbbcSToomas Soome 	}
270c262cbbcSToomas Soome 
271760a3dc4SToomas Soome 	return (rv);
272c262cbbcSToomas Soome }
273c262cbbcSToomas Soome 
274b713c91eSToomas Soome /*
275b713c91eSToomas Soome  * Get the be_active_next for bootfs.
276b713c91eSToomas Soome  */
277b713c91eSToomas Soome static boolean_t
menu_active_next(be_node_list_t * be_nodes,const char * bootfs)278b713c91eSToomas Soome menu_active_next(be_node_list_t *be_nodes, const char *bootfs)
279b713c91eSToomas Soome {
280b713c91eSToomas Soome 	be_node_list_t *be_node;
281b713c91eSToomas Soome 	boolean_t rv = B_FALSE;
282b713c91eSToomas Soome 
283b713c91eSToomas Soome 	for (be_node = be_nodes; be_node != NULL;
284b713c91eSToomas Soome 	    be_node = be_node->be_next_node) {
285b713c91eSToomas Soome 		if (strcmp(be_node->be_root_ds, bootfs) == 0) {
286b713c91eSToomas Soome 			rv = be_node->be_active_next;
287b713c91eSToomas Soome 			break;
288b713c91eSToomas Soome 		}
289b713c91eSToomas Soome 	}
290b713c91eSToomas Soome 
291b713c91eSToomas Soome 	return (rv);
292b713c91eSToomas Soome }
293b713c91eSToomas Soome 
294c262cbbcSToomas Soome error_t
menu_read(struct menu_lst * menu,char * menu_path)295c262cbbcSToomas Soome menu_read(struct menu_lst *menu, char *menu_path)
296c262cbbcSToomas Soome {
297c262cbbcSToomas Soome 	FILE *fp;
298760a3dc4SToomas Soome 	be_node_list_t *be_nodes;
299760a3dc4SToomas Soome 	menu_entry_t *mp;
300c262cbbcSToomas Soome 	char buf[PATH_MAX];
301c262cbbcSToomas Soome 	char *title;
302c262cbbcSToomas Soome 	char *bootfs;
303760a3dc4SToomas Soome 	char *type;
304760a3dc4SToomas Soome 	char *key, *value;
305c262cbbcSToomas Soome 	int i = 0;
306c262cbbcSToomas Soome 	int ret = BAM_SUCCESS;
307c262cbbcSToomas Soome 
308c262cbbcSToomas Soome 	fp = fopen(menu_path, "r");
309c262cbbcSToomas Soome 	if (fp == NULL)
310c262cbbcSToomas Soome 		return (BAM_ERROR);
311c262cbbcSToomas Soome 
312a897f28bSAndy Fiddaman 	if (be_list(NULL, &be_nodes, BE_LIST_DEFAULT) != BE_SUCCESS)
313760a3dc4SToomas Soome 		be_nodes = NULL;
314760a3dc4SToomas Soome 
315c262cbbcSToomas Soome 	/*
316c262cbbcSToomas Soome 	 * menu.lst entry is on two lines, one for title, one for bootfs
317c262cbbcSToomas Soome 	 * so we process both lines in succession.
318c262cbbcSToomas Soome 	 */
319760a3dc4SToomas Soome 	title = NULL;
320760a3dc4SToomas Soome 	type = NULL;
321760a3dc4SToomas Soome 	bootfs = NULL;
322c262cbbcSToomas Soome 	do {
323c262cbbcSToomas Soome 		if (fgets(buf, PATH_MAX, fp) == NULL) {
324c262cbbcSToomas Soome 			if (!feof(fp))
325c262cbbcSToomas Soome 				ret = BAM_ERROR;
326760a3dc4SToomas Soome 			goto done;
327c262cbbcSToomas Soome 		}
328eaf9751fSToomas Soome 		if (buf[0] == '\n')	/* Skip empty lines */
329eaf9751fSToomas Soome 			continue;
330eaf9751fSToomas Soome 
331760a3dc4SToomas Soome 		key = strtok(buf, " \n");
332eaf9751fSToomas Soome 		if (key == NULL || strcmp(key, "title") != 0) {
333760a3dc4SToomas Soome 			ret = BAM_ERROR;
334760a3dc4SToomas Soome 			goto done;
335c262cbbcSToomas Soome 		}
336760a3dc4SToomas Soome 		value = strtok(NULL, " \n");
337eaf9751fSToomas Soome 		if (value == NULL || (title = strdup(value)) == NULL) {
338760a3dc4SToomas Soome 			ret = BAM_ERROR;
339760a3dc4SToomas Soome 			goto done;
340c262cbbcSToomas Soome 		}
341c262cbbcSToomas Soome 
342eaf9751fSToomas Soome 		do {
343eaf9751fSToomas Soome 			if (fgets(buf, PATH_MAX, fp) == NULL) {
344eaf9751fSToomas Soome 				ret = BAM_ERROR;
345eaf9751fSToomas Soome 				goto done;
346eaf9751fSToomas Soome 			}
347eaf9751fSToomas Soome 		} while (buf[0] == '\n');	/* Skip empty lines */
348c262cbbcSToomas Soome 
349760a3dc4SToomas Soome 		key = strtok(buf, " \n");
350eaf9751fSToomas Soome 		if (key == NULL || (type = strdup(key)) == NULL) {
351760a3dc4SToomas Soome 			ret = BAM_ERROR;
352760a3dc4SToomas Soome 			goto done;
353c262cbbcSToomas Soome 		}
354760a3dc4SToomas Soome 		value = strtok(NULL, " \n");
355eaf9751fSToomas Soome 		if (value == NULL || (bootfs = strdup(value)) == NULL) {
356760a3dc4SToomas Soome 			ret = BAM_ERROR;
357760a3dc4SToomas Soome 			goto done;
358c262cbbcSToomas Soome 		}
359760a3dc4SToomas Soome 		if ((mp = malloc(sizeof (menu_entry_t))) == NULL) {
360760a3dc4SToomas Soome 			ret = BAM_ERROR;
361760a3dc4SToomas Soome 			goto done;
362c262cbbcSToomas Soome 		}
363760a3dc4SToomas Soome 		mp->me_idx = i++;
364760a3dc4SToomas Soome 		mp->me_title = title;
365760a3dc4SToomas Soome 		mp->me_type = type;
366760a3dc4SToomas Soome 		mp->me_bootfs = bootfs;
367760a3dc4SToomas Soome 		mp->me_active = menu_active_on_boot(be_nodes, bootfs);
368b713c91eSToomas Soome 		mp->me_active_next = menu_active_next(be_nodes, bootfs);
369760a3dc4SToomas Soome 		STAILQ_INSERT_TAIL(menu, mp, me_next);
370760a3dc4SToomas Soome 
371760a3dc4SToomas Soome 		title = NULL;
372760a3dc4SToomas Soome 		type = NULL;
373760a3dc4SToomas Soome 		bootfs = NULL;
374c262cbbcSToomas Soome 	} while (feof(fp) == 0);
375c262cbbcSToomas Soome 
376760a3dc4SToomas Soome done:
377760a3dc4SToomas Soome 	free(title);
378760a3dc4SToomas Soome 	free(type);
379760a3dc4SToomas Soome 	free(bootfs);
380c262cbbcSToomas Soome 	(void) fclose(fp);
381760a3dc4SToomas Soome 	be_free_list(be_nodes);
382c262cbbcSToomas Soome 	return (ret);
383c262cbbcSToomas Soome }
384c262cbbcSToomas Soome 
385c262cbbcSToomas Soome void
menu_free(struct menu_lst * menu)386c262cbbcSToomas Soome menu_free(struct menu_lst *menu)
387c262cbbcSToomas Soome {
388760a3dc4SToomas Soome 	menu_entry_t *entry;
389135ec7c8SToomas Soome 
390135ec7c8SToomas Soome 	while (!STAILQ_EMPTY(menu)) {
391135ec7c8SToomas Soome 		entry = STAILQ_FIRST(menu);
392760a3dc4SToomas Soome 		STAILQ_REMOVE_HEAD(menu, me_next);
393760a3dc4SToomas Soome 		free(entry->me_title);
394760a3dc4SToomas Soome 		free(entry->me_type);
395760a3dc4SToomas Soome 		free(entry->me_bootfs);
396c262cbbcSToomas Soome 		free(entry);
397c262cbbcSToomas Soome 	}
398c262cbbcSToomas Soome }
399c262cbbcSToomas Soome 
400c262cbbcSToomas Soome error_t
bam_loader_menu(char * subcmd,char * opt,int largc,char * largv[])401c262cbbcSToomas Soome bam_loader_menu(char *subcmd, char *opt, int largc, char *largv[])
402c262cbbcSToomas Soome {
403c262cbbcSToomas Soome 	error_t		ret;
404c262cbbcSToomas Soome 	char		menu_path[PATH_MAX];
405c262cbbcSToomas Soome 	char		clean_menu_root[PATH_MAX];
406c262cbbcSToomas Soome 	char		menu_root[PATH_MAX];
407c262cbbcSToomas Soome 	struct stat	sb;
408c262cbbcSToomas Soome 	error_t		(*f)(struct menu_lst *, char *, char *);
409c262cbbcSToomas Soome 	char		*special;
410c262cbbcSToomas Soome 	char		*pool = NULL;
411c262cbbcSToomas Soome 	zfs_mnted_t	zmnted;
412c262cbbcSToomas Soome 	char		*zmntpt;
413c262cbbcSToomas Soome 	char		*osdev;
414c262cbbcSToomas Soome 	char		*osroot;
415c262cbbcSToomas Soome 	const char	*fcn = "bam_loader_menu()";
416c262cbbcSToomas Soome 	struct menu_lst	menu = {0};
417c262cbbcSToomas Soome 
418c262cbbcSToomas Soome 	STAILQ_INIT(&menu);
419c262cbbcSToomas Soome 
420c262cbbcSToomas Soome 	/*
421c262cbbcSToomas Soome 	 * Check arguments
422c262cbbcSToomas Soome 	 */
423c262cbbcSToomas Soome 	ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f);
424c262cbbcSToomas Soome 	if (ret == BAM_ERROR) {
425c262cbbcSToomas Soome 		return (BAM_ERROR);
426c262cbbcSToomas Soome 	}
427c262cbbcSToomas Soome 
428c262cbbcSToomas Soome 	assert(bam_root);
429c262cbbcSToomas Soome 
430c262cbbcSToomas Soome 	(void) strlcpy(menu_root, bam_root, sizeof (menu_root));
431c262cbbcSToomas Soome 	osdev = osroot = NULL;
432c262cbbcSToomas Soome 
433c262cbbcSToomas Soome 	if (strcmp(subcmd, "update_entry") == 0) {
434c262cbbcSToomas Soome 		assert(opt);
435c262cbbcSToomas Soome 
436c262cbbcSToomas Soome 		osdev = strtok(opt, ",");
437c262cbbcSToomas Soome 		assert(osdev);
438c262cbbcSToomas Soome 		osroot = strtok(NULL, ",");
439c262cbbcSToomas Soome 		if (osroot) {
440c262cbbcSToomas Soome 			/* fixup bam_root so that it points at osroot */
441c262cbbcSToomas Soome 			if (realpath(osroot, rootbuf) == NULL) {
442c262cbbcSToomas Soome 				bam_error(_("cannot resolve path %s: %s\n"),
443c262cbbcSToomas Soome 				    osroot, strerror(errno));
444c262cbbcSToomas Soome 				return (BAM_ERROR);
445c262cbbcSToomas Soome 			}
446c262cbbcSToomas Soome 			bam_alt_root = 1;
447c262cbbcSToomas Soome 			bam_root  = rootbuf;
448c262cbbcSToomas Soome 			bam_rootlen = strlen(rootbuf);
449c262cbbcSToomas Soome 		}
450c262cbbcSToomas Soome 	}
451c262cbbcSToomas Soome 
452c262cbbcSToomas Soome 	if (stat(menu_root, &sb) == -1) {
453c262cbbcSToomas Soome 		bam_error(_("cannot find menu\n"));
454c262cbbcSToomas Soome 		return (BAM_ERROR);
455c262cbbcSToomas Soome 	}
456c262cbbcSToomas Soome 
457c262cbbcSToomas Soome 	if (!is_zfs(menu_root)) {
458c262cbbcSToomas Soome 		bam_error(_("only ZFS root is supported\n"));
459c262cbbcSToomas Soome 		return (BAM_ERROR);
460c262cbbcSToomas Soome 	}
461c262cbbcSToomas Soome 
462c262cbbcSToomas Soome 	assert(strcmp(menu_root, bam_root) == 0);
463c262cbbcSToomas Soome 	special = get_special(menu_root);
464c262cbbcSToomas Soome 	INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL);
465c262cbbcSToomas Soome 	if (special == NULL) {
466c262cbbcSToomas Soome 		bam_error(_("cant find special file for mount-point %s\n"),
467c262cbbcSToomas Soome 		    menu_root);
468c262cbbcSToomas Soome 		return (BAM_ERROR);
469c262cbbcSToomas Soome 	}
470c262cbbcSToomas Soome 	pool = strtok(special, "/");
471c262cbbcSToomas Soome 	INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL);
472c262cbbcSToomas Soome 	if (pool == NULL) {
473c262cbbcSToomas Soome 		free(special);
474c262cbbcSToomas Soome 		bam_error(_("cant find pool for mount-point %s\n"), menu_root);
475c262cbbcSToomas Soome 		return (BAM_ERROR);
476c262cbbcSToomas Soome 	}
477c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: derived pool=%s from special\n", fcn, pool));
478c262cbbcSToomas Soome 
479c262cbbcSToomas Soome 	zmntpt = mount_top_dataset(pool, &zmnted);
480c262cbbcSToomas Soome 	INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL);
481c262cbbcSToomas Soome 	if (zmntpt == NULL) {
482c262cbbcSToomas Soome 		bam_error(_("cannot mount pool dataset for pool: %s\n"), pool);
483c262cbbcSToomas Soome 		free(special);
484c262cbbcSToomas Soome 		return (BAM_ERROR);
485c262cbbcSToomas Soome 	}
486c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: top dataset mountpoint=%s\n", fcn, zmntpt));
487c262cbbcSToomas Soome 
488c262cbbcSToomas Soome 	(void) strlcpy(menu_root, zmntpt, sizeof (menu_root));
489c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: zfs menu_root=%s\n", fcn, menu_root));
490c262cbbcSToomas Soome 
491c262cbbcSToomas Soome 	elide_trailing_slash(menu_root, clean_menu_root,
492c262cbbcSToomas Soome 	    sizeof (clean_menu_root));
493c262cbbcSToomas Soome 
494c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: cleaned menu root is <%s>\n", fcn, clean_menu_root));
495c262cbbcSToomas Soome 
496c262cbbcSToomas Soome 	(void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path));
497c262cbbcSToomas Soome 	(void) strlcat(menu_path, MENU, sizeof (menu_path));
498c262cbbcSToomas Soome 
499c262cbbcSToomas Soome 	BAM_DPRINTF(("%s: menu path is: %s\n", fcn, menu_path));
500c262cbbcSToomas Soome 
501c262cbbcSToomas Soome 	/*
502c262cbbcSToomas Soome 	 * update_entry is special case, its used by installer
503c262cbbcSToomas Soome 	 * and needs to create menu.lst file for loader
504c262cbbcSToomas Soome 	 */
505c262cbbcSToomas Soome 	if (menu_read(&menu, menu_path) == BAM_ERROR &&
506c262cbbcSToomas Soome 	    strcmp(subcmd, "update_entry") != 0) {
507c262cbbcSToomas Soome 		bam_error(_("cannot find menu file: %s\n"), menu_path);
508c262cbbcSToomas Soome 		if (special != NULL)
509c262cbbcSToomas Soome 			free(special);
510c262cbbcSToomas Soome 		return (BAM_ERROR);
511c262cbbcSToomas Soome 	}
512c262cbbcSToomas Soome 
513c262cbbcSToomas Soome 	/*
514c262cbbcSToomas Soome 	 * If listing the menu, display the menu location
515c262cbbcSToomas Soome 	 */
516c262cbbcSToomas Soome 	if (strcmp(subcmd, "list_entry") == 0)
517c262cbbcSToomas Soome 		bam_print(_("the location for the active menu is: %s\n"),
518c262cbbcSToomas Soome 		    menu_path);
519c262cbbcSToomas Soome 
520c262cbbcSToomas Soome 	/*
521c262cbbcSToomas Soome 	 * We already checked the following case in
522c262cbbcSToomas Soome 	 * check_subcmd_and_suboptions() above. Complete the
523c262cbbcSToomas Soome 	 * final step now.
524c262cbbcSToomas Soome 	 */
525c262cbbcSToomas Soome 	if (strcmp(subcmd, "set_option") == 0) {
526c262cbbcSToomas Soome 		assert(largc == 1 && largv[0] && largv[1] == NULL);
527c262cbbcSToomas Soome 		opt = largv[0];
528c262cbbcSToomas Soome 	} else if ((strcmp(subcmd, "enable_hypervisor") != 0) &&
529c262cbbcSToomas Soome 	    (strcmp(subcmd, "list_setting") != 0)) {
530c262cbbcSToomas Soome 		assert(largc == 0 && largv == NULL);
531c262cbbcSToomas Soome 	}
532c262cbbcSToomas Soome 
533c262cbbcSToomas Soome 	/*
534c262cbbcSToomas Soome 	 * Once the sub-cmd handler has run
535c262cbbcSToomas Soome 	 * only the line field is guaranteed to have valid values
536c262cbbcSToomas Soome 	 */
537c262cbbcSToomas Soome 	if (strcmp(subcmd, "update_entry") == 0) {
538c262cbbcSToomas Soome 		ret = f(&menu, menu_root, osdev);
539c262cbbcSToomas Soome 	} else if (strcmp(subcmd, "upgrade") == 0) {
540c262cbbcSToomas Soome 		ret = f(&menu, bam_root, menu_root);
541c262cbbcSToomas Soome 	} else if (strcmp(subcmd, "list_entry") == 0) {
542c262cbbcSToomas Soome 		ret = f(&menu, menu_path, opt);
543c262cbbcSToomas Soome 	} else if (strcmp(subcmd, "list_setting") == 0) {
544c262cbbcSToomas Soome 		ret = f(&menu, ((largc > 0) ? largv[0] : ""),
545c262cbbcSToomas Soome 		    ((largc > 1) ? largv[1] : ""));
546c262cbbcSToomas Soome 	} else if (strcmp(subcmd, "disable_hypervisor") == 0) {
547c262cbbcSToomas Soome 		if (is_sparc()) {
548c262cbbcSToomas Soome 			bam_error(_("%s operation unsupported on SPARC "
549c262cbbcSToomas Soome 			    "machines\n"), subcmd);
550c262cbbcSToomas Soome 			ret = BAM_ERROR;
551c262cbbcSToomas Soome 		} else {
552c262cbbcSToomas Soome 			ret = f(&menu, bam_root, NULL);
553c262cbbcSToomas Soome 		}
554c262cbbcSToomas Soome 	} else if (strcmp(subcmd, "enable_hypervisor") == 0) {
555c262cbbcSToomas Soome 		if (is_sparc()) {
556c262cbbcSToomas Soome 			bam_error(_("%s operation unsupported on SPARC "
557c262cbbcSToomas Soome 			    "machines\n"), subcmd);
558c262cbbcSToomas Soome 			ret = BAM_ERROR;
559c262cbbcSToomas Soome 		} else {
560c262cbbcSToomas Soome 			char *extra_args = NULL;
561c262cbbcSToomas Soome 
562c262cbbcSToomas Soome 			/*
563c262cbbcSToomas Soome 			 * Compress all arguments passed in the largv[] array
564c262cbbcSToomas Soome 			 * into one string that can then be appended to the
565c262cbbcSToomas Soome 			 * end of the kernel$ string the routine to enable the
566c262cbbcSToomas Soome 			 * hypervisor will build.
567c262cbbcSToomas Soome 			 *
568c262cbbcSToomas Soome 			 * This allows the caller to supply arbitrary unparsed
569c262cbbcSToomas Soome 			 * arguments, such as dom0 memory settings or APIC
570c262cbbcSToomas Soome 			 * options.
571c262cbbcSToomas Soome 			 *
572c262cbbcSToomas Soome 			 * This concatenation will be done without ANY syntax
573c262cbbcSToomas Soome 			 * checking whatsoever, so it's the responsibility of
574c262cbbcSToomas Soome 			 * the caller to make sure the arguments are valid and
575c262cbbcSToomas Soome 			 * do not duplicate arguments the conversion routines
576c262cbbcSToomas Soome 			 * may create.
577c262cbbcSToomas Soome 			 */
578c262cbbcSToomas Soome 			if (largc > 0) {
579c262cbbcSToomas Soome 				int extra_len, i;
580c262cbbcSToomas Soome 
581c262cbbcSToomas Soome 				for (extra_len = 0, i = 0; i < largc; i++)
582c262cbbcSToomas Soome 					extra_len += strlen(largv[i]);
583c262cbbcSToomas Soome 
584c262cbbcSToomas Soome 				/*
585c262cbbcSToomas Soome 				 * Allocate space for argument strings,
586c262cbbcSToomas Soome 				 * intervening spaces and terminating NULL.
587c262cbbcSToomas Soome 				 */
588c262cbbcSToomas Soome 				extra_args = alloca(extra_len + largc);
589c262cbbcSToomas Soome 
590c262cbbcSToomas Soome 				(void) strcpy(extra_args, largv[0]);
591c262cbbcSToomas Soome 
592c262cbbcSToomas Soome 				for (i = 1; i < largc; i++) {
593c262cbbcSToomas Soome 					(void) strcat(extra_args, " ");
594c262cbbcSToomas Soome 					(void) strcat(extra_args, largv[i]);
595c262cbbcSToomas Soome 				}
596c262cbbcSToomas Soome 			}
597c262cbbcSToomas Soome 
598c262cbbcSToomas Soome 			ret = f(&menu, bam_root, extra_args);
599c262cbbcSToomas Soome 		}
600c262cbbcSToomas Soome 	} else
601c262cbbcSToomas Soome 		ret = f(&menu, NULL, opt);
602c262cbbcSToomas Soome 
603c262cbbcSToomas Soome 	if (ret == BAM_WRITE) {
604c262cbbcSToomas Soome 		BAM_DPRINTF(("%s: writing menu to clean-menu-root: <%s>\n",
605c262cbbcSToomas Soome 		    fcn, clean_menu_root));
606c262cbbcSToomas Soome 		/* ret = menu_write(clean_menu_root, menu); */
607c262cbbcSToomas Soome 	}
608c262cbbcSToomas Soome 
609c262cbbcSToomas Soome 	INJECT_ERROR1("POOL_SET", pool = "/pooldata");
610c262cbbcSToomas Soome 	assert((is_zfs(menu_root)) ^ (pool == NULL));
611c262cbbcSToomas Soome 	if (pool) {
612c262cbbcSToomas Soome 		(void) umount_top_dataset(pool, zmnted, zmntpt);
613c262cbbcSToomas Soome 		free(special);
614c262cbbcSToomas Soome 	}
615c262cbbcSToomas Soome 
616c262cbbcSToomas Soome 	menu_free(&menu);
617c262cbbcSToomas Soome 	return (ret);
618c262cbbcSToomas Soome }
619c262cbbcSToomas Soome 
620c262cbbcSToomas Soome /*
621c262cbbcSToomas Soome  * To suppress output from ficl. We do not want to see messages
622c262cbbcSToomas Soome  * from interpreting loader config.
623c262cbbcSToomas Soome  */
624c262cbbcSToomas Soome 
625c262cbbcSToomas Soome /*ARGSUSED*/
626c262cbbcSToomas Soome static void
ficlTextOutSilent(ficlCallback * cb,char * text)627c262cbbcSToomas Soome ficlTextOutSilent(ficlCallback *cb, char *text)
628c262cbbcSToomas Soome {
629c262cbbcSToomas Soome }
630c262cbbcSToomas Soome 
631c262cbbcSToomas Soome /*ARGSUSED*/
632c262cbbcSToomas Soome static error_t
set_option(struct menu_lst * menu,char * dummy,char * opt)633c262cbbcSToomas Soome set_option(struct menu_lst *menu, char *dummy, char *opt)
634c262cbbcSToomas Soome {
635c262cbbcSToomas Soome 	char path[PATH_MAX];
636c262cbbcSToomas Soome 	char *val;
637c262cbbcSToomas Soome 	char *rest;
638c262cbbcSToomas Soome 	int optval;
639760a3dc4SToomas Soome 	menu_entry_t *entry;
640c262cbbcSToomas Soome 	nvlist_t *be_attrs;
641c262cbbcSToomas Soome 	FILE *fp;
642c262cbbcSToomas Soome 	int rv, ret = BAM_SUCCESS;
643c262cbbcSToomas Soome 
644c262cbbcSToomas Soome 	assert(menu);
645c262cbbcSToomas Soome 	assert(opt);
646c262cbbcSToomas Soome 	assert(dummy == NULL);
647c262cbbcSToomas Soome 
648c262cbbcSToomas Soome 	val = strchr(opt, '=');
649c262cbbcSToomas Soome 	if (val != NULL) {
650c262cbbcSToomas Soome 		*val++ = '\0';
651f13f1998SAlexander Eremin 	} else {
652f13f1998SAlexander Eremin 		bam_error(_("missing value in key=value\n"));
653f13f1998SAlexander Eremin 		return (BAM_ERROR);
654c262cbbcSToomas Soome 	}
655c262cbbcSToomas Soome 
656c262cbbcSToomas Soome 	if (strcmp(opt, "default") == 0) {
657c262cbbcSToomas Soome 		errno = 0;
658c262cbbcSToomas Soome 		optval = strtol(val, &rest, 10);
659c262cbbcSToomas Soome 		if (errno != 0 || *rest != '\0') {
660c262cbbcSToomas Soome 			bam_error(_("invalid boot entry number: %s\n"), val);
661c262cbbcSToomas Soome 			return (BAM_ERROR);
662c262cbbcSToomas Soome 		}
663760a3dc4SToomas Soome 		STAILQ_FOREACH(entry, menu, me_next) {
664760a3dc4SToomas Soome 			if (entry->me_idx == optval)
665c262cbbcSToomas Soome 				break;
666c262cbbcSToomas Soome 		}
667c262cbbcSToomas Soome 		if (entry == NULL) {
668c262cbbcSToomas Soome 			bam_error(_("invalid boot entry number: %s\n"), val);
669c262cbbcSToomas Soome 			return (BAM_ERROR);
670c262cbbcSToomas Soome 		}
671c262cbbcSToomas Soome 		if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
672c262cbbcSToomas Soome 			bam_error(_("out of memory\n"));
673c262cbbcSToomas Soome 			return (BAM_ERROR);
674c262cbbcSToomas Soome 		}
675c262cbbcSToomas Soome 		if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
676760a3dc4SToomas Soome 		    entry->me_title) != 0) {
677c262cbbcSToomas Soome 			bam_error(_("out of memory\n"));
678c262cbbcSToomas Soome 			nvlist_free(be_attrs);
679c262cbbcSToomas Soome 			return (BAM_ERROR);
680c262cbbcSToomas Soome 		}
681c262cbbcSToomas Soome 		ret = be_activate(be_attrs);
682c262cbbcSToomas Soome 		nvlist_free(be_attrs);
683c262cbbcSToomas Soome 		if (ret != 0)
684c262cbbcSToomas Soome 			ret = BAM_ERROR;
685c262cbbcSToomas Soome 		return (ret);
686c262cbbcSToomas Soome 	} else if (strcmp(opt, "timeout") == 0) {
687c262cbbcSToomas Soome 		errno = 0;
688c262cbbcSToomas Soome 		optval = strtol(val, &rest, 10);
689c262cbbcSToomas Soome 		if (errno != 0 || *rest != '\0') {
690c262cbbcSToomas Soome 			bam_error(_("invalid timeout: %s\n"), val);
691c262cbbcSToomas Soome 			return (BAM_ERROR);
692c262cbbcSToomas Soome 		}
693c262cbbcSToomas Soome 
694c262cbbcSToomas Soome 		(void) snprintf(path, PATH_MAX, "%s" CONF_DIR "/timeout",
695c262cbbcSToomas Soome 		    bam_root);
696c262cbbcSToomas Soome 
697c262cbbcSToomas Soome 		fp = fopen(path, "w");
698c262cbbcSToomas Soome 		if (fp == NULL) {
699c262cbbcSToomas Soome 			bam_error(_("failed to open file: %s: %s\n"),
700c262cbbcSToomas Soome 			    path, strerror(errno));
701c262cbbcSToomas Soome 			return (BAM_ERROR);
702c262cbbcSToomas Soome 		}
703c262cbbcSToomas Soome 		/*
704c262cbbcSToomas Soome 		 * timeout=-1 is to disable auto boot in illumos, but
705c262cbbcSToomas Soome 		 * loader needs "NO" to disable auto boot.
706c262cbbcSToomas Soome 		 */
707c262cbbcSToomas Soome 		if (optval == -1)
708c262cbbcSToomas Soome 			rv = fprintf(fp, "autoboot_delay=\"NO\"\n");
709c262cbbcSToomas Soome 		else
710c262cbbcSToomas Soome 			rv = fprintf(fp, "autoboot_delay=\"%d\"\n", optval);
711c262cbbcSToomas Soome 
712c262cbbcSToomas Soome 		if (rv < 0) {
713c262cbbcSToomas Soome 			bam_error(_("write to file failed: %s: %s\n"),
714c262cbbcSToomas Soome 			    path, strerror(errno));
715c262cbbcSToomas Soome 			(void) fclose(fp);
716c262cbbcSToomas Soome 			ret = BAM_ERROR;
717c262cbbcSToomas Soome 		} else
718c262cbbcSToomas Soome 			rv = fclose(fp);
719c262cbbcSToomas Soome 
720c262cbbcSToomas Soome 		if (rv < 0) {
721c262cbbcSToomas Soome 			bam_error(_("failed to close file: %s: %s\n"),
722c262cbbcSToomas Soome 			    path, strerror(errno));
723c262cbbcSToomas Soome 			ret = BAM_ERROR;
724c262cbbcSToomas Soome 		}
725c262cbbcSToomas Soome 		if (ret == BAM_ERROR)
726c262cbbcSToomas Soome 			(void) unlink(path);
727c262cbbcSToomas Soome 
728c262cbbcSToomas Soome 		return (BAM_SUCCESS);
729c262cbbcSToomas Soome 	}
730c262cbbcSToomas Soome 
731c262cbbcSToomas Soome 	bam_error(_("invalid option: %s\n"), opt);
732c262cbbcSToomas Soome 	return (BAM_ERROR);
733c262cbbcSToomas Soome }
734c262cbbcSToomas Soome 
735c262cbbcSToomas Soome static int
bam_mount_be(menu_entry_t * entry,char ** dir)736760a3dc4SToomas Soome bam_mount_be(menu_entry_t *entry, char **dir)
737c262cbbcSToomas Soome {
738c262cbbcSToomas Soome 	nvlist_t *be_attrs = NULL;
739c262cbbcSToomas Soome 	const char *tmpdir = getenv("TMPDIR");
740c262cbbcSToomas Soome 	const char *tmpname = "bam.XXXXXX";
741c262cbbcSToomas Soome 	be_node_list_t *be_node, *be_nodes = NULL;
742c262cbbcSToomas Soome 	int ret;
743c262cbbcSToomas Soome 
744c262cbbcSToomas Soome 	*dir = NULL;
745c262cbbcSToomas Soome 	if (tmpdir == NULL)
746c262cbbcSToomas Soome 		tmpdir = "/tmp";
747c262cbbcSToomas Soome 
748c262cbbcSToomas Soome 	ret = asprintf(dir, "%s/%s", tmpdir, tmpname);
749c262cbbcSToomas Soome 	if (ret < 0) {
750c262cbbcSToomas Soome 		return (BE_ERR_NOMEM);
751c262cbbcSToomas Soome 	}
752c262cbbcSToomas Soome 	*dir = mkdtemp(*dir);
753c262cbbcSToomas Soome 
754c262cbbcSToomas Soome 	if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
755c262cbbcSToomas Soome 		ret = BE_ERR_NOMEM;
756c262cbbcSToomas Soome 		goto out;
757c262cbbcSToomas Soome 	}
758c262cbbcSToomas Soome 
759a897f28bSAndy Fiddaman 	ret = be_list(NULL, &be_nodes, BE_LIST_DEFAULT);
760c262cbbcSToomas Soome 	if (ret != BE_SUCCESS) {
761c262cbbcSToomas Soome 		goto out;
762c262cbbcSToomas Soome 	}
763c262cbbcSToomas Soome 
764c262cbbcSToomas Soome 	for (be_node = be_nodes; be_node;
765c262cbbcSToomas Soome 	    be_node = be_node->be_next_node)
766760a3dc4SToomas Soome 		if (strcmp(be_node->be_root_ds, entry->me_bootfs) == 0)
767c262cbbcSToomas Soome 			break;
768c262cbbcSToomas Soome 
769*d094b9b6SToomas Soome 	if (be_node == NULL) {
770*d094b9b6SToomas Soome 		ret = BE_ERR_BE_NOENT;
771*d094b9b6SToomas Soome 		goto out;
772*d094b9b6SToomas Soome 	}
773*d094b9b6SToomas Soome 
774c262cbbcSToomas Soome 	if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
775c262cbbcSToomas Soome 	    be_node->be_node_name) != 0) {
776c262cbbcSToomas Soome 		ret = BE_ERR_NOMEM;
777c262cbbcSToomas Soome 		goto out;
778c262cbbcSToomas Soome 	}
779c262cbbcSToomas Soome 
780c262cbbcSToomas Soome 	if (nvlist_add_string(be_attrs, BE_ATTR_MOUNTPOINT, *dir) != 0) {
781c262cbbcSToomas Soome 		ret = BE_ERR_NOMEM;
782c262cbbcSToomas Soome 		goto out;
783c262cbbcSToomas Soome 	}
784c262cbbcSToomas Soome 
785c262cbbcSToomas Soome 	ret = be_mount(be_attrs);
786c262cbbcSToomas Soome 	if (ret == BE_ERR_MOUNTED) {
787c262cbbcSToomas Soome 		/*
788c262cbbcSToomas Soome 		 * if BE is mounted, dir does not point to correct directory
789c262cbbcSToomas Soome 		 */
790c262cbbcSToomas Soome 		(void) rmdir(*dir);
791c262cbbcSToomas Soome 		free(*dir);
792c262cbbcSToomas Soome 		*dir = NULL;
793c262cbbcSToomas Soome 	}
794c262cbbcSToomas Soome out:
795c262cbbcSToomas Soome 	if (be_nodes != NULL)
796c262cbbcSToomas Soome 		be_free_list(be_nodes);
797c262cbbcSToomas Soome 	nvlist_free(be_attrs);
798c262cbbcSToomas Soome 	return (ret);
799c262cbbcSToomas Soome }
800c262cbbcSToomas Soome 
801c262cbbcSToomas Soome static int
bam_umount_be(char * dir)802c262cbbcSToomas Soome bam_umount_be(char *dir)
803c262cbbcSToomas Soome {
804c262cbbcSToomas Soome 	nvlist_t *be_attrs;
805c262cbbcSToomas Soome 	int ret;
806c262cbbcSToomas Soome 
807c262cbbcSToomas Soome 	if (dir == NULL)		/* nothing to do */
808c262cbbcSToomas Soome 		return (BE_SUCCESS);
809c262cbbcSToomas Soome 
810c262cbbcSToomas Soome 	if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0)
811c262cbbcSToomas Soome 		return (BE_ERR_NOMEM);
812c262cbbcSToomas Soome 
813c262cbbcSToomas Soome 	if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, dir) != 0) {
814c262cbbcSToomas Soome 		ret = BE_ERR_NOMEM;
815c262cbbcSToomas Soome 		goto out;
816c262cbbcSToomas Soome 	}
817c262cbbcSToomas Soome 
818c262cbbcSToomas Soome 	ret = be_unmount(be_attrs);
819c262cbbcSToomas Soome out:
820c262cbbcSToomas Soome 	nvlist_free(be_attrs);
821c262cbbcSToomas Soome 	return (ret);
822c262cbbcSToomas Soome }
823c262cbbcSToomas Soome 
824c262cbbcSToomas Soome /*
825c262cbbcSToomas Soome  * display details of menu entry or single property
826c262cbbcSToomas Soome  */
827c262cbbcSToomas Soome static error_t
list_menu_entry(menu_entry_t * entry,char * setting)828760a3dc4SToomas Soome list_menu_entry(menu_entry_t *entry, char *setting)
829c262cbbcSToomas Soome {
830c262cbbcSToomas Soome 	int ret = BAM_SUCCESS;
831c262cbbcSToomas Soome 	char *ptr, *dir;
832c262cbbcSToomas Soome 	char buf[MAX_INPUT];
833c262cbbcSToomas Soome 	ficlVm *vm;
834c262cbbcSToomas Soome 	int mounted;
835c262cbbcSToomas Soome 
836160df579SToomas Soome 	ptr = strrchr(entry->me_bootfs, ':');
837760a3dc4SToomas Soome 	if (strcmp(entry->me_type, "bootfs") != 0 ||
838160df579SToomas Soome 	    (ptr != NULL && ptr[1] == '\0')) {
839760a3dc4SToomas Soome 		(void) printf("\nTitle:       %s\n", entry->me_title);
840760a3dc4SToomas Soome 		(void) printf("Type:        %s\n", entry->me_type);
841760a3dc4SToomas Soome 		(void) printf("Device:      %s\n", entry->me_bootfs);
842760a3dc4SToomas Soome 		return (ret);
843760a3dc4SToomas Soome 	}
844760a3dc4SToomas Soome 
845c262cbbcSToomas Soome 	mounted = bam_mount_be(entry, &dir);
846c262cbbcSToomas Soome 	if (mounted != BE_SUCCESS && mounted != BE_ERR_MOUNTED) {
847c262cbbcSToomas Soome 		if (dir != NULL) {
848c262cbbcSToomas Soome 			(void) rmdir(dir);
849c262cbbcSToomas Soome 			free(dir);
850c262cbbcSToomas Soome 		}
851*d094b9b6SToomas Soome 		bam_error(_("%s is not mounted: %s\n"), entry->me_title,
852*d094b9b6SToomas Soome 		    be_err_to_str(mounted));
853c262cbbcSToomas Soome 		return (BAM_ERROR);
854c262cbbcSToomas Soome 	}
855c262cbbcSToomas Soome 
856c262cbbcSToomas Soome 	vm = bf_init("", ficlTextOutSilent);
857c262cbbcSToomas Soome 	if (vm == NULL) {
858c262cbbcSToomas Soome 		bam_error(_("error setting up forth interpreter\n"));
859c262cbbcSToomas Soome 		ret = BAM_ERROR;
860c262cbbcSToomas Soome 		goto done;
861c262cbbcSToomas Soome 	}
862c262cbbcSToomas Soome 
863c262cbbcSToomas Soome 	/* should only get FICL_VM_STATUS_OUT_OF_TEXT */
864c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:",
865760a3dc4SToomas Soome 	    entry->me_bootfs);
866c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
867c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
868c262cbbcSToomas Soome 		bam_error(_("error interpreting boot config\n"));
869c262cbbcSToomas Soome 		ret = BAM_ERROR;
870c262cbbcSToomas Soome 		goto done;
871c262cbbcSToomas Soome 	}
872c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
873c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
874c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
875c262cbbcSToomas Soome 		bam_error(_("error interpreting boot config\n"));
876c262cbbcSToomas Soome 		ret = BAM_ERROR;
877c262cbbcSToomas Soome 		goto done;
878c262cbbcSToomas Soome 	}
879c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "start");
880c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
881c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
882c262cbbcSToomas Soome 		bam_error(_("error interpreting boot config\n"));
883c262cbbcSToomas Soome 		ret = BAM_ERROR;
884c262cbbcSToomas Soome 		goto done;
885c262cbbcSToomas Soome 	}
886c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "boot");
887c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
888c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
889c262cbbcSToomas Soome 		bam_error(_("error interpreting boot config\n"));
890c262cbbcSToomas Soome 		ret = BAM_ERROR;
891c262cbbcSToomas Soome 		goto done;
892c262cbbcSToomas Soome 	}
893c262cbbcSToomas Soome 
894c262cbbcSToomas Soome 	ret = BAM_SUCCESS;
895c262cbbcSToomas Soome 	if (*setting == '\0')
896760a3dc4SToomas Soome 		(void) printf("\nTitle:       %s\n", entry->me_title);
897c262cbbcSToomas Soome 	else if (strcasecmp(setting, "title") == 0) {
898760a3dc4SToomas Soome 		(void) printf("%s\n", entry->me_title);
899c262cbbcSToomas Soome 		goto done;
900c262cbbcSToomas Soome 	}
901c262cbbcSToomas Soome 
902c262cbbcSToomas Soome 	ptr = getenv("autoboot_delay");
903c262cbbcSToomas Soome 	if (ptr != NULL) {
904c262cbbcSToomas Soome 		char *timeout = "-1";
905c262cbbcSToomas Soome 
906c262cbbcSToomas Soome 		if (strcasecmp(ptr, "NO") != 0)
907c262cbbcSToomas Soome 			timeout = ptr;
908c262cbbcSToomas Soome 
909c262cbbcSToomas Soome 		if (*setting == '\0')
910c262cbbcSToomas Soome 			(void) printf("Timeout:     %s\n", timeout);
911c262cbbcSToomas Soome 		else if (strcasecmp(setting, "timeout") == 0) {
912c262cbbcSToomas Soome 			(void) printf("%s\n", timeout);
913c262cbbcSToomas Soome 			goto done;
914c262cbbcSToomas Soome 		}
915c262cbbcSToomas Soome 
916c262cbbcSToomas Soome 	}
917c262cbbcSToomas Soome 	ptr = getenv("console");
918c262cbbcSToomas Soome 	if (ptr != NULL) {
919c262cbbcSToomas Soome 		if (*setting == '\0')
920c262cbbcSToomas Soome 			(void) printf("Console:     %s\n", ptr);
921c262cbbcSToomas Soome 		else if (strcasecmp(setting, "console") == 0) {
922c262cbbcSToomas Soome 			(void) printf("%s\n", ptr);
923c262cbbcSToomas Soome 			goto done;
924c262cbbcSToomas Soome 		}
925c262cbbcSToomas Soome 	}
926c262cbbcSToomas Soome 
927c262cbbcSToomas Soome 	if (*setting == '\0')
928760a3dc4SToomas Soome 		(void) printf("Bootfs:      %s\n", entry->me_bootfs);
929c262cbbcSToomas Soome 	else if (strcasecmp(setting, "bootfs") == 0) {
930760a3dc4SToomas Soome 		(void) printf("%s\n", entry->me_bootfs);
931c262cbbcSToomas Soome 		goto done;
932c262cbbcSToomas Soome 	}
933c262cbbcSToomas Soome 
934c262cbbcSToomas Soome 	ptr = getenv("xen_kernel");
935c262cbbcSToomas Soome 	if (ptr != NULL) {
936c262cbbcSToomas Soome 			if (*setting == '\0') {
937c262cbbcSToomas Soome 				(void) printf("Xen kernel:  %s\n", ptr);
938c262cbbcSToomas Soome 			} else if (strcasecmp(setting, "xen_kernel") == 0) {
939c262cbbcSToomas Soome 				(void) printf("%s\n", ptr);
940c262cbbcSToomas Soome 				goto done;
941c262cbbcSToomas Soome 			}
942c262cbbcSToomas Soome 
943c262cbbcSToomas Soome 			if (*setting == '\0') {
944c262cbbcSToomas Soome 				(void) printf("Xen args:    \"%s\"\n",
945c262cbbcSToomas Soome 				    getenv("xen_cmdline"));
946c262cbbcSToomas Soome 			} else if (strcasecmp(setting, "xen_cmdline") == 0) {
947c262cbbcSToomas Soome 				(void) printf("%s\n", getenv("xen_cmdline"));
948c262cbbcSToomas Soome 				goto done;
949c262cbbcSToomas Soome 			}
950c262cbbcSToomas Soome 
951c262cbbcSToomas Soome 			if (*setting == '\0') {
952c262cbbcSToomas Soome 				(void) printf("Kernel:      %s\n",
953c262cbbcSToomas Soome 				    getenv("bootfile"));
9549dded1d9SToomas Soome 			} else if (strcasecmp(setting, "kernel") == 0) {
955c262cbbcSToomas Soome 				(void) printf("%s\n", getenv("bootfile"));
956c262cbbcSToomas Soome 				goto done;
957c262cbbcSToomas Soome 			}
958c262cbbcSToomas Soome 	} else {
959c262cbbcSToomas Soome 		ptr = getenv("kernelname");
960c262cbbcSToomas Soome 		if (ptr != NULL) {
961c262cbbcSToomas Soome 			if (*setting == '\0') {
962c262cbbcSToomas Soome 				(void) printf("Kernel:      %s\n", ptr);
963c262cbbcSToomas Soome 			} else if (strcasecmp(setting, "kernel") == 0) {
964c262cbbcSToomas Soome 				(void) printf("%s\n", ptr);
965c262cbbcSToomas Soome 				goto done;
966c262cbbcSToomas Soome 			}
967c262cbbcSToomas Soome 		}
968c262cbbcSToomas Soome 	}
969c262cbbcSToomas Soome 
970c262cbbcSToomas Soome 	ptr = getenv("boot-args");
971c262cbbcSToomas Soome 	if (ptr != NULL) {
972c262cbbcSToomas Soome 		if (*setting == '\0') {
973c262cbbcSToomas Soome 			(void) printf("Boot-args:   \"%s\"\n", ptr);
974c262cbbcSToomas Soome 		} else if (strcasecmp(setting, "boot-args") == 0) {
975c262cbbcSToomas Soome 			(void) printf("%s\n", ptr);
976c262cbbcSToomas Soome 			goto done;
977c262cbbcSToomas Soome 		}
978c262cbbcSToomas Soome 	}
979c262cbbcSToomas Soome 
980c262cbbcSToomas Soome 	if (*setting == '\0' || strcasecmp(setting, "modules") == 0) {
981c262cbbcSToomas Soome 		(void) printf("\nModules:\n");
982c262cbbcSToomas Soome 		ficlVmSetTextOut(vm, ficlCallbackDefaultTextOut);
983c262cbbcSToomas Soome 		(void) snprintf(buf, MAX_INPUT, "show-module-options");
984c262cbbcSToomas Soome 		ret = ficlVmEvaluate(vm, buf);
985c262cbbcSToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
986c262cbbcSToomas Soome 			bam_error(_("error interpreting boot config\n"));
987c262cbbcSToomas Soome 			ret = BAM_ERROR;
988c262cbbcSToomas Soome 			goto done;
989c262cbbcSToomas Soome 		}
990c262cbbcSToomas Soome 		ret = BAM_SUCCESS;
991c262cbbcSToomas Soome 		goto done;
992c262cbbcSToomas Soome 	}
993c262cbbcSToomas Soome 
994c262cbbcSToomas Soome 	/* if we got here with setting string, its unknown property */
995c262cbbcSToomas Soome 	if (*setting != '\0') {
996c262cbbcSToomas Soome 		bam_error(_("unknown property: %s\n"), setting);
997c262cbbcSToomas Soome 		ret = BAM_ERROR;
998c262cbbcSToomas Soome 	} else
999c262cbbcSToomas Soome 		ret = BAM_SUCCESS;
1000c262cbbcSToomas Soome done:
1001c262cbbcSToomas Soome 	bf_fini();
1002c262cbbcSToomas Soome 	if (mounted != BE_ERR_MOUNTED) {
1003c262cbbcSToomas Soome 		(void) bam_umount_be(dir);
1004c262cbbcSToomas Soome 	}
1005c262cbbcSToomas Soome 
1006c262cbbcSToomas Soome 	if (dir != NULL) {
1007c262cbbcSToomas Soome 		(void) rmdir(dir);
1008c262cbbcSToomas Soome 		free(dir);
1009c262cbbcSToomas Soome 	}
1010c262cbbcSToomas Soome 
1011c262cbbcSToomas Soome 	return (ret);
1012c262cbbcSToomas Soome }
1013c262cbbcSToomas Soome 
1014c262cbbcSToomas Soome /*ARGSUSED*/
1015c262cbbcSToomas Soome static error_t
list_entry(struct menu_lst * menu,char * menu_root,char * opt)1016c262cbbcSToomas Soome list_entry(struct menu_lst *menu, char *menu_root, char *opt)
1017c262cbbcSToomas Soome {
1018c262cbbcSToomas Soome 	error_t ret = BAM_SUCCESS;
1019760a3dc4SToomas Soome 	menu_entry_t *entry;
1020c262cbbcSToomas Soome 	char *ptr, *title = NULL;
1021c262cbbcSToomas Soome 	int i, e = -1;
1022c262cbbcSToomas Soome 
1023c262cbbcSToomas Soome 	if (opt == NULL) {
1024c262cbbcSToomas Soome 		print_nodes(B_FALSE, menu);
1025c262cbbcSToomas Soome 		return (ret);
1026c262cbbcSToomas Soome 	}
1027c262cbbcSToomas Soome 
1028c262cbbcSToomas Soome 	if ((ptr = strchr(opt, '=')) == NULL) {
1029c262cbbcSToomas Soome 		bam_error(_("invalid option: %s\n"), opt);
1030c262cbbcSToomas Soome 		return (BAM_ERROR);
1031c262cbbcSToomas Soome 	}
1032c262cbbcSToomas Soome 
1033c262cbbcSToomas Soome 	i = ptr - opt;
1034c262cbbcSToomas Soome 	if (strncmp(opt, "entry", i) == 0) {
1035c262cbbcSToomas Soome 		e = atoi(ptr+1);
1036c262cbbcSToomas Soome 	} else if (strncmp(opt, "title", i) == 0) {
1037c262cbbcSToomas Soome 		title = ptr+1;
1038c262cbbcSToomas Soome 	} else {
1039c262cbbcSToomas Soome 		bam_error(_("invalid option: %s\n"), opt);
1040c262cbbcSToomas Soome 		return (BAM_ERROR);
1041c262cbbcSToomas Soome 	}
1042c262cbbcSToomas Soome 
1043760a3dc4SToomas Soome 	STAILQ_FOREACH(entry, menu, me_next) {
1044c262cbbcSToomas Soome 		if (title != NULL) {
1045760a3dc4SToomas Soome 			if (strcmp(title, entry->me_title) == 0)
1046c262cbbcSToomas Soome 				break;
1047760a3dc4SToomas Soome 		} else if (entry->me_idx == e)
1048c262cbbcSToomas Soome 			break;
1049c262cbbcSToomas Soome 	}
1050c262cbbcSToomas Soome 
1051c262cbbcSToomas Soome 	if (entry == NULL) {
1052c262cbbcSToomas Soome 		bam_error(_("no matching entry found\n"));
1053c262cbbcSToomas Soome 		return (BAM_ERROR);
1054c262cbbcSToomas Soome 	}
1055c262cbbcSToomas Soome 
1056c262cbbcSToomas Soome 	return (list_menu_entry(entry, ""));
1057c262cbbcSToomas Soome }
1058c262cbbcSToomas Soome 
1059c262cbbcSToomas Soome /*
1060c262cbbcSToomas Soome  * For now this is just stub entry to support grub interface, the
1061c262cbbcSToomas Soome  * known consumer is installer ict.py code, calling as:
1062c262cbbcSToomas Soome  * bootadm update-menu -R /a -Z -o rdisk
1063c262cbbcSToomas Soome  * Later this can be converted to do something useful.
1064c262cbbcSToomas Soome  */
1065c262cbbcSToomas Soome /*ARGSUSED*/
1066c262cbbcSToomas Soome static error_t
update_entry(struct menu_lst * menu,char * menu_root,char * osdev)1067c262cbbcSToomas Soome update_entry(struct menu_lst *menu, char *menu_root, char *osdev)
1068c262cbbcSToomas Soome {
1069c262cbbcSToomas Soome 	char path[PATH_MAX];
1070c262cbbcSToomas Soome 	char *pool = menu_root + 1;
1071c262cbbcSToomas Soome 	be_node_list_t *be_nodes, *be_node;
1072c262cbbcSToomas Soome 	int rv;
1073c262cbbcSToomas Soome 	FILE *fp;
1074c262cbbcSToomas Soome 
1075c262cbbcSToomas Soome 	(void) snprintf(path, PATH_MAX, "%s%s", menu_root, MENU);
1076a897f28bSAndy Fiddaman 	rv = be_list(NULL, &be_nodes, BE_LIST_DEFAULT);
1077c262cbbcSToomas Soome 
1078c262cbbcSToomas Soome 	if (rv != BE_SUCCESS)
1079c262cbbcSToomas Soome 		return (BAM_ERROR);
1080c262cbbcSToomas Soome 
1081c262cbbcSToomas Soome 	fp = fopen(path, "w");
1082c262cbbcSToomas Soome 	if (fp == NULL) {
1083c262cbbcSToomas Soome 		be_free_list(be_nodes);
1084c262cbbcSToomas Soome 		return (BAM_ERROR);
1085c262cbbcSToomas Soome 	}
1086c262cbbcSToomas Soome 
1087c262cbbcSToomas Soome 	for (be_node = be_nodes; be_node; be_node = be_node->be_next_node) {
1088c262cbbcSToomas Soome 		if (strcmp(be_node->be_rpool, pool) == 0) {
1089c262cbbcSToomas Soome 			(void) fprintf(fp, "title %s\n", be_node->be_node_name);
1090c262cbbcSToomas Soome 			(void) fprintf(fp, "bootfs %s\n", be_node->be_root_ds);
1091c262cbbcSToomas Soome 		}
1092c262cbbcSToomas Soome 	}
1093c262cbbcSToomas Soome 
1094c262cbbcSToomas Soome 	be_free_list(be_nodes);
1095c262cbbcSToomas Soome 	(void) fclose(fp);
1096c262cbbcSToomas Soome 	return (BAM_SUCCESS);
1097c262cbbcSToomas Soome }
1098c262cbbcSToomas Soome 
1099c262cbbcSToomas Soome /*ARGSUSED*/
1100c262cbbcSToomas Soome static error_t
update_temp(struct menu_lst * menu,char * dummy,char * opt)1101c262cbbcSToomas Soome update_temp(struct menu_lst *menu, char *dummy, char *opt)
1102c262cbbcSToomas Soome {
1103c262cbbcSToomas Soome 	error_t ret = BAM_ERROR;
1104c262cbbcSToomas Soome 	char path[PATH_MAX];
1105c262cbbcSToomas Soome 	char buf[MAX_INPUT];
1106c262cbbcSToomas Soome 	struct mnttab mpref = { 0 };
1107c262cbbcSToomas Soome 	struct mnttab mp = { 0 };
1108c262cbbcSToomas Soome 	ficlVm *vm;
1109c262cbbcSToomas Soome 	char *env, *o;
1110c262cbbcSToomas Soome 	FILE *fp;
1111c262cbbcSToomas Soome 
1112c262cbbcSToomas Soome 	(void) snprintf(path, PATH_MAX, "%s" TRANSIENT, bam_root);
1113c262cbbcSToomas Soome 	/*
1114c262cbbcSToomas Soome 	 * if opt == NULL, remove transient config
1115c262cbbcSToomas Soome 	 */
1116c262cbbcSToomas Soome 	if (opt == NULL) {
1117c262cbbcSToomas Soome 		(void) unlink(path);
1118c262cbbcSToomas Soome 		return (BAM_SUCCESS);
1119c262cbbcSToomas Soome 	}
1120c262cbbcSToomas Soome 
1121c262cbbcSToomas Soome 	fp = fopen(MNTTAB, "r");
1122c262cbbcSToomas Soome 	if (fp == NULL)
1123c262cbbcSToomas Soome 		return (BAM_ERROR);
1124c262cbbcSToomas Soome 
1125c262cbbcSToomas Soome 	mpref.mnt_mountp = "/";
1126c262cbbcSToomas Soome 	if (getmntany(fp, &mp, &mpref) != 0) {
1127c262cbbcSToomas Soome 		(void) fclose(fp);
1128c262cbbcSToomas Soome 		return (BAM_ERROR);
1129c262cbbcSToomas Soome 	}
1130c262cbbcSToomas Soome 	(void) fclose(fp);
1131c262cbbcSToomas Soome 
1132c262cbbcSToomas Soome 	vm = bf_init("", ficlTextOutSilent);
1133c262cbbcSToomas Soome 	if (vm == NULL) {
1134c262cbbcSToomas Soome 		bam_error(_("Error setting up forth interpreter\n"));
1135c262cbbcSToomas Soome 		return (ret);
1136c262cbbcSToomas Soome 	}
1137c262cbbcSToomas Soome 
1138c262cbbcSToomas Soome 	/*
1139c262cbbcSToomas Soome 	 * need to check current boot config, so fire up the ficl
1140c262cbbcSToomas Soome 	 * if its xen setup, we add option to boot-args list, not replacing it.
1141c262cbbcSToomas Soome 	 */
1142c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:", mp.mnt_special);
1143c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1144c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1145c262cbbcSToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1146c262cbbcSToomas Soome 		bf_fini();
1147c262cbbcSToomas Soome 		return (BAM_ERROR);
1148c262cbbcSToomas Soome 	}
1149c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
1150c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1151c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1152c262cbbcSToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1153c262cbbcSToomas Soome 		bf_fini();
1154c262cbbcSToomas Soome 		return (BAM_ERROR);
1155c262cbbcSToomas Soome 	}
1156c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "start");
1157c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1158c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1159c262cbbcSToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1160c262cbbcSToomas Soome 		bf_fini();
1161c262cbbcSToomas Soome 		return (BAM_ERROR);
1162c262cbbcSToomas Soome 	}
1163c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "boot");
1164c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1165c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1166c262cbbcSToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1167c262cbbcSToomas Soome 		bf_fini();
1168c262cbbcSToomas Soome 		return (BAM_ERROR);
1169c262cbbcSToomas Soome 	}
1170c262cbbcSToomas Soome 	bf_fini();
1171c262cbbcSToomas Soome 
1172c262cbbcSToomas Soome 	if (opt[0] == '-') {
1173c262cbbcSToomas Soome 		env = getenv("xen_kernel");
1174c262cbbcSToomas Soome 		fp = fopen(path, "w");
1175c262cbbcSToomas Soome 		if (fp == NULL)
1176c262cbbcSToomas Soome 			return (BAM_ERROR);
1177c262cbbcSToomas Soome 
1178c262cbbcSToomas Soome 		if (env != NULL) {
1179c262cbbcSToomas Soome 			env = getenv("boot-args");
1180e39d8488SAndy Fiddaman 			(void) fprintf(fp, "boot-args='%s %s'\n", env, opt);
1181c262cbbcSToomas Soome 		} else
1182e39d8488SAndy Fiddaman 			(void) fprintf(fp, "boot-args='%s'\n", opt);
1183c262cbbcSToomas Soome 		(void) fclose(fp);
1184c262cbbcSToomas Soome 		return (BAM_SUCCESS);
1185c262cbbcSToomas Soome 	}
1186c262cbbcSToomas Soome 
1187c262cbbcSToomas Soome 	/*
1188c262cbbcSToomas Soome 	 * it should be the case with "kernel args"
1189c262cbbcSToomas Soome 	 * so, we split the opt at first space
1190c262cbbcSToomas Soome 	 * and store bootfile= and boot-args=
1191c262cbbcSToomas Soome 	 */
1192c262cbbcSToomas Soome 	env = getenv("xen_kernel");
1193c262cbbcSToomas Soome 
1194c262cbbcSToomas Soome 	o = strchr(opt, ' ');
1195c262cbbcSToomas Soome 	if (o == NULL) {
1196c262cbbcSToomas Soome 		fp = fopen(path, "w");
1197c262cbbcSToomas Soome 		if (fp == NULL)
1198c262cbbcSToomas Soome 			return (BAM_ERROR);
1199e39d8488SAndy Fiddaman 		(void) fprintf(fp, "bootfile='%s;unix'\n", opt);
1200c262cbbcSToomas Soome 		(void) fclose(fp);
1201c262cbbcSToomas Soome 		return (BAM_SUCCESS);
1202c262cbbcSToomas Soome 	}
1203c262cbbcSToomas Soome 	*o++ = '\0';
1204c262cbbcSToomas Soome 	fp = fopen(path, "w");
1205c262cbbcSToomas Soome 	if (fp == NULL)
1206c262cbbcSToomas Soome 		return (BAM_ERROR);
1207e39d8488SAndy Fiddaman 	(void) fprintf(fp, "bootfile='%s;unix'\n", opt);
1208c262cbbcSToomas Soome 
1209c262cbbcSToomas Soome 	if (env != NULL) {
1210c262cbbcSToomas Soome 		env = getenv("boot-args");
1211e39d8488SAndy Fiddaman 		(void) fprintf(fp, "boot-args='%s %s'\n", env, o);
1212c262cbbcSToomas Soome 	} else
1213e39d8488SAndy Fiddaman 		(void) fprintf(fp, "boot-args='%s'\n", o);
1214c262cbbcSToomas Soome 
1215c262cbbcSToomas Soome 	(void) fflush(fp);
1216c262cbbcSToomas Soome 	(void) fclose(fp);
1217c262cbbcSToomas Soome 	return (ret);
1218c262cbbcSToomas Soome }
1219c262cbbcSToomas Soome 
1220c262cbbcSToomas Soome static error_t
list_setting(struct menu_lst * menu,char * which,char * setting)1221c262cbbcSToomas Soome list_setting(struct menu_lst *menu, char *which, char *setting)
1222c262cbbcSToomas Soome {
1223c262cbbcSToomas Soome 	int entry = -1;
1224760a3dc4SToomas Soome 	menu_entry_t *m;
1225c262cbbcSToomas Soome 	be_node_list_t *be_nodes, *be_node = NULL;
1226c262cbbcSToomas Soome 	int ret;
1227c262cbbcSToomas Soome 
1228c262cbbcSToomas Soome 	assert(which);
1229c262cbbcSToomas Soome 	assert(setting);
1230c262cbbcSToomas Soome 
1231c262cbbcSToomas Soome 	/*
1232c262cbbcSToomas Soome 	 * which can be:
1233c262cbbcSToomas Soome 	 * "" - list default entry
1234c262cbbcSToomas Soome 	 * number - use for entry number
1235c262cbbcSToomas Soome 	 * property name
1236c262cbbcSToomas Soome 	 */
1237c262cbbcSToomas Soome 	if (*which != '\0') {
1238c262cbbcSToomas Soome 		if (isdigit(*which)) {
1239c262cbbcSToomas Soome 			char *rest;
1240c262cbbcSToomas Soome 			errno = 0;
1241c262cbbcSToomas Soome 			entry = strtol(which, &rest, 10);
1242c262cbbcSToomas Soome 			if (errno != 0 || *rest != '\0') {
1243c262cbbcSToomas Soome 				bam_error(_("invalid boot entry number: %s\n"),
1244c262cbbcSToomas Soome 				    which);
1245c262cbbcSToomas Soome 				return (BAM_ERROR);
1246c262cbbcSToomas Soome 			}
1247c262cbbcSToomas Soome 		} else
1248c262cbbcSToomas Soome 			setting = which;
1249c262cbbcSToomas Soome 	}
1250c262cbbcSToomas Soome 
1251c262cbbcSToomas Soome 	/* find default entry */
1252c262cbbcSToomas Soome 	if (entry == -1) {
1253a897f28bSAndy Fiddaman 		ret = be_list(NULL, &be_nodes, BE_LIST_DEFAULT);
1254c262cbbcSToomas Soome 		if (ret != BE_SUCCESS) {
1255c262cbbcSToomas Soome 			bam_error(_("No BE's found\n"));
1256c262cbbcSToomas Soome 			return (BAM_ERROR);
1257c262cbbcSToomas Soome 		}
1258760a3dc4SToomas Soome 		STAILQ_FOREACH(m, menu, me_next) {
1259c262cbbcSToomas Soome 			entry++;
1260c262cbbcSToomas Soome 			for (be_node = be_nodes; be_node;
1261760a3dc4SToomas Soome 			    be_node = be_node->be_next_node) {
1262760a3dc4SToomas Soome 				if (strcmp(be_node->be_root_ds,
1263760a3dc4SToomas Soome 				    m->me_bootfs) == 0)
1264c262cbbcSToomas Soome 					break;
1265760a3dc4SToomas Soome 			}
1266760a3dc4SToomas Soome 			if (be_node != NULL &&
1267760a3dc4SToomas Soome 			    be_node->be_active_on_boot == B_TRUE)
1268c262cbbcSToomas Soome 				break; /* found active node */
1269c262cbbcSToomas Soome 		}
1270c262cbbcSToomas Soome 		be_free_list(be_nodes);
1271c262cbbcSToomas Soome 		if (be_node == NULL) {
1272c262cbbcSToomas Soome 			bam_error(_("None of BE nodes is marked active\n"));
1273c262cbbcSToomas Soome 			return (BAM_ERROR);
1274c262cbbcSToomas Soome 		}
1275c262cbbcSToomas Soome 	} else {
1276760a3dc4SToomas Soome 		STAILQ_FOREACH(m, menu, me_next)
1277760a3dc4SToomas Soome 			if (m->me_idx == entry)
1278c262cbbcSToomas Soome 				break;
1279c262cbbcSToomas Soome 
1280c262cbbcSToomas Soome 		if (m == NULL) {
1281c262cbbcSToomas Soome 			bam_error(_("no matching entry found\n"));
1282c262cbbcSToomas Soome 			return (BAM_ERROR);
1283c262cbbcSToomas Soome 		}
1284c262cbbcSToomas Soome 	}
1285c262cbbcSToomas Soome 
1286c262cbbcSToomas Soome 	return (list_menu_entry(m, setting));
1287c262cbbcSToomas Soome }
1288c262cbbcSToomas Soome 
1289c262cbbcSToomas Soome /*ARGSUSED*/
1290c262cbbcSToomas Soome static error_t
disable_hyper(struct menu_lst * menu,char * osroot,char * opt)1291c262cbbcSToomas Soome disable_hyper(struct menu_lst *menu, char *osroot, char *opt)
1292c262cbbcSToomas Soome {
1293c262cbbcSToomas Soome 	char path[PATH_MAX];
1294c262cbbcSToomas Soome 
1295c262cbbcSToomas Soome 	(void) snprintf(path, PATH_MAX, "%s" XEN_CONFIG, bam_root);
1296c262cbbcSToomas Soome 	(void) unlink(path);
1297c262cbbcSToomas Soome 	return (BAM_SUCCESS);
1298c262cbbcSToomas Soome }
1299c262cbbcSToomas Soome 
1300c262cbbcSToomas Soome /*ARGSUSED*/
1301c262cbbcSToomas Soome static error_t
enable_hyper(struct menu_lst * menu,char * osroot,char * opt)1302c262cbbcSToomas Soome enable_hyper(struct menu_lst *menu, char *osroot, char *opt)
1303c262cbbcSToomas Soome {
1304c262cbbcSToomas Soome 	ficlVm *vm;
1305c262cbbcSToomas Soome 	char path[PATH_MAX];
1306c262cbbcSToomas Soome 	char buf[MAX_INPUT];
1307c262cbbcSToomas Soome 	char *env;
1308c262cbbcSToomas Soome 	FILE *fp;
1309c262cbbcSToomas Soome 	struct mnttab mpref = { 0 };
1310c262cbbcSToomas Soome 	struct mnttab mp = { 0 };
1311c262cbbcSToomas Soome 	int ret;
1312c262cbbcSToomas Soome 
1313c262cbbcSToomas Soome 	fp = fopen(MNTTAB, "r");
1314c262cbbcSToomas Soome 	if (fp == NULL)
1315c262cbbcSToomas Soome 		return (BAM_ERROR);
1316c262cbbcSToomas Soome 
1317c262cbbcSToomas Soome 	mpref.mnt_mountp = "/";
1318c262cbbcSToomas Soome 	if (getmntany(fp, &mp, &mpref) != 0) {
1319c262cbbcSToomas Soome 		(void) fclose(fp);
1320c262cbbcSToomas Soome 		return (BAM_ERROR);
1321c262cbbcSToomas Soome 	}
1322c262cbbcSToomas Soome 	(void) fclose(fp);
1323c262cbbcSToomas Soome 
1324c262cbbcSToomas Soome 	vm = bf_init("", ficlTextOutSilent);
1325c262cbbcSToomas Soome 	if (vm == NULL) {
1326c262cbbcSToomas Soome 		bam_error(_("Error setting up forth interpreter\n"));
1327c262cbbcSToomas Soome 		return (BAM_ERROR);
1328c262cbbcSToomas Soome 	}
1329c262cbbcSToomas Soome 
1330c262cbbcSToomas Soome 	/*
1331c262cbbcSToomas Soome 	 * need to check current boot config, so fire up the ficl
1332c262cbbcSToomas Soome 	 * if its xen setup, we add option to boot-args list, not replacing it.
1333c262cbbcSToomas Soome 	 */
1334c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:", mp.mnt_special);
1335c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1336c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1337c262cbbcSToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1338c262cbbcSToomas Soome 		bf_fini();
1339c262cbbcSToomas Soome 		return (BAM_ERROR);
1340c262cbbcSToomas Soome 	}
1341c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
1342c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1343c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1344c262cbbcSToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1345c262cbbcSToomas Soome 		bf_fini();
1346c262cbbcSToomas Soome 		return (BAM_ERROR);
1347c262cbbcSToomas Soome 	}
1348c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "start");
1349c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1350c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1351c262cbbcSToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1352c262cbbcSToomas Soome 		bf_fini();
1353c262cbbcSToomas Soome 		return (BAM_ERROR);
1354c262cbbcSToomas Soome 	}
1355c262cbbcSToomas Soome 	(void) snprintf(buf, MAX_INPUT, "boot");
1356c262cbbcSToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1357c262cbbcSToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1358c262cbbcSToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1359c262cbbcSToomas Soome 		bf_fini();
1360c262cbbcSToomas Soome 		return (BAM_ERROR);
1361c262cbbcSToomas Soome 	}
1362c262cbbcSToomas Soome 	bf_fini();
1363c262cbbcSToomas Soome 
1364c262cbbcSToomas Soome 	(void) mkdir(CONF_DIR, 0755);
1365c262cbbcSToomas Soome 	(void) snprintf(path, PATH_MAX, "%s" XEN_CONFIG, bam_root);
1366c262cbbcSToomas Soome 	fp = fopen(path, "w");
1367c262cbbcSToomas Soome 	if (fp == NULL) {
1368c262cbbcSToomas Soome 		return (BAM_ERROR);	/* error, cant write config */
1369c262cbbcSToomas Soome 	}
1370c262cbbcSToomas Soome 
1371c262cbbcSToomas Soome 	errno = 0;
1372c262cbbcSToomas Soome 	/*
1373c262cbbcSToomas Soome 	 * on write error, remove file to ensure we have bootable config.
1374c262cbbcSToomas Soome 	 * note we dont mind if config exists, it will get updated
1375c262cbbcSToomas Soome 	 */
1376c262cbbcSToomas Soome 	(void) fprintf(fp, "xen_kernel=\"/boot/${ISADIR}/xen\"\n");
1377c262cbbcSToomas Soome 	if (errno != 0)
1378c262cbbcSToomas Soome 		goto error;
1379c262cbbcSToomas Soome 
1380c262cbbcSToomas Soome 	/*
1381c262cbbcSToomas Soome 	 * really simple and stupid console conversion.
1382c262cbbcSToomas Soome 	 * it really has to be gone, it belongs to milestone/xvm properties.
1383c262cbbcSToomas Soome 	 */
1384c262cbbcSToomas Soome 	env = getenv("console");
1385c262cbbcSToomas Soome 	if (env != NULL) {
1386c262cbbcSToomas Soome 		if (strcmp(env, "ttya") == 0)
1387c262cbbcSToomas Soome 			(void) fprintf(fp, "xen_cmdline=\"console=com1 %s\"\n",
1388c262cbbcSToomas Soome 			    opt);
1389c262cbbcSToomas Soome 		else if (strcmp(env, "ttyb") == 0)
1390c262cbbcSToomas Soome 			(void) fprintf(fp, "xen_cmdline=\"console=com2 %s\"\n",
1391c262cbbcSToomas Soome 			    opt);
1392c262cbbcSToomas Soome 		else
1393c262cbbcSToomas Soome 			(void) fprintf(fp, "xen_cmdline=\"console=vga %s\"\n",
1394c262cbbcSToomas Soome 			    opt);
1395c262cbbcSToomas Soome 	} else
1396c262cbbcSToomas Soome 		(void) fprintf(fp, "xen_cmdline=\"%s\"\n", opt);
1397c262cbbcSToomas Soome 	if (errno != 0)
1398c262cbbcSToomas Soome 		goto error;
1399c262cbbcSToomas Soome 
1400c262cbbcSToomas Soome 	(void) fprintf(fp,
1401c262cbbcSToomas Soome 	    "bootfile=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1402c262cbbcSToomas Soome 	if (errno != 0)
1403c262cbbcSToomas Soome 		goto error;
1404c262cbbcSToomas Soome 
1405c262cbbcSToomas Soome 	(void) fprintf(fp,
1406c262cbbcSToomas Soome 	    "boot-args=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1407c262cbbcSToomas Soome 	if (errno != 0)
1408c262cbbcSToomas Soome 		goto error;
1409c262cbbcSToomas Soome 
1410c262cbbcSToomas Soome 	(void) fclose(fp);
1411c262cbbcSToomas Soome 	if (errno != 0) {
1412c262cbbcSToomas Soome 		(void) unlink(path);
1413c262cbbcSToomas Soome 		return (BAM_ERROR);
1414c262cbbcSToomas Soome 	}
1415c262cbbcSToomas Soome 	return (BAM_SUCCESS);
1416c262cbbcSToomas Soome error:
1417c262cbbcSToomas Soome 	(void) fclose(fp);
1418c262cbbcSToomas Soome 	(void) unlink(path);
1419c262cbbcSToomas Soome 	return (BAM_ERROR);
1420c262cbbcSToomas Soome }
1421