xref: /titanic_51/usr/src/cmd/boot/bootadm/bootadm_loader.c (revision 71668a2f05bc8eb5e0c1f7eaf23e10cc7d40c90b)
1f64ca102SToomas Soome /*
2f64ca102SToomas Soome  * CDDL HEADER START
3f64ca102SToomas Soome  *
4f64ca102SToomas Soome  * The contents of this file are subject to the terms of the
5f64ca102SToomas Soome  * Common Development and Distribution License (the "License").
6f64ca102SToomas Soome  * You may not use this file except in compliance with the License.
7f64ca102SToomas Soome  *
8f64ca102SToomas Soome  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f64ca102SToomas Soome  * or http://www.opensolaris.org/os/licensing.
10f64ca102SToomas Soome  * See the License for the specific language governing permissions
11f64ca102SToomas Soome  * and limitations under the License.
12f64ca102SToomas Soome  *
13f64ca102SToomas Soome  * When distributing Covered Code, include this CDDL HEADER in each
14f64ca102SToomas Soome  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f64ca102SToomas Soome  * If applicable, add the following below this CDDL HEADER, with the
16f64ca102SToomas Soome  * fields enclosed by brackets "[]" replaced with your own identifying
17f64ca102SToomas Soome  * information: Portions Copyright [yyyy] [name of copyright owner]
18f64ca102SToomas Soome  *
19f64ca102SToomas Soome  * CDDL HEADER END
20f64ca102SToomas Soome  */
21f64ca102SToomas Soome /*
22f64ca102SToomas Soome  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23f64ca102SToomas Soome  * Copyright 2012 Milan Jurik. All rights reserved.
24f64ca102SToomas Soome  */
25f64ca102SToomas Soome 
26f64ca102SToomas Soome /*
27f64ca102SToomas Soome  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28f64ca102SToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
29*71668a2fSAndy Fiddaman  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
30f64ca102SToomas Soome  */
31f64ca102SToomas Soome 
32f64ca102SToomas Soome /*
33f64ca102SToomas Soome  * Loader menu management.
34f64ca102SToomas Soome  */
35f64ca102SToomas Soome 
36f64ca102SToomas Soome #include <stdio.h>
37f64ca102SToomas Soome #include <stdlib.h>
38f64ca102SToomas Soome #include <string.h>
39f64ca102SToomas Soome #include <wchar.h>
40f64ca102SToomas Soome #include <errno.h>
41f64ca102SToomas Soome #include <limits.h>
42f64ca102SToomas Soome #include <alloca.h>
43f64ca102SToomas Soome #include <unistd.h>
44f64ca102SToomas Soome #include <sys/types.h>
45f64ca102SToomas Soome #include <sys/stat.h>
46f64ca102SToomas Soome #include <sys/queue.h>
47f64ca102SToomas Soome #include <libbe.h>
48f64ca102SToomas Soome #include <ficl.h>
49f64ca102SToomas Soome #include <ficlplatform/emu.h>
50353ca6f2SToomas Soome #include <ofmt.h>
51f64ca102SToomas Soome 
52f64ca102SToomas Soome #include "bootadm.h"
53f64ca102SToomas Soome 
54f64ca102SToomas Soome extern int bam_rootlen;
55f64ca102SToomas Soome extern int bam_alt_root;
56f64ca102SToomas Soome extern char *rootbuf;
57f64ca102SToomas Soome extern char *bam_root;
58f64ca102SToomas Soome 
59f64ca102SToomas Soome #define	BOOT_DIR	"/boot"
60f64ca102SToomas Soome #define	CONF_DIR	BOOT_DIR "/conf.d"
61f64ca102SToomas Soome #define	MENU		BOOT_DIR "/menu.lst"
62f64ca102SToomas Soome #define	TRANSIENT	BOOT_DIR "/transient.conf"
63f64ca102SToomas Soome #define	XEN_CONFIG	CONF_DIR "/xen"
64f64ca102SToomas Soome 
65353ca6f2SToomas Soome typedef struct menu_entry {
66353ca6f2SToomas Soome 	int me_idx;
67353ca6f2SToomas Soome 	boolean_t me_active;
68353ca6f2SToomas Soome 	char *me_title;
69353ca6f2SToomas Soome 	char *me_type;
70353ca6f2SToomas Soome 	char *me_bootfs;
71353ca6f2SToomas Soome 	STAILQ_ENTRY(menu_entry) me_next;
72353ca6f2SToomas Soome } menu_entry_t;
73f64ca102SToomas Soome STAILQ_HEAD(menu_lst, menu_entry);
74f64ca102SToomas Soome 
75f64ca102SToomas Soome static error_t set_option(struct menu_lst *, char *, char *);
76f64ca102SToomas Soome static error_t list_entry(struct menu_lst *, char *, char *);
77f64ca102SToomas Soome static error_t update_entry(struct menu_lst *, char *, char *);
78f64ca102SToomas Soome static error_t update_temp(struct menu_lst *, char *, char *);
79f64ca102SToomas Soome static error_t list_setting(struct menu_lst *menu, char *, char *);
80f64ca102SToomas Soome static error_t disable_hyper(struct menu_lst *, char *, char *);
81f64ca102SToomas Soome static error_t enable_hyper(struct menu_lst *, char *, char *);
82f64ca102SToomas Soome 
83f64ca102SToomas Soome /* Menu related sub commands */
84f64ca102SToomas Soome static subcmd_defn_t menu_subcmds[] = {
85f64ca102SToomas Soome 	"set_option",		OPT_ABSENT,	set_option, 0,	/* PUB */
86f64ca102SToomas Soome 	"list_entry",		OPT_OPTIONAL,	list_entry, 1,	/* PUB */
87f64ca102SToomas Soome 	"update_entry",		OPT_REQ,	update_entry, 0, /* menu */
88f64ca102SToomas Soome 	"update_temp",		OPT_OPTIONAL,	update_temp, 0,	/* reboot */
89f64ca102SToomas Soome 	"list_setting",		OPT_OPTIONAL,	list_setting, 1, /* menu */
90f64ca102SToomas Soome 	"disable_hypervisor",	OPT_ABSENT,	disable_hyper, 0, /* menu */
91f64ca102SToomas Soome 	"enable_hypervisor",	OPT_ABSENT,	enable_hyper, 0, /* menu */
92f64ca102SToomas Soome 	NULL,			0,		NULL, 0 /* must be last */
93f64ca102SToomas Soome };
94f64ca102SToomas Soome 
95353ca6f2SToomas Soome #define	NUM_COLS	(5)
96f64ca102SToomas Soome 
97353ca6f2SToomas Soome static boolean_t
98353ca6f2SToomas Soome print_menu_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
99f64ca102SToomas Soome {
100353ca6f2SToomas Soome 	menu_entry_t *entry = ofarg->ofmt_cbarg;
101f64ca102SToomas Soome 
102353ca6f2SToomas Soome 	switch (ofarg->ofmt_id) {
103353ca6f2SToomas Soome 	case 0:
104353ca6f2SToomas Soome 		(void) snprintf(buf, bufsize, "%d", entry->me_idx);
105353ca6f2SToomas Soome 		break;
106353ca6f2SToomas Soome 	case 1:
107353ca6f2SToomas Soome 		(void) snprintf(buf, bufsize, "%s", entry->me_title);
108353ca6f2SToomas Soome 		break;
109353ca6f2SToomas Soome 	case 2:
110353ca6f2SToomas Soome 		(void) snprintf(buf, bufsize, "%s", entry->me_bootfs);
111353ca6f2SToomas Soome 		break;
112353ca6f2SToomas Soome 	case 3:
113353ca6f2SToomas Soome 		(void) snprintf(buf, bufsize, "%s", entry->me_type);
114353ca6f2SToomas Soome 		break;
115353ca6f2SToomas Soome 	case 4:
116353ca6f2SToomas Soome 		if (entry->me_active == B_TRUE)
117353ca6f2SToomas Soome 			(void) snprintf(buf, bufsize, "   *");
118353ca6f2SToomas Soome 		else
119353ca6f2SToomas Soome 			(void) snprintf(buf, bufsize, "   -");
120353ca6f2SToomas Soome 		break;
121353ca6f2SToomas Soome 	default:
122353ca6f2SToomas Soome 		return (B_FALSE);
123f64ca102SToomas Soome 	}
124353ca6f2SToomas Soome 	return (B_TRUE);
125f64ca102SToomas Soome }
126f64ca102SToomas Soome 
127f64ca102SToomas Soome static void
128353ca6f2SToomas Soome init_hdr_cols(ofmt_field_t *hdr)
129f64ca102SToomas Soome {
130353ca6f2SToomas Soome 	uint_t i;
131f64ca102SToomas Soome 
132f64ca102SToomas Soome 	for (i = 0; i < NUM_COLS; i++) {
133353ca6f2SToomas Soome 		char *name = NULL;
134353ca6f2SToomas Soome 
135353ca6f2SToomas Soome 		switch (i) {
136353ca6f2SToomas Soome 		case 0:
137353ca6f2SToomas Soome 			name = _("INDEX");
138353ca6f2SToomas Soome 			break;
139353ca6f2SToomas Soome 		case 1:
140353ca6f2SToomas Soome 			name = _("NAME");
141353ca6f2SToomas Soome 			break;
142353ca6f2SToomas Soome 		case 2:
143353ca6f2SToomas Soome 			name = _("DEVICE");
144353ca6f2SToomas Soome 			break;
145353ca6f2SToomas Soome 		case 3:
146353ca6f2SToomas Soome 			name = _("TYPE");
147353ca6f2SToomas Soome 			break;
148353ca6f2SToomas Soome 		case 4:
149353ca6f2SToomas Soome 			name = _("DEFAULT");
150353ca6f2SToomas Soome 			break;
151353ca6f2SToomas Soome 		}
152353ca6f2SToomas Soome 
153353ca6f2SToomas Soome 		hdr[i].of_name = name;
154353ca6f2SToomas Soome 		hdr[i].of_id = i;
155353ca6f2SToomas Soome 		hdr[i].of_cb = print_menu_cb;
156f64ca102SToomas Soome 
157f64ca102SToomas Soome 		if (name != NULL) {
158f64ca102SToomas Soome 			wchar_t wname[128];
159f64ca102SToomas Soome 			size_t sz = mbstowcs(wname, name, sizeof (wname) /
160f64ca102SToomas Soome 			    sizeof (wchar_t));
161f64ca102SToomas Soome 			if (sz > 0) {
162f64ca102SToomas Soome 				int wcsw = wcswidth(wname, sz);
163f64ca102SToomas Soome 				if (wcsw > 0)
164353ca6f2SToomas Soome 					hdr[i].of_width = wcsw;
165f64ca102SToomas Soome 				else
166353ca6f2SToomas Soome 					hdr[i].of_width = sz;
167f64ca102SToomas Soome 			} else {
168353ca6f2SToomas Soome 				hdr[i].of_width = strlen(name);
169f64ca102SToomas Soome 			}
170f64ca102SToomas Soome 		}
171f64ca102SToomas Soome 	}
172f64ca102SToomas Soome }
173f64ca102SToomas Soome 
174f64ca102SToomas Soome static void
175353ca6f2SToomas Soome menu_update_widths(ofmt_field_t *hdr, struct menu_lst *menu)
176f64ca102SToomas Soome {
177f64ca102SToomas Soome 	size_t len[NUM_COLS];
178353ca6f2SToomas Soome 	menu_entry_t *entry;
179f64ca102SToomas Soome 	int i;
180f64ca102SToomas Soome 
181f64ca102SToomas Soome 	for (i = 0; i < NUM_COLS; i++)
182353ca6f2SToomas Soome 		len[i] = hdr[i].of_width + 1;
183f64ca102SToomas Soome 
184353ca6f2SToomas Soome 	STAILQ_FOREACH(entry, menu, me_next) {
185353ca6f2SToomas Soome 		size_t entry_len;
186353ca6f2SToomas Soome 
187353ca6f2SToomas Soome 		entry_len = strlen(entry->me_title) + 1;
188353ca6f2SToomas Soome 		if (entry_len > len[1])
189353ca6f2SToomas Soome 			len[1] = entry_len;
190353ca6f2SToomas Soome 
191353ca6f2SToomas Soome 		entry_len = strlen(entry->me_bootfs) + 1;
192353ca6f2SToomas Soome 		if (entry_len > len[2])
193353ca6f2SToomas Soome 			len[2] = entry_len;
194353ca6f2SToomas Soome 
195353ca6f2SToomas Soome 		entry_len = strlen(entry->me_type) + 1;
196353ca6f2SToomas Soome 		if (entry_len > len[3])
197353ca6f2SToomas Soome 			len[3] = entry_len;
198f64ca102SToomas Soome 	}
199f64ca102SToomas Soome 
200f64ca102SToomas Soome 	for (i = 0; i < NUM_COLS; i++)
201353ca6f2SToomas Soome 		hdr[i].of_width = len[i];
202f64ca102SToomas Soome }
203f64ca102SToomas Soome 
204353ca6f2SToomas Soome static ofmt_field_t *
205353ca6f2SToomas Soome init_menu_template(struct menu_lst *menu)
206f64ca102SToomas Soome {
207353ca6f2SToomas Soome 	ofmt_field_t *temp;
208f64ca102SToomas Soome 
209353ca6f2SToomas Soome 	if ((temp = calloc(NUM_COLS + 1, sizeof (ofmt_field_t))) == NULL)
210353ca6f2SToomas Soome 		return (temp);
211f64ca102SToomas Soome 
212353ca6f2SToomas Soome 	init_hdr_cols(temp);
213353ca6f2SToomas Soome 	menu_update_widths(temp, menu);
214353ca6f2SToomas Soome 	return (temp);
215f64ca102SToomas Soome }
216f64ca102SToomas Soome 
217f64ca102SToomas Soome static void
218f64ca102SToomas Soome print_nodes(boolean_t parsable, struct menu_lst *menu)
219f64ca102SToomas Soome {
220353ca6f2SToomas Soome 	ofmt_status_t oferr;
221353ca6f2SToomas Soome 	ofmt_handle_t ofmt;
222353ca6f2SToomas Soome 	uint_t ofmtflags = 0;
223353ca6f2SToomas Soome 	ofmt_field_t *menu_template;
224353ca6f2SToomas Soome 	menu_entry_t  *entry;
225f64ca102SToomas Soome 
226353ca6f2SToomas Soome 	if (parsable == B_TRUE)
227353ca6f2SToomas Soome 		ofmtflags = OFMT_PARSABLE;
228353ca6f2SToomas Soome 
229353ca6f2SToomas Soome 	menu_template = init_menu_template(menu);
230353ca6f2SToomas Soome 	oferr = ofmt_open(NULL, menu_template, ofmtflags, 0, &ofmt);
231353ca6f2SToomas Soome 
232353ca6f2SToomas Soome 	if (oferr != OFMT_SUCCESS) {
233353ca6f2SToomas Soome 		char buf[OFMT_BUFSIZE];
234353ca6f2SToomas Soome 
235353ca6f2SToomas Soome 		(void) ofmt_strerror(ofmt, oferr, buf, sizeof (buf));
236353ca6f2SToomas Soome 		(void) printf("bootadm: %s\n", buf);
237353ca6f2SToomas Soome 		free(menu_template);
238353ca6f2SToomas Soome 		return;
239f64ca102SToomas Soome 	}
240f64ca102SToomas Soome 
241353ca6f2SToomas Soome 	STAILQ_FOREACH(entry, menu, me_next)
242353ca6f2SToomas Soome 		ofmt_print(ofmt, entry);
243353ca6f2SToomas Soome 
244353ca6f2SToomas Soome 	ofmt_close(ofmt);
245353ca6f2SToomas Soome 	free(menu_template);
246353ca6f2SToomas Soome }
247353ca6f2SToomas Soome 
248353ca6f2SToomas Soome /*
249353ca6f2SToomas Soome  * Get the be_active_on_boot for bootfs.
250353ca6f2SToomas Soome  */
251353ca6f2SToomas Soome static boolean_t
252353ca6f2SToomas Soome menu_active_on_boot(be_node_list_t *be_nodes, const char *bootfs)
253353ca6f2SToomas Soome {
254353ca6f2SToomas Soome 	be_node_list_t *be_node;
255353ca6f2SToomas Soome 	boolean_t rv = B_FALSE;
256353ca6f2SToomas Soome 
257353ca6f2SToomas Soome 	for (be_node = be_nodes; be_node != NULL;
258353ca6f2SToomas Soome 	    be_node = be_node->be_next_node) {
259353ca6f2SToomas Soome 		if (strcmp(be_node->be_root_ds, bootfs) == 0) {
260353ca6f2SToomas Soome 			rv = be_node->be_active_on_boot;
261353ca6f2SToomas Soome 			break;
262353ca6f2SToomas Soome 		}
263353ca6f2SToomas Soome 	}
264353ca6f2SToomas Soome 
265353ca6f2SToomas Soome 	return (rv);
266f64ca102SToomas Soome }
267f64ca102SToomas Soome 
268f64ca102SToomas Soome error_t
269f64ca102SToomas Soome menu_read(struct menu_lst *menu, char *menu_path)
270f64ca102SToomas Soome {
271f64ca102SToomas Soome 	FILE *fp;
272353ca6f2SToomas Soome 	be_node_list_t *be_nodes;
273353ca6f2SToomas Soome 	menu_entry_t *mp;
274f64ca102SToomas Soome 	char buf[PATH_MAX];
275f64ca102SToomas Soome 	char *title;
276f64ca102SToomas Soome 	char *bootfs;
277353ca6f2SToomas Soome 	char *type;
278353ca6f2SToomas Soome 	char *key, *value;
279f64ca102SToomas Soome 	int i = 0;
280f64ca102SToomas Soome 	int ret = BAM_SUCCESS;
281f64ca102SToomas Soome 
282f64ca102SToomas Soome 	fp = fopen(menu_path, "r");
283f64ca102SToomas Soome 	if (fp == NULL)
284f64ca102SToomas Soome 		return (BAM_ERROR);
285f64ca102SToomas Soome 
286*71668a2fSAndy Fiddaman 	if (be_list(NULL, &be_nodes, BE_LIST_DEFAULT) != BE_SUCCESS)
287353ca6f2SToomas Soome 		be_nodes = NULL;
288353ca6f2SToomas Soome 
289f64ca102SToomas Soome 	/*
290f64ca102SToomas Soome 	 * menu.lst entry is on two lines, one for title, one for bootfs
291f64ca102SToomas Soome 	 * so we process both lines in succession.
292f64ca102SToomas Soome 	 */
293353ca6f2SToomas Soome 	title = NULL;
294353ca6f2SToomas Soome 	type = NULL;
295353ca6f2SToomas Soome 	bootfs = NULL;
296f64ca102SToomas Soome 	do {
297f64ca102SToomas Soome 		if (fgets(buf, PATH_MAX, fp) == NULL) {
298f64ca102SToomas Soome 			if (!feof(fp))
299f64ca102SToomas Soome 				ret = BAM_ERROR;
300353ca6f2SToomas Soome 			goto done;
301f64ca102SToomas Soome 		}
302353ca6f2SToomas Soome 		key = strtok(buf, " \n");
303353ca6f2SToomas Soome 		if (strcmp(key, "title") != 0) {
304353ca6f2SToomas Soome 			ret = BAM_ERROR;
305353ca6f2SToomas Soome 			goto done;
306f64ca102SToomas Soome 		}
307353ca6f2SToomas Soome 		value = strtok(NULL, " \n");
308353ca6f2SToomas Soome 		if ((title = strdup(value)) == NULL) {
309353ca6f2SToomas Soome 			ret = BAM_ERROR;
310353ca6f2SToomas Soome 			goto done;
311f64ca102SToomas Soome 		}
312f64ca102SToomas Soome 
313f64ca102SToomas Soome 		if (fgets(buf, PATH_MAX, fp) == NULL) {
314353ca6f2SToomas Soome 			ret = BAM_ERROR;
315353ca6f2SToomas Soome 			goto done;
316f64ca102SToomas Soome 		}
317f64ca102SToomas Soome 
318353ca6f2SToomas Soome 		key = strtok(buf, " \n");
319353ca6f2SToomas Soome 		if ((type = strdup(key)) == NULL) {
320353ca6f2SToomas Soome 			ret = BAM_ERROR;
321353ca6f2SToomas Soome 			goto done;
322353ca6f2SToomas Soome 		}
323353ca6f2SToomas Soome 		value = strtok(NULL, " \n");
324353ca6f2SToomas Soome 		if ((bootfs = strdup(value)) == NULL) {
325353ca6f2SToomas Soome 			ret = BAM_ERROR;
326353ca6f2SToomas Soome 			goto done;
327353ca6f2SToomas Soome 		}
328353ca6f2SToomas Soome 		if ((mp = malloc(sizeof (menu_entry_t))) == NULL) {
329353ca6f2SToomas Soome 			ret = BAM_ERROR;
330353ca6f2SToomas Soome 			goto done;
331353ca6f2SToomas Soome 		}
332353ca6f2SToomas Soome 		mp->me_idx = i++;
333353ca6f2SToomas Soome 		mp->me_title = title;
334353ca6f2SToomas Soome 		mp->me_type = type;
335353ca6f2SToomas Soome 		mp->me_bootfs = bootfs;
336353ca6f2SToomas Soome 		mp->me_active = menu_active_on_boot(be_nodes, bootfs);
337353ca6f2SToomas Soome 		STAILQ_INSERT_TAIL(menu, mp, me_next);
338f64ca102SToomas Soome 
339353ca6f2SToomas Soome 		title = NULL;
340353ca6f2SToomas Soome 		type = NULL;
341353ca6f2SToomas Soome 		bootfs = NULL;
342f64ca102SToomas Soome 	} while (feof(fp) == 0);
343f64ca102SToomas Soome 
344353ca6f2SToomas Soome done:
345353ca6f2SToomas Soome 	free(title);
346353ca6f2SToomas Soome 	free(type);
347353ca6f2SToomas Soome 	free(bootfs);
348f64ca102SToomas Soome 	(void) fclose(fp);
349353ca6f2SToomas Soome 	be_free_list(be_nodes);
350f64ca102SToomas Soome 	return (ret);
351f64ca102SToomas Soome }
352f64ca102SToomas Soome 
353f64ca102SToomas Soome void
354f64ca102SToomas Soome menu_free(struct menu_lst *menu)
355f64ca102SToomas Soome {
356353ca6f2SToomas Soome 	menu_entry_t *entry;
357353ca6f2SToomas Soome 	STAILQ_FOREACH(entry, menu, me_next) {
358353ca6f2SToomas Soome 		STAILQ_REMOVE_HEAD(menu, me_next);
359353ca6f2SToomas Soome 		free(entry->me_title);
360353ca6f2SToomas Soome 		free(entry->me_type);
361353ca6f2SToomas Soome 		free(entry->me_bootfs);
362f64ca102SToomas Soome 		free(entry);
363f64ca102SToomas Soome 	}
364f64ca102SToomas Soome }
365f64ca102SToomas Soome 
366f64ca102SToomas Soome error_t
367f64ca102SToomas Soome bam_loader_menu(char *subcmd, char *opt, int largc, char *largv[])
368f64ca102SToomas Soome {
369f64ca102SToomas Soome 	error_t		ret;
370f64ca102SToomas Soome 	char		menu_path[PATH_MAX];
371f64ca102SToomas Soome 	char		clean_menu_root[PATH_MAX];
372f64ca102SToomas Soome 	char		menu_root[PATH_MAX];
373f64ca102SToomas Soome 	struct stat	sb;
374f64ca102SToomas Soome 	error_t		(*f)(struct menu_lst *, char *, char *);
375f64ca102SToomas Soome 	char		*special;
376f64ca102SToomas Soome 	char		*pool = NULL;
377f64ca102SToomas Soome 	zfs_mnted_t	zmnted;
378f64ca102SToomas Soome 	char		*zmntpt;
379f64ca102SToomas Soome 	char		*osdev;
380f64ca102SToomas Soome 	char		*osroot;
381f64ca102SToomas Soome 	const char	*fcn = "bam_loader_menu()";
382f64ca102SToomas Soome 	struct menu_lst	menu = {0};
383f64ca102SToomas Soome 
384f64ca102SToomas Soome 	STAILQ_INIT(&menu);
385f64ca102SToomas Soome 
386f64ca102SToomas Soome 	/*
387f64ca102SToomas Soome 	 * Check arguments
388f64ca102SToomas Soome 	 */
389f64ca102SToomas Soome 	ret = check_subcmd_and_options(subcmd, opt, menu_subcmds, &f);
390f64ca102SToomas Soome 	if (ret == BAM_ERROR) {
391f64ca102SToomas Soome 		return (BAM_ERROR);
392f64ca102SToomas Soome 	}
393f64ca102SToomas Soome 
394f64ca102SToomas Soome 	assert(bam_root);
395f64ca102SToomas Soome 
396f64ca102SToomas Soome 	(void) strlcpy(menu_root, bam_root, sizeof (menu_root));
397f64ca102SToomas Soome 	osdev = osroot = NULL;
398f64ca102SToomas Soome 
399f64ca102SToomas Soome 	if (strcmp(subcmd, "update_entry") == 0) {
400f64ca102SToomas Soome 		assert(opt);
401f64ca102SToomas Soome 
402f64ca102SToomas Soome 		osdev = strtok(opt, ",");
403f64ca102SToomas Soome 		assert(osdev);
404f64ca102SToomas Soome 		osroot = strtok(NULL, ",");
405f64ca102SToomas Soome 		if (osroot) {
406f64ca102SToomas Soome 			/* fixup bam_root so that it points at osroot */
407f64ca102SToomas Soome 			if (realpath(osroot, rootbuf) == NULL) {
408f64ca102SToomas Soome 				bam_error(_("cannot resolve path %s: %s\n"),
409f64ca102SToomas Soome 				    osroot, strerror(errno));
410f64ca102SToomas Soome 				return (BAM_ERROR);
411f64ca102SToomas Soome 			}
412f64ca102SToomas Soome 			bam_alt_root = 1;
413f64ca102SToomas Soome 			bam_root  = rootbuf;
414f64ca102SToomas Soome 			bam_rootlen = strlen(rootbuf);
415f64ca102SToomas Soome 		}
416f64ca102SToomas Soome 	}
417f64ca102SToomas Soome 
418f64ca102SToomas Soome 	if (stat(menu_root, &sb) == -1) {
419f64ca102SToomas Soome 		bam_error(_("cannot find menu\n"));
420f64ca102SToomas Soome 		return (BAM_ERROR);
421f64ca102SToomas Soome 	}
422f64ca102SToomas Soome 
423f64ca102SToomas Soome 	if (!is_zfs(menu_root)) {
424f64ca102SToomas Soome 		bam_error(_("only ZFS root is supported\n"));
425f64ca102SToomas Soome 		return (BAM_ERROR);
426f64ca102SToomas Soome 	}
427f64ca102SToomas Soome 
428f64ca102SToomas Soome 	assert(strcmp(menu_root, bam_root) == 0);
429f64ca102SToomas Soome 	special = get_special(menu_root);
430f64ca102SToomas Soome 	INJECT_ERROR1("Z_MENU_GET_SPECIAL", special = NULL);
431f64ca102SToomas Soome 	if (special == NULL) {
432f64ca102SToomas Soome 		bam_error(_("cant find special file for mount-point %s\n"),
433f64ca102SToomas Soome 		    menu_root);
434f64ca102SToomas Soome 		return (BAM_ERROR);
435f64ca102SToomas Soome 	}
436f64ca102SToomas Soome 	pool = strtok(special, "/");
437f64ca102SToomas Soome 	INJECT_ERROR1("Z_MENU_GET_POOL", pool = NULL);
438f64ca102SToomas Soome 	if (pool == NULL) {
439f64ca102SToomas Soome 		free(special);
440f64ca102SToomas Soome 		bam_error(_("cant find pool for mount-point %s\n"), menu_root);
441f64ca102SToomas Soome 		return (BAM_ERROR);
442f64ca102SToomas Soome 	}
443f64ca102SToomas Soome 	BAM_DPRINTF(("%s: derived pool=%s from special\n", fcn, pool));
444f64ca102SToomas Soome 
445f64ca102SToomas Soome 	zmntpt = mount_top_dataset(pool, &zmnted);
446f64ca102SToomas Soome 	INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt = NULL);
447f64ca102SToomas Soome 	if (zmntpt == NULL) {
448f64ca102SToomas Soome 		bam_error(_("cannot mount pool dataset for pool: %s\n"), pool);
449f64ca102SToomas Soome 		free(special);
450f64ca102SToomas Soome 		return (BAM_ERROR);
451f64ca102SToomas Soome 	}
452f64ca102SToomas Soome 	BAM_DPRINTF(("%s: top dataset mountpoint=%s\n", fcn, zmntpt));
453f64ca102SToomas Soome 
454f64ca102SToomas Soome 	(void) strlcpy(menu_root, zmntpt, sizeof (menu_root));
455f64ca102SToomas Soome 	BAM_DPRINTF(("%s: zfs menu_root=%s\n", fcn, menu_root));
456f64ca102SToomas Soome 
457f64ca102SToomas Soome 	elide_trailing_slash(menu_root, clean_menu_root,
458f64ca102SToomas Soome 	    sizeof (clean_menu_root));
459f64ca102SToomas Soome 
460f64ca102SToomas Soome 	BAM_DPRINTF(("%s: cleaned menu root is <%s>\n", fcn, clean_menu_root));
461f64ca102SToomas Soome 
462f64ca102SToomas Soome 	(void) strlcpy(menu_path, clean_menu_root, sizeof (menu_path));
463f64ca102SToomas Soome 	(void) strlcat(menu_path, MENU, sizeof (menu_path));
464f64ca102SToomas Soome 
465f64ca102SToomas Soome 	BAM_DPRINTF(("%s: menu path is: %s\n", fcn, menu_path));
466f64ca102SToomas Soome 
467f64ca102SToomas Soome 	/*
468f64ca102SToomas Soome 	 * update_entry is special case, its used by installer
469f64ca102SToomas Soome 	 * and needs to create menu.lst file for loader
470f64ca102SToomas Soome 	 */
471f64ca102SToomas Soome 	if (menu_read(&menu, menu_path) == BAM_ERROR &&
472f64ca102SToomas Soome 	    strcmp(subcmd, "update_entry") != 0) {
473f64ca102SToomas Soome 		bam_error(_("cannot find menu file: %s\n"), menu_path);
474f64ca102SToomas Soome 		if (special != NULL)
475f64ca102SToomas Soome 			free(special);
476f64ca102SToomas Soome 		return (BAM_ERROR);
477f64ca102SToomas Soome 	}
478f64ca102SToomas Soome 
479f64ca102SToomas Soome 	/*
480f64ca102SToomas Soome 	 * If listing the menu, display the menu location
481f64ca102SToomas Soome 	 */
482f64ca102SToomas Soome 	if (strcmp(subcmd, "list_entry") == 0)
483f64ca102SToomas Soome 		bam_print(_("the location for the active menu is: %s\n"),
484f64ca102SToomas Soome 		    menu_path);
485f64ca102SToomas Soome 
486f64ca102SToomas Soome 	/*
487f64ca102SToomas Soome 	 * We already checked the following case in
488f64ca102SToomas Soome 	 * check_subcmd_and_suboptions() above. Complete the
489f64ca102SToomas Soome 	 * final step now.
490f64ca102SToomas Soome 	 */
491f64ca102SToomas Soome 	if (strcmp(subcmd, "set_option") == 0) {
492f64ca102SToomas Soome 		assert(largc == 1 && largv[0] && largv[1] == NULL);
493f64ca102SToomas Soome 		opt = largv[0];
494f64ca102SToomas Soome 	} else if ((strcmp(subcmd, "enable_hypervisor") != 0) &&
495f64ca102SToomas Soome 	    (strcmp(subcmd, "list_setting") != 0)) {
496f64ca102SToomas Soome 		assert(largc == 0 && largv == NULL);
497f64ca102SToomas Soome 	}
498f64ca102SToomas Soome 
499f64ca102SToomas Soome 	/*
500f64ca102SToomas Soome 	 * Once the sub-cmd handler has run
501f64ca102SToomas Soome 	 * only the line field is guaranteed to have valid values
502f64ca102SToomas Soome 	 */
503f64ca102SToomas Soome 	if (strcmp(subcmd, "update_entry") == 0) {
504f64ca102SToomas Soome 		ret = f(&menu, menu_root, osdev);
505f64ca102SToomas Soome 	} else if (strcmp(subcmd, "upgrade") == 0) {
506f64ca102SToomas Soome 		ret = f(&menu, bam_root, menu_root);
507f64ca102SToomas Soome 	} else if (strcmp(subcmd, "list_entry") == 0) {
508f64ca102SToomas Soome 		ret = f(&menu, menu_path, opt);
509f64ca102SToomas Soome 	} else if (strcmp(subcmd, "list_setting") == 0) {
510f64ca102SToomas Soome 		ret = f(&menu, ((largc > 0) ? largv[0] : ""),
511f64ca102SToomas Soome 		    ((largc > 1) ? largv[1] : ""));
512f64ca102SToomas Soome 	} else if (strcmp(subcmd, "disable_hypervisor") == 0) {
513f64ca102SToomas Soome 		if (is_sparc()) {
514f64ca102SToomas Soome 			bam_error(_("%s operation unsupported on SPARC "
515f64ca102SToomas Soome 			    "machines\n"), subcmd);
516f64ca102SToomas Soome 			ret = BAM_ERROR;
517f64ca102SToomas Soome 		} else {
518f64ca102SToomas Soome 			ret = f(&menu, bam_root, NULL);
519f64ca102SToomas Soome 		}
520f64ca102SToomas Soome 	} else if (strcmp(subcmd, "enable_hypervisor") == 0) {
521f64ca102SToomas Soome 		if (is_sparc()) {
522f64ca102SToomas Soome 			bam_error(_("%s operation unsupported on SPARC "
523f64ca102SToomas Soome 			    "machines\n"), subcmd);
524f64ca102SToomas Soome 			ret = BAM_ERROR;
525f64ca102SToomas Soome 		} else {
526f64ca102SToomas Soome 			char *extra_args = NULL;
527f64ca102SToomas Soome 
528f64ca102SToomas Soome 			/*
529f64ca102SToomas Soome 			 * Compress all arguments passed in the largv[] array
530f64ca102SToomas Soome 			 * into one string that can then be appended to the
531f64ca102SToomas Soome 			 * end of the kernel$ string the routine to enable the
532f64ca102SToomas Soome 			 * hypervisor will build.
533f64ca102SToomas Soome 			 *
534f64ca102SToomas Soome 			 * This allows the caller to supply arbitrary unparsed
535f64ca102SToomas Soome 			 * arguments, such as dom0 memory settings or APIC
536f64ca102SToomas Soome 			 * options.
537f64ca102SToomas Soome 			 *
538f64ca102SToomas Soome 			 * This concatenation will be done without ANY syntax
539f64ca102SToomas Soome 			 * checking whatsoever, so it's the responsibility of
540f64ca102SToomas Soome 			 * the caller to make sure the arguments are valid and
541f64ca102SToomas Soome 			 * do not duplicate arguments the conversion routines
542f64ca102SToomas Soome 			 * may create.
543f64ca102SToomas Soome 			 */
544f64ca102SToomas Soome 			if (largc > 0) {
545f64ca102SToomas Soome 				int extra_len, i;
546f64ca102SToomas Soome 
547f64ca102SToomas Soome 				for (extra_len = 0, i = 0; i < largc; i++)
548f64ca102SToomas Soome 					extra_len += strlen(largv[i]);
549f64ca102SToomas Soome 
550f64ca102SToomas Soome 				/*
551f64ca102SToomas Soome 				 * Allocate space for argument strings,
552f64ca102SToomas Soome 				 * intervening spaces and terminating NULL.
553f64ca102SToomas Soome 				 */
554f64ca102SToomas Soome 				extra_args = alloca(extra_len + largc);
555f64ca102SToomas Soome 
556f64ca102SToomas Soome 				(void) strcpy(extra_args, largv[0]);
557f64ca102SToomas Soome 
558f64ca102SToomas Soome 				for (i = 1; i < largc; i++) {
559f64ca102SToomas Soome 					(void) strcat(extra_args, " ");
560f64ca102SToomas Soome 					(void) strcat(extra_args, largv[i]);
561f64ca102SToomas Soome 				}
562f64ca102SToomas Soome 			}
563f64ca102SToomas Soome 
564f64ca102SToomas Soome 			ret = f(&menu, bam_root, extra_args);
565f64ca102SToomas Soome 		}
566f64ca102SToomas Soome 	} else
567f64ca102SToomas Soome 		ret = f(&menu, NULL, opt);
568f64ca102SToomas Soome 
569f64ca102SToomas Soome 	if (ret == BAM_WRITE) {
570f64ca102SToomas Soome 		BAM_DPRINTF(("%s: writing menu to clean-menu-root: <%s>\n",
571f64ca102SToomas Soome 		    fcn, clean_menu_root));
572f64ca102SToomas Soome 		/* ret = menu_write(clean_menu_root, menu); */
573f64ca102SToomas Soome 	}
574f64ca102SToomas Soome 
575f64ca102SToomas Soome 	INJECT_ERROR1("POOL_SET", pool = "/pooldata");
576f64ca102SToomas Soome 	assert((is_zfs(menu_root)) ^ (pool == NULL));
577f64ca102SToomas Soome 	if (pool) {
578f64ca102SToomas Soome 		(void) umount_top_dataset(pool, zmnted, zmntpt);
579f64ca102SToomas Soome 		free(special);
580f64ca102SToomas Soome 	}
581f64ca102SToomas Soome 
582f64ca102SToomas Soome 	menu_free(&menu);
583f64ca102SToomas Soome 	return (ret);
584f64ca102SToomas Soome }
585f64ca102SToomas Soome 
586f64ca102SToomas Soome /*
587f64ca102SToomas Soome  * To suppress output from ficl. We do not want to see messages
588f64ca102SToomas Soome  * from interpreting loader config.
589f64ca102SToomas Soome  */
590f64ca102SToomas Soome 
591f64ca102SToomas Soome /*ARGSUSED*/
592f64ca102SToomas Soome static void
593f64ca102SToomas Soome ficlTextOutSilent(ficlCallback *cb, char *text)
594f64ca102SToomas Soome {
595f64ca102SToomas Soome }
596f64ca102SToomas Soome 
597f64ca102SToomas Soome /*ARGSUSED*/
598f64ca102SToomas Soome static error_t
599f64ca102SToomas Soome set_option(struct menu_lst *menu, char *dummy, char *opt)
600f64ca102SToomas Soome {
601f64ca102SToomas Soome 	char path[PATH_MAX];
602f64ca102SToomas Soome 	char *val;
603f64ca102SToomas Soome 	char *rest;
604f64ca102SToomas Soome 	int optval;
605353ca6f2SToomas Soome 	menu_entry_t *entry;
606f64ca102SToomas Soome 	nvlist_t *be_attrs;
607f64ca102SToomas Soome 	FILE *fp;
608f64ca102SToomas Soome 	int rv, ret = BAM_SUCCESS;
609f64ca102SToomas Soome 
610f64ca102SToomas Soome 	assert(menu);
611f64ca102SToomas Soome 	assert(opt);
612f64ca102SToomas Soome 	assert(dummy == NULL);
613f64ca102SToomas Soome 
614f64ca102SToomas Soome 	val = strchr(opt, '=');
615f64ca102SToomas Soome 	if (val != NULL) {
616f64ca102SToomas Soome 		*val++ = '\0';
617f64ca102SToomas Soome 	}
618f64ca102SToomas Soome 
619f64ca102SToomas Soome 	if (strcmp(opt, "default") == 0) {
620f64ca102SToomas Soome 		errno = 0;
621f64ca102SToomas Soome 		optval = strtol(val, &rest, 10);
622f64ca102SToomas Soome 		if (errno != 0 || *rest != '\0') {
623f64ca102SToomas Soome 			bam_error(_("invalid boot entry number: %s\n"), val);
624f64ca102SToomas Soome 			return (BAM_ERROR);
625f64ca102SToomas Soome 		}
626353ca6f2SToomas Soome 		STAILQ_FOREACH(entry, menu, me_next) {
627353ca6f2SToomas Soome 			if (entry->me_idx == optval)
628f64ca102SToomas Soome 				break;
629f64ca102SToomas Soome 		}
630f64ca102SToomas Soome 		if (entry == NULL) {
631f64ca102SToomas Soome 			bam_error(_("invalid boot entry number: %s\n"), val);
632f64ca102SToomas Soome 			return (BAM_ERROR);
633f64ca102SToomas Soome 		}
634f64ca102SToomas Soome 		if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
635f64ca102SToomas Soome 			bam_error(_("out of memory\n"));
636f64ca102SToomas Soome 			return (BAM_ERROR);
637f64ca102SToomas Soome 		}
638f64ca102SToomas Soome 		if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
639353ca6f2SToomas Soome 		    entry->me_title) != 0) {
640f64ca102SToomas Soome 			bam_error(_("out of memory\n"));
641f64ca102SToomas Soome 			nvlist_free(be_attrs);
642f64ca102SToomas Soome 			return (BAM_ERROR);
643f64ca102SToomas Soome 		}
644f64ca102SToomas Soome 		ret = be_activate(be_attrs);
645f64ca102SToomas Soome 		nvlist_free(be_attrs);
646f64ca102SToomas Soome 		if (ret != 0)
647f64ca102SToomas Soome 			ret = BAM_ERROR;
648f64ca102SToomas Soome 		return (ret);
649f64ca102SToomas Soome 	} else if (strcmp(opt, "timeout") == 0) {
650f64ca102SToomas Soome 		errno = 0;
651f64ca102SToomas Soome 		optval = strtol(val, &rest, 10);
652f64ca102SToomas Soome 		if (errno != 0 || *rest != '\0') {
653f64ca102SToomas Soome 			bam_error(_("invalid timeout: %s\n"), val);
654f64ca102SToomas Soome 			return (BAM_ERROR);
655f64ca102SToomas Soome 		}
656f64ca102SToomas Soome 
657f64ca102SToomas Soome 		(void) snprintf(path, PATH_MAX, "%s" CONF_DIR "/timeout",
658f64ca102SToomas Soome 		    bam_root);
659f64ca102SToomas Soome 
660f64ca102SToomas Soome 		fp = fopen(path, "w");
661f64ca102SToomas Soome 		if (fp == NULL) {
662f64ca102SToomas Soome 			bam_error(_("failed to open file: %s: %s\n"),
663f64ca102SToomas Soome 			    path, strerror(errno));
664f64ca102SToomas Soome 			return (BAM_ERROR);
665f64ca102SToomas Soome 		}
666f64ca102SToomas Soome 		/*
667f64ca102SToomas Soome 		 * timeout=-1 is to disable auto boot in illumos, but
668f64ca102SToomas Soome 		 * loader needs "NO" to disable auto boot.
669f64ca102SToomas Soome 		 */
670f64ca102SToomas Soome 		if (optval == -1)
671f64ca102SToomas Soome 			rv = fprintf(fp, "autoboot_delay=\"NO\"\n");
672f64ca102SToomas Soome 		else
673f64ca102SToomas Soome 			rv = fprintf(fp, "autoboot_delay=\"%d\"\n", optval);
674f64ca102SToomas Soome 
675f64ca102SToomas Soome 		if (rv < 0) {
676f64ca102SToomas Soome 			bam_error(_("write to file failed: %s: %s\n"),
677f64ca102SToomas Soome 			    path, strerror(errno));
678f64ca102SToomas Soome 			(void) fclose(fp);
679f64ca102SToomas Soome 			ret = BAM_ERROR;
680f64ca102SToomas Soome 		} else
681f64ca102SToomas Soome 			rv = fclose(fp);
682f64ca102SToomas Soome 
683f64ca102SToomas Soome 		if (rv < 0) {
684f64ca102SToomas Soome 			bam_error(_("failed to close file: %s: %s\n"),
685f64ca102SToomas Soome 			    path, strerror(errno));
686f64ca102SToomas Soome 			ret = BAM_ERROR;
687f64ca102SToomas Soome 		}
688f64ca102SToomas Soome 		if (ret == BAM_ERROR)
689f64ca102SToomas Soome 			(void) unlink(path);
690f64ca102SToomas Soome 
691f64ca102SToomas Soome 		return (BAM_SUCCESS);
692f64ca102SToomas Soome 	}
693f64ca102SToomas Soome 
694f64ca102SToomas Soome 	bam_error(_("invalid option: %s\n"), opt);
695f64ca102SToomas Soome 	return (BAM_ERROR);
696f64ca102SToomas Soome }
697f64ca102SToomas Soome 
698f64ca102SToomas Soome static int
699353ca6f2SToomas Soome bam_mount_be(menu_entry_t *entry, char **dir)
700f64ca102SToomas Soome {
701f64ca102SToomas Soome 	nvlist_t *be_attrs = NULL;
702f64ca102SToomas Soome 	const char *tmpdir = getenv("TMPDIR");
703f64ca102SToomas Soome 	const char *tmpname = "bam.XXXXXX";
704f64ca102SToomas Soome 	be_node_list_t *be_node, *be_nodes = NULL;
705f64ca102SToomas Soome 	int ret;
706f64ca102SToomas Soome 
707f64ca102SToomas Soome 	*dir = NULL;
708f64ca102SToomas Soome 	if (tmpdir == NULL)
709f64ca102SToomas Soome 		tmpdir = "/tmp";
710f64ca102SToomas Soome 
711f64ca102SToomas Soome 	ret = asprintf(dir, "%s/%s", tmpdir, tmpname);
712f64ca102SToomas Soome 	if (ret < 0) {
713f64ca102SToomas Soome 		return (BE_ERR_NOMEM);
714f64ca102SToomas Soome 	}
715f64ca102SToomas Soome 	*dir = mkdtemp(*dir);
716f64ca102SToomas Soome 
717f64ca102SToomas Soome 	if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0) {
718f64ca102SToomas Soome 		ret = BE_ERR_NOMEM;
719f64ca102SToomas Soome 		goto out;
720f64ca102SToomas Soome 	}
721f64ca102SToomas Soome 
722*71668a2fSAndy Fiddaman 	ret = be_list(NULL, &be_nodes, BE_LIST_DEFAULT);
723f64ca102SToomas Soome 	if (ret != BE_SUCCESS) {
724f64ca102SToomas Soome 		goto out;
725f64ca102SToomas Soome 	}
726f64ca102SToomas Soome 
727f64ca102SToomas Soome 	for (be_node = be_nodes; be_node;
728f64ca102SToomas Soome 	    be_node = be_node->be_next_node)
729353ca6f2SToomas Soome 		if (strcmp(be_node->be_root_ds, entry->me_bootfs) == 0)
730f64ca102SToomas Soome 			break;
731f64ca102SToomas Soome 
732f64ca102SToomas Soome 	if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
733f64ca102SToomas Soome 	    be_node->be_node_name) != 0) {
734f64ca102SToomas Soome 		ret = BE_ERR_NOMEM;
735f64ca102SToomas Soome 		goto out;
736f64ca102SToomas Soome 	}
737f64ca102SToomas Soome 
738f64ca102SToomas Soome 	if (nvlist_add_string(be_attrs, BE_ATTR_MOUNTPOINT, *dir) != 0) {
739f64ca102SToomas Soome 		ret = BE_ERR_NOMEM;
740f64ca102SToomas Soome 		goto out;
741f64ca102SToomas Soome 	}
742f64ca102SToomas Soome 
743f64ca102SToomas Soome 	ret = be_mount(be_attrs);
744f64ca102SToomas Soome 	if (ret == BE_ERR_MOUNTED) {
745f64ca102SToomas Soome 		/*
746f64ca102SToomas Soome 		 * if BE is mounted, dir does not point to correct directory
747f64ca102SToomas Soome 		 */
748f64ca102SToomas Soome 		(void) rmdir(*dir);
749f64ca102SToomas Soome 		free(*dir);
750f64ca102SToomas Soome 		*dir = NULL;
751f64ca102SToomas Soome 	}
752f64ca102SToomas Soome out:
753f64ca102SToomas Soome 	if (be_nodes != NULL)
754f64ca102SToomas Soome 		be_free_list(be_nodes);
755f64ca102SToomas Soome 	nvlist_free(be_attrs);
756f64ca102SToomas Soome 	return (ret);
757f64ca102SToomas Soome }
758f64ca102SToomas Soome 
759f64ca102SToomas Soome static int
760f64ca102SToomas Soome bam_umount_be(char *dir)
761f64ca102SToomas Soome {
762f64ca102SToomas Soome 	nvlist_t *be_attrs;
763f64ca102SToomas Soome 	int ret;
764f64ca102SToomas Soome 
765f64ca102SToomas Soome 	if (dir == NULL)		/* nothing to do */
766f64ca102SToomas Soome 		return (BE_SUCCESS);
767f64ca102SToomas Soome 
768f64ca102SToomas Soome 	if (nvlist_alloc(&be_attrs, NV_UNIQUE_NAME, 0) != 0)
769f64ca102SToomas Soome 		return (BE_ERR_NOMEM);
770f64ca102SToomas Soome 
771f64ca102SToomas Soome 	if (nvlist_add_string(be_attrs, BE_ATTR_ORIG_BE_NAME, dir) != 0) {
772f64ca102SToomas Soome 		ret = BE_ERR_NOMEM;
773f64ca102SToomas Soome 		goto out;
774f64ca102SToomas Soome 	}
775f64ca102SToomas Soome 
776f64ca102SToomas Soome 	ret = be_unmount(be_attrs);
777f64ca102SToomas Soome out:
778f64ca102SToomas Soome 	nvlist_free(be_attrs);
779f64ca102SToomas Soome 	return (ret);
780f64ca102SToomas Soome }
781f64ca102SToomas Soome 
782f64ca102SToomas Soome /*
783f64ca102SToomas Soome  * display details of menu entry or single property
784f64ca102SToomas Soome  */
785f64ca102SToomas Soome static error_t
786353ca6f2SToomas Soome list_menu_entry(menu_entry_t *entry, char *setting)
787f64ca102SToomas Soome {
788f64ca102SToomas Soome 	int ret = BAM_SUCCESS;
789f64ca102SToomas Soome 	char *ptr, *dir;
790f64ca102SToomas Soome 	char buf[MAX_INPUT];
791f64ca102SToomas Soome 	ficlVm *vm;
792f64ca102SToomas Soome 	int mounted;
793f64ca102SToomas Soome 
794353ca6f2SToomas Soome 	if (strcmp(entry->me_type, "bootfs") != 0 ||
795353ca6f2SToomas Soome 	    strchr(entry->me_bootfs, ':') != NULL) {
796353ca6f2SToomas Soome 		(void) printf("\nTitle:       %s\n", entry->me_title);
797353ca6f2SToomas Soome 		(void) printf("Type:        %s\n", entry->me_type);
798353ca6f2SToomas Soome 		(void) printf("Device:      %s\n", entry->me_bootfs);
799353ca6f2SToomas Soome 		return (ret);
800353ca6f2SToomas Soome 	}
801353ca6f2SToomas Soome 
802f64ca102SToomas Soome 	mounted = bam_mount_be(entry, &dir);
803f64ca102SToomas Soome 	if (mounted != BE_SUCCESS && mounted != BE_ERR_MOUNTED) {
804f64ca102SToomas Soome 		if (dir != NULL) {
805f64ca102SToomas Soome 			(void) rmdir(dir);
806f64ca102SToomas Soome 			free(dir);
807f64ca102SToomas Soome 		}
808353ca6f2SToomas Soome 		bam_error(_("%s is not mounted\n"), entry->me_title);
809f64ca102SToomas Soome 		return (BAM_ERROR);
810f64ca102SToomas Soome 	}
811f64ca102SToomas Soome 
812f64ca102SToomas Soome 	vm = bf_init("", ficlTextOutSilent);
813f64ca102SToomas Soome 	if (vm == NULL) {
814f64ca102SToomas Soome 		bam_error(_("error setting up forth interpreter\n"));
815f64ca102SToomas Soome 		ret = BAM_ERROR;
816f64ca102SToomas Soome 		goto done;
817f64ca102SToomas Soome 	}
818f64ca102SToomas Soome 
819f64ca102SToomas Soome 	/* should only get FICL_VM_STATUS_OUT_OF_TEXT */
820f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:",
821353ca6f2SToomas Soome 	    entry->me_bootfs);
822f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
823f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
824f64ca102SToomas Soome 		bam_error(_("error interpreting boot config\n"));
825f64ca102SToomas Soome 		ret = BAM_ERROR;
826f64ca102SToomas Soome 		goto done;
827f64ca102SToomas Soome 	}
828f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
829f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
830f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
831f64ca102SToomas Soome 		bam_error(_("error interpreting boot config\n"));
832f64ca102SToomas Soome 		ret = BAM_ERROR;
833f64ca102SToomas Soome 		goto done;
834f64ca102SToomas Soome 	}
835f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "start");
836f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
837f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
838f64ca102SToomas Soome 		bam_error(_("error interpreting boot config\n"));
839f64ca102SToomas Soome 		ret = BAM_ERROR;
840f64ca102SToomas Soome 		goto done;
841f64ca102SToomas Soome 	}
842f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "boot");
843f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
844f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
845f64ca102SToomas Soome 		bam_error(_("error interpreting boot config\n"));
846f64ca102SToomas Soome 		ret = BAM_ERROR;
847f64ca102SToomas Soome 		goto done;
848f64ca102SToomas Soome 	}
849f64ca102SToomas Soome 
850f64ca102SToomas Soome 	ret = BAM_SUCCESS;
851f64ca102SToomas Soome 	if (*setting == '\0')
852353ca6f2SToomas Soome 		(void) printf("\nTitle:       %s\n", entry->me_title);
853f64ca102SToomas Soome 	else if (strcasecmp(setting, "title") == 0) {
854353ca6f2SToomas Soome 		(void) printf("%s\n", entry->me_title);
855f64ca102SToomas Soome 		goto done;
856f64ca102SToomas Soome 	}
857f64ca102SToomas Soome 
858f64ca102SToomas Soome 	ptr = getenv("autoboot_delay");
859f64ca102SToomas Soome 	if (ptr != NULL) {
860f64ca102SToomas Soome 		char *timeout = "-1";
861f64ca102SToomas Soome 
862f64ca102SToomas Soome 		if (strcasecmp(ptr, "NO") != 0)
863f64ca102SToomas Soome 			timeout = ptr;
864f64ca102SToomas Soome 
865f64ca102SToomas Soome 		if (*setting == '\0')
866f64ca102SToomas Soome 			(void) printf("Timeout:     %s\n", timeout);
867f64ca102SToomas Soome 		else if (strcasecmp(setting, "timeout") == 0) {
868f64ca102SToomas Soome 			(void) printf("%s\n", timeout);
869f64ca102SToomas Soome 			goto done;
870f64ca102SToomas Soome 		}
871f64ca102SToomas Soome 
872f64ca102SToomas Soome 	}
873f64ca102SToomas Soome 	ptr = getenv("console");
874f64ca102SToomas Soome 	if (ptr != NULL) {
875f64ca102SToomas Soome 		if (*setting == '\0')
876f64ca102SToomas Soome 			(void) printf("Console:     %s\n", ptr);
877f64ca102SToomas Soome 		else if (strcasecmp(setting, "console") == 0) {
878f64ca102SToomas Soome 			(void) printf("%s\n", ptr);
879f64ca102SToomas Soome 			goto done;
880f64ca102SToomas Soome 		}
881f64ca102SToomas Soome 	}
882f64ca102SToomas Soome 
883f64ca102SToomas Soome 	if (*setting == '\0')
884353ca6f2SToomas Soome 		(void) printf("Bootfs:      %s\n", entry->me_bootfs);
885f64ca102SToomas Soome 	else if (strcasecmp(setting, "bootfs") == 0) {
886353ca6f2SToomas Soome 		(void) printf("%s\n", entry->me_bootfs);
887f64ca102SToomas Soome 		goto done;
888f64ca102SToomas Soome 	}
889f64ca102SToomas Soome 
890f64ca102SToomas Soome 	ptr = getenv("xen_kernel");
891f64ca102SToomas Soome 	if (ptr != NULL) {
892f64ca102SToomas Soome 			if (*setting == '\0') {
893f64ca102SToomas Soome 				(void) printf("Xen kernel:  %s\n", ptr);
894f64ca102SToomas Soome 			} else if (strcasecmp(setting, "xen_kernel") == 0) {
895f64ca102SToomas Soome 				(void) printf("%s\n", ptr);
896f64ca102SToomas Soome 				goto done;
897f64ca102SToomas Soome 			}
898f64ca102SToomas Soome 
899f64ca102SToomas Soome 			if (*setting == '\0') {
900f64ca102SToomas Soome 				(void) printf("Xen args:    \"%s\"\n",
901f64ca102SToomas Soome 				    getenv("xen_cmdline"));
902f64ca102SToomas Soome 			} else if (strcasecmp(setting, "xen_cmdline") == 0) {
903f64ca102SToomas Soome 				(void) printf("%s\n", getenv("xen_cmdline"));
904f64ca102SToomas Soome 				goto done;
905f64ca102SToomas Soome 			}
906f64ca102SToomas Soome 
907f64ca102SToomas Soome 			if (*setting == '\0') {
908f64ca102SToomas Soome 				(void) printf("Kernel:      %s\n",
909f64ca102SToomas Soome 				    getenv("bootfile"));
910f64ca102SToomas Soome 			} if (strcasecmp(setting, "kernel") == 0) {
911f64ca102SToomas Soome 				(void) printf("%s\n", getenv("bootfile"));
912f64ca102SToomas Soome 				goto done;
913f64ca102SToomas Soome 			}
914f64ca102SToomas Soome 	} else {
915f64ca102SToomas Soome 		ptr = getenv("kernelname");
916f64ca102SToomas Soome 		if (ptr != NULL) {
917f64ca102SToomas Soome 			if (*setting == '\0') {
918f64ca102SToomas Soome 				(void) printf("Kernel:      %s\n", ptr);
919f64ca102SToomas Soome 			} else if (strcasecmp(setting, "kernel") == 0) {
920f64ca102SToomas Soome 				(void) printf("%s\n", ptr);
921f64ca102SToomas Soome 				goto done;
922f64ca102SToomas Soome 			}
923f64ca102SToomas Soome 		}
924f64ca102SToomas Soome 	}
925f64ca102SToomas Soome 
926f64ca102SToomas Soome 	ptr = getenv("boot-args");
927f64ca102SToomas Soome 	if (ptr != NULL) {
928f64ca102SToomas Soome 		if (*setting == '\0') {
929f64ca102SToomas Soome 			(void) printf("Boot-args:   \"%s\"\n", ptr);
930f64ca102SToomas Soome 		} else if (strcasecmp(setting, "boot-args") == 0) {
931f64ca102SToomas Soome 			(void) printf("%s\n", ptr);
932f64ca102SToomas Soome 			goto done;
933f64ca102SToomas Soome 		}
934f64ca102SToomas Soome 	}
935f64ca102SToomas Soome 
936f64ca102SToomas Soome 	if (*setting == '\0' || strcasecmp(setting, "modules") == 0) {
937f64ca102SToomas Soome 		(void) printf("\nModules:\n");
938f64ca102SToomas Soome 		ficlVmSetTextOut(vm, ficlCallbackDefaultTextOut);
939f64ca102SToomas Soome 		(void) snprintf(buf, MAX_INPUT, "show-module-options");
940f64ca102SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
941f64ca102SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
942f64ca102SToomas Soome 			bam_error(_("error interpreting boot config\n"));
943f64ca102SToomas Soome 			ret = BAM_ERROR;
944f64ca102SToomas Soome 			goto done;
945f64ca102SToomas Soome 		}
946f64ca102SToomas Soome 		ret = BAM_SUCCESS;
947f64ca102SToomas Soome 		goto done;
948f64ca102SToomas Soome 	}
949f64ca102SToomas Soome 
950f64ca102SToomas Soome 	/* if we got here with setting string, its unknown property */
951f64ca102SToomas Soome 	if (*setting != '\0') {
952f64ca102SToomas Soome 		bam_error(_("unknown property: %s\n"), setting);
953f64ca102SToomas Soome 		ret = BAM_ERROR;
954f64ca102SToomas Soome 	} else
955f64ca102SToomas Soome 		ret = BAM_SUCCESS;
956f64ca102SToomas Soome done:
957f64ca102SToomas Soome 	bf_fini();
958f64ca102SToomas Soome 	if (mounted != BE_ERR_MOUNTED) {
959f64ca102SToomas Soome 		(void) bam_umount_be(dir);
960f64ca102SToomas Soome 	}
961f64ca102SToomas Soome 
962f64ca102SToomas Soome 	if (dir != NULL) {
963f64ca102SToomas Soome 		(void) rmdir(dir);
964f64ca102SToomas Soome 		free(dir);
965f64ca102SToomas Soome 	}
966f64ca102SToomas Soome 
967f64ca102SToomas Soome 	return (ret);
968f64ca102SToomas Soome }
969f64ca102SToomas Soome 
970f64ca102SToomas Soome /*ARGSUSED*/
971f64ca102SToomas Soome static error_t
972f64ca102SToomas Soome list_entry(struct menu_lst *menu, char *menu_root, char *opt)
973f64ca102SToomas Soome {
974f64ca102SToomas Soome 	error_t ret = BAM_SUCCESS;
975353ca6f2SToomas Soome 	menu_entry_t *entry;
976f64ca102SToomas Soome 	char *ptr, *title = NULL;
977f64ca102SToomas Soome 	int i, e = -1;
978f64ca102SToomas Soome 
979f64ca102SToomas Soome 	if (opt == NULL) {
980f64ca102SToomas Soome 		print_nodes(B_FALSE, menu);
981f64ca102SToomas Soome 		return (ret);
982f64ca102SToomas Soome 	}
983f64ca102SToomas Soome 
984f64ca102SToomas Soome 	if ((ptr = strchr(opt, '=')) == NULL) {
985f64ca102SToomas Soome 		bam_error(_("invalid option: %s\n"), opt);
986f64ca102SToomas Soome 		return (BAM_ERROR);
987f64ca102SToomas Soome 	}
988f64ca102SToomas Soome 
989f64ca102SToomas Soome 	i = ptr - opt;
990f64ca102SToomas Soome 	if (strncmp(opt, "entry", i) == 0) {
991f64ca102SToomas Soome 		e = atoi(ptr+1);
992f64ca102SToomas Soome 	} else if (strncmp(opt, "title", i) == 0) {
993f64ca102SToomas Soome 		title = ptr+1;
994f64ca102SToomas Soome 	} else {
995f64ca102SToomas Soome 		bam_error(_("invalid option: %s\n"), opt);
996f64ca102SToomas Soome 		return (BAM_ERROR);
997f64ca102SToomas Soome 	}
998f64ca102SToomas Soome 
999353ca6f2SToomas Soome 	STAILQ_FOREACH(entry, menu, me_next) {
1000f64ca102SToomas Soome 		if (title != NULL) {
1001353ca6f2SToomas Soome 			if (strcmp(title, entry->me_title) == 0)
1002f64ca102SToomas Soome 				break;
1003353ca6f2SToomas Soome 		} else if (entry->me_idx == e)
1004f64ca102SToomas Soome 			break;
1005f64ca102SToomas Soome 	}
1006f64ca102SToomas Soome 
1007f64ca102SToomas Soome 	if (entry == NULL) {
1008f64ca102SToomas Soome 		bam_error(_("no matching entry found\n"));
1009f64ca102SToomas Soome 		return (BAM_ERROR);
1010f64ca102SToomas Soome 	}
1011f64ca102SToomas Soome 
1012f64ca102SToomas Soome 	return (list_menu_entry(entry, ""));
1013f64ca102SToomas Soome }
1014f64ca102SToomas Soome 
1015f64ca102SToomas Soome /*
1016f64ca102SToomas Soome  * For now this is just stub entry to support grub interface, the
1017f64ca102SToomas Soome  * known consumer is installer ict.py code, calling as:
1018f64ca102SToomas Soome  * bootadm update-menu -R /a -Z -o rdisk
1019f64ca102SToomas Soome  * Later this can be converted to do something useful.
1020f64ca102SToomas Soome  */
1021f64ca102SToomas Soome /*ARGSUSED*/
1022f64ca102SToomas Soome static error_t
1023f64ca102SToomas Soome update_entry(struct menu_lst *menu, char *menu_root, char *osdev)
1024f64ca102SToomas Soome {
1025f64ca102SToomas Soome 	char path[PATH_MAX];
1026f64ca102SToomas Soome 	char *pool = menu_root + 1;
1027f64ca102SToomas Soome 	be_node_list_t *be_nodes, *be_node;
1028f64ca102SToomas Soome 	int rv;
1029f64ca102SToomas Soome 	FILE *fp;
1030f64ca102SToomas Soome 
1031f64ca102SToomas Soome 	(void) snprintf(path, PATH_MAX, "%s%s", menu_root, MENU);
1032*71668a2fSAndy Fiddaman 	rv = be_list(NULL, &be_nodes, BE_LIST_DEFAULT);
1033f64ca102SToomas Soome 
1034f64ca102SToomas Soome 	if (rv != BE_SUCCESS)
1035f64ca102SToomas Soome 		return (BAM_ERROR);
1036f64ca102SToomas Soome 
1037f64ca102SToomas Soome 	fp = fopen(path, "w");
1038f64ca102SToomas Soome 	if (fp == NULL) {
1039f64ca102SToomas Soome 		be_free_list(be_nodes);
1040f64ca102SToomas Soome 		return (BAM_ERROR);
1041f64ca102SToomas Soome 	}
1042f64ca102SToomas Soome 
1043f64ca102SToomas Soome 	for (be_node = be_nodes; be_node; be_node = be_node->be_next_node) {
1044f64ca102SToomas Soome 		if (strcmp(be_node->be_rpool, pool) == 0) {
1045f64ca102SToomas Soome 			(void) fprintf(fp, "title %s\n", be_node->be_node_name);
1046f64ca102SToomas Soome 			(void) fprintf(fp, "bootfs %s\n", be_node->be_root_ds);
1047f64ca102SToomas Soome 		}
1048f64ca102SToomas Soome 	}
1049f64ca102SToomas Soome 
1050f64ca102SToomas Soome 	be_free_list(be_nodes);
1051f64ca102SToomas Soome 	(void) fclose(fp);
1052f64ca102SToomas Soome 	return (BAM_SUCCESS);
1053f64ca102SToomas Soome }
1054f64ca102SToomas Soome 
1055f64ca102SToomas Soome /*ARGSUSED*/
1056f64ca102SToomas Soome static error_t
1057f64ca102SToomas Soome update_temp(struct menu_lst *menu, char *dummy, char *opt)
1058f64ca102SToomas Soome {
1059f64ca102SToomas Soome 	error_t ret = BAM_ERROR;
1060f64ca102SToomas Soome 	char path[PATH_MAX];
1061f64ca102SToomas Soome 	char buf[MAX_INPUT];
1062f64ca102SToomas Soome 	struct mnttab mpref = { 0 };
1063f64ca102SToomas Soome 	struct mnttab mp = { 0 };
1064f64ca102SToomas Soome 	ficlVm *vm;
1065f64ca102SToomas Soome 	char *env, *o;
1066f64ca102SToomas Soome 	FILE *fp;
1067f64ca102SToomas Soome 
1068f64ca102SToomas Soome 	(void) snprintf(path, PATH_MAX, "%s" TRANSIENT, bam_root);
1069f64ca102SToomas Soome 	/*
1070f64ca102SToomas Soome 	 * if opt == NULL, remove transient config
1071f64ca102SToomas Soome 	 */
1072f64ca102SToomas Soome 	if (opt == NULL) {
1073f64ca102SToomas Soome 		(void) unlink(path);
1074f64ca102SToomas Soome 		return (BAM_SUCCESS);
1075f64ca102SToomas Soome 	}
1076f64ca102SToomas Soome 
1077f64ca102SToomas Soome 	fp = fopen(MNTTAB, "r");
1078f64ca102SToomas Soome 	if (fp == NULL)
1079f64ca102SToomas Soome 		return (BAM_ERROR);
1080f64ca102SToomas Soome 
1081f64ca102SToomas Soome 	mpref.mnt_mountp = "/";
1082f64ca102SToomas Soome 	if (getmntany(fp, &mp, &mpref) != 0) {
1083f64ca102SToomas Soome 		(void) fclose(fp);
1084f64ca102SToomas Soome 		return (BAM_ERROR);
1085f64ca102SToomas Soome 	}
1086f64ca102SToomas Soome 	(void) fclose(fp);
1087f64ca102SToomas Soome 
1088f64ca102SToomas Soome 	vm = bf_init("", ficlTextOutSilent);
1089f64ca102SToomas Soome 	if (vm == NULL) {
1090f64ca102SToomas Soome 		bam_error(_("Error setting up forth interpreter\n"));
1091f64ca102SToomas Soome 		return (ret);
1092f64ca102SToomas Soome 	}
1093f64ca102SToomas Soome 
1094f64ca102SToomas Soome 	/*
1095f64ca102SToomas Soome 	 * need to check current boot config, so fire up the ficl
1096f64ca102SToomas Soome 	 * if its xen setup, we add option to boot-args list, not replacing it.
1097f64ca102SToomas Soome 	 */
1098f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:", mp.mnt_special);
1099f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1100f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1101f64ca102SToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1102f64ca102SToomas Soome 		bf_fini();
1103f64ca102SToomas Soome 		return (BAM_ERROR);
1104f64ca102SToomas Soome 	}
1105f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
1106f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1107f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1108f64ca102SToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1109f64ca102SToomas Soome 		bf_fini();
1110f64ca102SToomas Soome 		return (BAM_ERROR);
1111f64ca102SToomas Soome 	}
1112f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "start");
1113f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1114f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1115f64ca102SToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1116f64ca102SToomas Soome 		bf_fini();
1117f64ca102SToomas Soome 		return (BAM_ERROR);
1118f64ca102SToomas Soome 	}
1119f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "boot");
1120f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1121f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1122f64ca102SToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1123f64ca102SToomas Soome 		bf_fini();
1124f64ca102SToomas Soome 		return (BAM_ERROR);
1125f64ca102SToomas Soome 	}
1126f64ca102SToomas Soome 	bf_fini();
1127f64ca102SToomas Soome 
1128f64ca102SToomas Soome 	if (opt[0] == '-') {
1129f64ca102SToomas Soome 		env = getenv("xen_kernel");
1130f64ca102SToomas Soome 		fp = fopen(path, "w");
1131f64ca102SToomas Soome 		if (fp == NULL)
1132f64ca102SToomas Soome 			return (BAM_ERROR);
1133f64ca102SToomas Soome 
1134f64ca102SToomas Soome 		if (env != NULL) {
1135f64ca102SToomas Soome 			env = getenv("boot-args");
1136f64ca102SToomas Soome 			(void) fprintf(fp, "boot-args=\"%s %s\"\n", env, opt);
1137f64ca102SToomas Soome 		} else
1138f64ca102SToomas Soome 			(void) fprintf(fp, "boot-args=\"%s\"\n", opt);
1139f64ca102SToomas Soome 		(void) fclose(fp);
1140f64ca102SToomas Soome 		return (BAM_SUCCESS);
1141f64ca102SToomas Soome 	}
1142f64ca102SToomas Soome 
1143f64ca102SToomas Soome 	/*
1144f64ca102SToomas Soome 	 * it should be the case with "kernel args"
1145f64ca102SToomas Soome 	 * so, we split the opt at first space
1146f64ca102SToomas Soome 	 * and store bootfile= and boot-args=
1147f64ca102SToomas Soome 	 */
1148f64ca102SToomas Soome 	env = getenv("xen_kernel");
1149f64ca102SToomas Soome 
1150f64ca102SToomas Soome 	o = strchr(opt, ' ');
1151f64ca102SToomas Soome 	if (o == NULL) {
1152f64ca102SToomas Soome 		fp = fopen(path, "w");
1153f64ca102SToomas Soome 		if (fp == NULL)
1154f64ca102SToomas Soome 			return (BAM_ERROR);
1155f64ca102SToomas Soome 		(void) fprintf(fp, "bootfile=\"%s\"\n", opt);
1156f64ca102SToomas Soome 		(void) fclose(fp);
1157f64ca102SToomas Soome 		return (BAM_SUCCESS);
1158f64ca102SToomas Soome 	}
1159f64ca102SToomas Soome 	*o++ = '\0';
1160f64ca102SToomas Soome 	fp = fopen(path, "w");
1161f64ca102SToomas Soome 	if (fp == NULL)
1162f64ca102SToomas Soome 		return (BAM_ERROR);
1163f64ca102SToomas Soome 	(void) fprintf(fp, "bootfile=\"%s\"\n", opt);
1164f64ca102SToomas Soome 
1165f64ca102SToomas Soome 	if (env != NULL) {
1166f64ca102SToomas Soome 		env = getenv("boot-args");
1167f64ca102SToomas Soome 		(void) fprintf(fp, "boot-args=\"%s %s\"\n", env, opt);
1168f64ca102SToomas Soome 	} else
1169f64ca102SToomas Soome 		(void) fprintf(fp, "boot-args=\"%s\"\n", o);
1170f64ca102SToomas Soome 
1171f64ca102SToomas Soome 	(void) fflush(fp);
1172f64ca102SToomas Soome 	(void) fclose(fp);
1173f64ca102SToomas Soome 	return (ret);
1174f64ca102SToomas Soome }
1175f64ca102SToomas Soome 
1176f64ca102SToomas Soome static error_t
1177f64ca102SToomas Soome list_setting(struct menu_lst *menu, char *which, char *setting)
1178f64ca102SToomas Soome {
1179f64ca102SToomas Soome 	int entry = -1;
1180353ca6f2SToomas Soome 	menu_entry_t *m;
1181f64ca102SToomas Soome 	be_node_list_t *be_nodes, *be_node = NULL;
1182f64ca102SToomas Soome 	int ret;
1183f64ca102SToomas Soome 
1184f64ca102SToomas Soome 	assert(which);
1185f64ca102SToomas Soome 	assert(setting);
1186f64ca102SToomas Soome 
1187f64ca102SToomas Soome 	/*
1188f64ca102SToomas Soome 	 * which can be:
1189f64ca102SToomas Soome 	 * "" - list default entry
1190f64ca102SToomas Soome 	 * number - use for entry number
1191f64ca102SToomas Soome 	 * property name
1192f64ca102SToomas Soome 	 */
1193f64ca102SToomas Soome 	if (*which != '\0') {
1194f64ca102SToomas Soome 		if (isdigit(*which)) {
1195f64ca102SToomas Soome 			char *rest;
1196f64ca102SToomas Soome 			errno = 0;
1197f64ca102SToomas Soome 			entry = strtol(which, &rest, 10);
1198f64ca102SToomas Soome 			if (errno != 0 || *rest != '\0') {
1199f64ca102SToomas Soome 				bam_error(_("invalid boot entry number: %s\n"),
1200f64ca102SToomas Soome 				    which);
1201f64ca102SToomas Soome 				return (BAM_ERROR);
1202f64ca102SToomas Soome 			}
1203f64ca102SToomas Soome 		} else
1204f64ca102SToomas Soome 			setting = which;
1205f64ca102SToomas Soome 	}
1206f64ca102SToomas Soome 
1207f64ca102SToomas Soome 	/* find default entry */
1208f64ca102SToomas Soome 	if (entry == -1) {
1209*71668a2fSAndy Fiddaman 		ret = be_list(NULL, &be_nodes, BE_LIST_DEFAULT);
1210f64ca102SToomas Soome 		if (ret != BE_SUCCESS) {
1211f64ca102SToomas Soome 			bam_error(_("No BE's found\n"));
1212f64ca102SToomas Soome 			return (BAM_ERROR);
1213f64ca102SToomas Soome 		}
1214353ca6f2SToomas Soome 		STAILQ_FOREACH(m, menu, me_next) {
1215f64ca102SToomas Soome 			entry++;
1216f64ca102SToomas Soome 			for (be_node = be_nodes; be_node;
1217353ca6f2SToomas Soome 			    be_node = be_node->be_next_node) {
1218353ca6f2SToomas Soome 				if (strcmp(be_node->be_root_ds,
1219353ca6f2SToomas Soome 				    m->me_bootfs) == 0)
1220f64ca102SToomas Soome 					break;
1221353ca6f2SToomas Soome 			}
1222353ca6f2SToomas Soome 			if (be_node != NULL &&
1223353ca6f2SToomas Soome 			    be_node->be_active_on_boot == B_TRUE)
1224f64ca102SToomas Soome 				break; /* found active node */
1225f64ca102SToomas Soome 		}
1226f64ca102SToomas Soome 		be_free_list(be_nodes);
1227f64ca102SToomas Soome 		if (be_node == NULL) {
1228f64ca102SToomas Soome 			bam_error(_("None of BE nodes is marked active\n"));
1229f64ca102SToomas Soome 			return (BAM_ERROR);
1230f64ca102SToomas Soome 		}
1231f64ca102SToomas Soome 	} else {
1232353ca6f2SToomas Soome 		STAILQ_FOREACH(m, menu, me_next)
1233353ca6f2SToomas Soome 			if (m->me_idx == entry)
1234f64ca102SToomas Soome 				break;
1235f64ca102SToomas Soome 
1236f64ca102SToomas Soome 		if (m == NULL) {
1237f64ca102SToomas Soome 			bam_error(_("no matching entry found\n"));
1238f64ca102SToomas Soome 			return (BAM_ERROR);
1239f64ca102SToomas Soome 		}
1240f64ca102SToomas Soome 	}
1241f64ca102SToomas Soome 
1242f64ca102SToomas Soome 	return (list_menu_entry(m, setting));
1243f64ca102SToomas Soome }
1244f64ca102SToomas Soome 
1245f64ca102SToomas Soome /*ARGSUSED*/
1246f64ca102SToomas Soome static error_t
1247f64ca102SToomas Soome disable_hyper(struct menu_lst *menu, char *osroot, char *opt)
1248f64ca102SToomas Soome {
1249f64ca102SToomas Soome 	char path[PATH_MAX];
1250f64ca102SToomas Soome 
1251f64ca102SToomas Soome 	(void) snprintf(path, PATH_MAX, "%s" XEN_CONFIG, bam_root);
1252f64ca102SToomas Soome 	(void) unlink(path);
1253f64ca102SToomas Soome 	return (BAM_SUCCESS);
1254f64ca102SToomas Soome }
1255f64ca102SToomas Soome 
1256f64ca102SToomas Soome /*ARGSUSED*/
1257f64ca102SToomas Soome static error_t
1258f64ca102SToomas Soome enable_hyper(struct menu_lst *menu, char *osroot, char *opt)
1259f64ca102SToomas Soome {
1260f64ca102SToomas Soome 	ficlVm *vm;
1261f64ca102SToomas Soome 	char path[PATH_MAX];
1262f64ca102SToomas Soome 	char buf[MAX_INPUT];
1263f64ca102SToomas Soome 	char *env;
1264f64ca102SToomas Soome 	FILE *fp;
1265f64ca102SToomas Soome 	struct mnttab mpref = { 0 };
1266f64ca102SToomas Soome 	struct mnttab mp = { 0 };
1267f64ca102SToomas Soome 	int ret;
1268f64ca102SToomas Soome 
1269f64ca102SToomas Soome 	fp = fopen(MNTTAB, "r");
1270f64ca102SToomas Soome 	if (fp == NULL)
1271f64ca102SToomas Soome 		return (BAM_ERROR);
1272f64ca102SToomas Soome 
1273f64ca102SToomas Soome 	mpref.mnt_mountp = "/";
1274f64ca102SToomas Soome 	if (getmntany(fp, &mp, &mpref) != 0) {
1275f64ca102SToomas Soome 		(void) fclose(fp);
1276f64ca102SToomas Soome 		return (BAM_ERROR);
1277f64ca102SToomas Soome 	}
1278f64ca102SToomas Soome 	(void) fclose(fp);
1279f64ca102SToomas Soome 
1280f64ca102SToomas Soome 	vm = bf_init("", ficlTextOutSilent);
1281f64ca102SToomas Soome 	if (vm == NULL) {
1282f64ca102SToomas Soome 		bam_error(_("Error setting up forth interpreter\n"));
1283f64ca102SToomas Soome 		return (BAM_ERROR);
1284f64ca102SToomas Soome 	}
1285f64ca102SToomas Soome 
1286f64ca102SToomas Soome 	/*
1287f64ca102SToomas Soome 	 * need to check current boot config, so fire up the ficl
1288f64ca102SToomas Soome 	 * if its xen setup, we add option to boot-args list, not replacing it.
1289f64ca102SToomas Soome 	 */
1290f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:", mp.mnt_special);
1291f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1292f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1293f64ca102SToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1294f64ca102SToomas Soome 		bf_fini();
1295f64ca102SToomas Soome 		return (BAM_ERROR);
1296f64ca102SToomas Soome 	}
1297f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
1298f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1299f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1300f64ca102SToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1301f64ca102SToomas Soome 		bf_fini();
1302f64ca102SToomas Soome 		return (BAM_ERROR);
1303f64ca102SToomas Soome 	}
1304f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "start");
1305f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1306f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1307f64ca102SToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1308f64ca102SToomas Soome 		bf_fini();
1309f64ca102SToomas Soome 		return (BAM_ERROR);
1310f64ca102SToomas Soome 	}
1311f64ca102SToomas Soome 	(void) snprintf(buf, MAX_INPUT, "boot");
1312f64ca102SToomas Soome 	ret = ficlVmEvaluate(vm, buf);
1313f64ca102SToomas Soome 	if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1314f64ca102SToomas Soome 		bam_error(_("Error interpreting boot config\n"));
1315f64ca102SToomas Soome 		bf_fini();
1316f64ca102SToomas Soome 		return (BAM_ERROR);
1317f64ca102SToomas Soome 	}
1318f64ca102SToomas Soome 	bf_fini();
1319f64ca102SToomas Soome 
1320f64ca102SToomas Soome 	(void) mkdir(CONF_DIR, 0755);
1321f64ca102SToomas Soome 	(void) snprintf(path, PATH_MAX, "%s" XEN_CONFIG, bam_root);
1322f64ca102SToomas Soome 	fp = fopen(path, "w");
1323f64ca102SToomas Soome 	if (fp == NULL) {
1324f64ca102SToomas Soome 		return (BAM_ERROR);	/* error, cant write config */
1325f64ca102SToomas Soome 	}
1326f64ca102SToomas Soome 
1327f64ca102SToomas Soome 	errno = 0;
1328f64ca102SToomas Soome 	/*
1329f64ca102SToomas Soome 	 * on write error, remove file to ensure we have bootable config.
1330f64ca102SToomas Soome 	 * note we dont mind if config exists, it will get updated
1331f64ca102SToomas Soome 	 */
1332f64ca102SToomas Soome 	(void) fprintf(fp, "xen_kernel=\"/boot/${ISADIR}/xen\"\n");
1333f64ca102SToomas Soome 	if (errno != 0)
1334f64ca102SToomas Soome 		goto error;
1335f64ca102SToomas Soome 
1336f64ca102SToomas Soome 	/*
1337f64ca102SToomas Soome 	 * really simple and stupid console conversion.
1338f64ca102SToomas Soome 	 * it really has to be gone, it belongs to milestone/xvm properties.
1339f64ca102SToomas Soome 	 */
1340f64ca102SToomas Soome 	env = getenv("console");
1341f64ca102SToomas Soome 	if (env != NULL) {
1342f64ca102SToomas Soome 		if (strcmp(env, "ttya") == 0)
1343f64ca102SToomas Soome 			(void) fprintf(fp, "xen_cmdline=\"console=com1 %s\"\n",
1344f64ca102SToomas Soome 			    opt);
1345f64ca102SToomas Soome 		else if (strcmp(env, "ttyb") == 0)
1346f64ca102SToomas Soome 			(void) fprintf(fp, "xen_cmdline=\"console=com2 %s\"\n",
1347f64ca102SToomas Soome 			    opt);
1348f64ca102SToomas Soome 		else
1349f64ca102SToomas Soome 			(void) fprintf(fp, "xen_cmdline=\"console=vga %s\"\n",
1350f64ca102SToomas Soome 			    opt);
1351f64ca102SToomas Soome 	} else
1352f64ca102SToomas Soome 		(void) fprintf(fp, "xen_cmdline=\"%s\"\n", opt);
1353f64ca102SToomas Soome 	if (errno != 0)
1354f64ca102SToomas Soome 		goto error;
1355f64ca102SToomas Soome 
1356f64ca102SToomas Soome 	(void) fprintf(fp,
1357f64ca102SToomas Soome 	    "bootfile=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1358f64ca102SToomas Soome 	if (errno != 0)
1359f64ca102SToomas Soome 		goto error;
1360f64ca102SToomas Soome 
1361f64ca102SToomas Soome 	(void) fprintf(fp,
1362f64ca102SToomas Soome 	    "boot-args=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1363f64ca102SToomas Soome 	if (errno != 0)
1364f64ca102SToomas Soome 		goto error;
1365f64ca102SToomas Soome 
1366f64ca102SToomas Soome 	(void) fclose(fp);
1367f64ca102SToomas Soome 	if (errno != 0) {
1368f64ca102SToomas Soome 		(void) unlink(path);
1369f64ca102SToomas Soome 		return (BAM_ERROR);
1370f64ca102SToomas Soome 	}
1371f64ca102SToomas Soome 	return (BAM_SUCCESS);
1372f64ca102SToomas Soome error:
1373f64ca102SToomas Soome 	(void) fclose(fp);
1374f64ca102SToomas Soome 	(void) unlink(path);
1375f64ca102SToomas Soome 	return (BAM_ERROR);
1376f64ca102SToomas Soome }
1377