xref: /illumos-gate/usr/src/lib/libbe/common/be_utils.c (revision a897f28b)
1f169c0eaSGlenn Lagasse /*
2f169c0eaSGlenn Lagasse  * CDDL HEADER START
3f169c0eaSGlenn Lagasse  *
4f169c0eaSGlenn Lagasse  * The contents of this file are subject to the terms of the
5f169c0eaSGlenn Lagasse  * Common Development and Distribution License (the "License").
6f169c0eaSGlenn Lagasse  * You may not use this file except in compliance with the License.
7f169c0eaSGlenn Lagasse  *
8f169c0eaSGlenn Lagasse  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f169c0eaSGlenn Lagasse  * or http://www.opensolaris.org/os/licensing.
10f169c0eaSGlenn Lagasse  * See the License for the specific language governing permissions
11f169c0eaSGlenn Lagasse  * and limitations under the License.
12f169c0eaSGlenn Lagasse  *
13f169c0eaSGlenn Lagasse  * When distributing Covered Code, include this CDDL HEADER in each
14f169c0eaSGlenn Lagasse  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f169c0eaSGlenn Lagasse  * If applicable, add the following below this CDDL HEADER, with the
16f169c0eaSGlenn Lagasse  * fields enclosed by brackets "[]" replaced with your own identifying
17f169c0eaSGlenn Lagasse  * information: Portions Copyright [yyyy] [name of copyright owner]
18f169c0eaSGlenn Lagasse  *
19f169c0eaSGlenn Lagasse  * CDDL HEADER END
20f169c0eaSGlenn Lagasse  */
21f169c0eaSGlenn Lagasse 
22f169c0eaSGlenn Lagasse /*
23f169c0eaSGlenn Lagasse  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
247e0e2549SAlexander Eremin  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
25f5e5a2c4SToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
269adfa60dSMatthew Ahrens  * Copyright (c) 2015 by Delphix. All rights reserved.
27*a897f28bSAndy Fiddaman  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
286b1d07a4SAlexander Eremin  */
296b1d07a4SAlexander Eremin 
306b1d07a4SAlexander Eremin 
31f169c0eaSGlenn Lagasse /*
32f169c0eaSGlenn Lagasse  * System includes
33f169c0eaSGlenn Lagasse  */
34f169c0eaSGlenn Lagasse #include <assert.h>
35f169c0eaSGlenn Lagasse #include <errno.h>
36f169c0eaSGlenn Lagasse #include <libgen.h>
37f169c0eaSGlenn Lagasse #include <libintl.h>
38f169c0eaSGlenn Lagasse #include <libnvpair.h>
39f169c0eaSGlenn Lagasse #include <libzfs.h>
40f169c0eaSGlenn Lagasse #include <libgen.h>
41f169c0eaSGlenn Lagasse #include <stdio.h>
42f169c0eaSGlenn Lagasse #include <stdlib.h>
43f169c0eaSGlenn Lagasse #include <string.h>
44f169c0eaSGlenn Lagasse #include <sys/stat.h>
45f169c0eaSGlenn Lagasse #include <sys/types.h>
46f169c0eaSGlenn Lagasse #include <sys/vfstab.h>
47f169c0eaSGlenn Lagasse #include <sys/param.h>
48f169c0eaSGlenn Lagasse #include <sys/systeminfo.h>
49f169c0eaSGlenn Lagasse #include <ctype.h>
50f169c0eaSGlenn Lagasse #include <time.h>
51f169c0eaSGlenn Lagasse #include <unistd.h>
52f169c0eaSGlenn Lagasse #include <fcntl.h>
53de1ab35cSAlexander Eremin #include <deflt.h>
54f169c0eaSGlenn Lagasse #include <wait.h>
556b1d07a4SAlexander Eremin #include <libdevinfo.h>
567e0e2549SAlexander Eremin #include <libgen.h>
57f169c0eaSGlenn Lagasse 
58f169c0eaSGlenn Lagasse #include <libbe.h>
59f169c0eaSGlenn Lagasse #include <libbe_priv.h>
60a63c99a2SToomas Soome #include <boot_utils.h>
61f5e5a2c4SToomas Soome #include <ficl.h>
62f5e5a2c4SToomas Soome #include <ficlplatform/emu.h>
63f169c0eaSGlenn Lagasse 
64f169c0eaSGlenn Lagasse /* Private function prototypes */
65f169c0eaSGlenn Lagasse static int update_dataset(char *, int, char *, char *, char *);
66f169c0eaSGlenn Lagasse static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *);
67de1ab35cSAlexander Eremin static int be_open_menu(char *, char *, FILE **, char *, boolean_t);
68de1ab35cSAlexander Eremin static int be_create_menu(char *, char *, FILE **, char *);
69f169c0eaSGlenn Lagasse static char *be_get_auto_name(char *, char *, boolean_t);
70f169c0eaSGlenn Lagasse 
71f169c0eaSGlenn Lagasse /*
72f169c0eaSGlenn Lagasse  * Global error printing
73f169c0eaSGlenn Lagasse  */
74f169c0eaSGlenn Lagasse boolean_t do_print = B_FALSE;
75f169c0eaSGlenn Lagasse 
76f169c0eaSGlenn Lagasse /*
77f169c0eaSGlenn Lagasse  * Private datatypes
78f169c0eaSGlenn Lagasse  */
79f169c0eaSGlenn Lagasse typedef struct zone_be_name_cb_data {
80f169c0eaSGlenn Lagasse 	char *base_be_name;
81f169c0eaSGlenn Lagasse 	int num;
82f169c0eaSGlenn Lagasse } zone_be_name_cb_data_t;
83f169c0eaSGlenn Lagasse 
84f169c0eaSGlenn Lagasse /* ********************************************************************	*/
85f169c0eaSGlenn Lagasse /*			Public Functions				*/
86f169c0eaSGlenn Lagasse /* ******************************************************************** */
87f169c0eaSGlenn Lagasse 
88f5e5a2c4SToomas Soome /*
89f5e5a2c4SToomas Soome  * Callback for ficl to suppress all output from ficl, as we do not
90f5e5a2c4SToomas Soome  * want to confuse user with messages from ficl, and we are only
91f5e5a2c4SToomas Soome  * checking results from function calls.
92f5e5a2c4SToomas Soome  */
93f5e5a2c4SToomas Soome /*ARGSUSED*/
94f5e5a2c4SToomas Soome static void
95f5e5a2c4SToomas Soome ficlSuppressTextOutput(ficlCallback *cb, char *text)
96f5e5a2c4SToomas Soome {
97f5e5a2c4SToomas Soome 	/* This function is intentionally doing nothing. */
98f5e5a2c4SToomas Soome }
99f5e5a2c4SToomas Soome 
100f5e5a2c4SToomas Soome /*
101f5e5a2c4SToomas Soome  * Function:	be_get_boot_args
102f5e5a2c4SToomas Soome  * Description:	Returns the fast boot argument string for enumerated BE.
103f5e5a2c4SToomas Soome  * Parameters:
104f5e5a2c4SToomas Soome  *		fbarg - pointer to argument string.
105f5e5a2c4SToomas Soome  *		entry - index of BE.
106f5e5a2c4SToomas Soome  * Returns:
107f5e5a2c4SToomas Soome  *		fast boot argument string.
108f5e5a2c4SToomas Soome  * Scope:
109f5e5a2c4SToomas Soome  *		Public
110f5e5a2c4SToomas Soome  */
111f5e5a2c4SToomas Soome int
112f5e5a2c4SToomas Soome be_get_boot_args(char **fbarg, int entry)
113f5e5a2c4SToomas Soome {
114f5e5a2c4SToomas Soome 	be_node_list_t *node, *be_nodes = NULL;
115f5e5a2c4SToomas Soome 	be_transaction_data_t bt = {0};
116f5e5a2c4SToomas Soome 	char *mountpoint = NULL;
117f5e5a2c4SToomas Soome 	boolean_t be_mounted = B_FALSE;
118f5e5a2c4SToomas Soome 	int ret = BE_SUCCESS;
119f5e5a2c4SToomas Soome 	int index;
120f5e5a2c4SToomas Soome 	ficlVm *vm;
121f5e5a2c4SToomas Soome 
122f5e5a2c4SToomas Soome 	*fbarg = NULL;
123f5e5a2c4SToomas Soome 	if (!be_zfs_init())
124f5e5a2c4SToomas Soome 		return (BE_ERR_INIT);
125f5e5a2c4SToomas Soome 
126f5e5a2c4SToomas Soome 	/*
127f5e5a2c4SToomas Soome 	 * need pool name, menu.lst has entries from our pool only
128f5e5a2c4SToomas Soome 	 */
129f5e5a2c4SToomas Soome 	ret = be_find_current_be(&bt);
130f5e5a2c4SToomas Soome 	if (ret != BE_SUCCESS) {
131f5e5a2c4SToomas Soome 		be_zfs_fini();
132f5e5a2c4SToomas Soome 		return (ret);
133f5e5a2c4SToomas Soome 	}
134f5e5a2c4SToomas Soome 
135f5e5a2c4SToomas Soome 	/*
136f5e5a2c4SToomas Soome 	 * be_get_boot_args() is for loader, fail with grub will trigger
137f5e5a2c4SToomas Soome 	 * normal boot.
138f5e5a2c4SToomas Soome 	 */
139f5e5a2c4SToomas Soome 	if (be_has_grub()) {
140f5e5a2c4SToomas Soome 		ret = BE_ERR_INIT;
141f5e5a2c4SToomas Soome 		goto done;
142f5e5a2c4SToomas Soome 	}
143f5e5a2c4SToomas Soome 
144*a897f28bSAndy Fiddaman 	ret = _be_list(NULL, &be_nodes, BE_LIST_DEFAULT);
145f5e5a2c4SToomas Soome 	if (ret != BE_SUCCESS)
146f5e5a2c4SToomas Soome 		goto done;
147f5e5a2c4SToomas Soome 
148f5e5a2c4SToomas Soome 	/*
149f5e5a2c4SToomas Soome 	 * iterate through be_nodes,
150f5e5a2c4SToomas Soome 	 * if entry == -1, stop if be_active_on_boot,
151f5e5a2c4SToomas Soome 	 * else stop if index == entry.
152f5e5a2c4SToomas Soome 	 */
153f5e5a2c4SToomas Soome 	index = 0;
154f5e5a2c4SToomas Soome 	for (node = be_nodes; node != NULL; node = node->be_next_node) {
155f5e5a2c4SToomas Soome 		if (strcmp(node->be_rpool, bt.obe_zpool) != 0)
156f5e5a2c4SToomas Soome 			continue;
157f5e5a2c4SToomas Soome 		if (entry == BE_ENTRY_DEFAULT &&
158f5e5a2c4SToomas Soome 		    node->be_active_on_boot == B_TRUE)
159f5e5a2c4SToomas Soome 			break;
160f5e5a2c4SToomas Soome 		if (index == entry)
161f5e5a2c4SToomas Soome 			break;
162f5e5a2c4SToomas Soome 		index++;
163f5e5a2c4SToomas Soome 	}
164f5e5a2c4SToomas Soome 	if (node == NULL) {
165f5e5a2c4SToomas Soome 		be_free_list(be_nodes);
166f5e5a2c4SToomas Soome 		ret = BE_ERR_NOENT;
167f5e5a2c4SToomas Soome 		goto done;
168f5e5a2c4SToomas Soome 	}
169f5e5a2c4SToomas Soome 
170f5e5a2c4SToomas Soome 	/* try to mount inactive be */
171f5e5a2c4SToomas Soome 	if (node->be_active == B_FALSE) {
172f5e5a2c4SToomas Soome 		ret = _be_mount(node->be_node_name, &mountpoint,
173f5e5a2c4SToomas Soome 		    BE_MOUNT_FLAG_NO_ZONES);
174f5e5a2c4SToomas Soome 		if (ret != BE_SUCCESS && ret != BE_ERR_MOUNTED) {
175f5e5a2c4SToomas Soome 			be_free_list(be_nodes);
176f5e5a2c4SToomas Soome 			goto done;
177f5e5a2c4SToomas Soome 		} else
178f5e5a2c4SToomas Soome 			be_mounted = B_TRUE;
179f5e5a2c4SToomas Soome 	}
180f5e5a2c4SToomas Soome 
181f5e5a2c4SToomas Soome 	vm = bf_init("", ficlSuppressTextOutput);
182f5e5a2c4SToomas Soome 	if (vm != NULL) {
183f5e5a2c4SToomas Soome 		/*
184f5e5a2c4SToomas Soome 		 * zfs MAXNAMELEN is 256, so we need to pick buf large enough
185f5e5a2c4SToomas Soome 		 * to contain such names.
186f5e5a2c4SToomas Soome 		 */
187f5e5a2c4SToomas Soome 		char buf[MAXNAMELEN * 2];
188f5e5a2c4SToomas Soome 		char *kernel_options = NULL;
189f5e5a2c4SToomas Soome 		char *kernel = NULL;
190f5e5a2c4SToomas Soome 		char *tmp;
191f5e5a2c4SToomas Soome 		zpool_handle_t *zph;
192f5e5a2c4SToomas Soome 
193f5e5a2c4SToomas Soome 		/*
194f5e5a2c4SToomas Soome 		 * just try to interpret following words. on error
195f5e5a2c4SToomas Soome 		 * we will be missing kernelname, and will get out.
196f5e5a2c4SToomas Soome 		 */
197f5e5a2c4SToomas Soome 		(void) snprintf(buf, sizeof (buf), "set currdev=zfs:%s:",
198f5e5a2c4SToomas Soome 		    node->be_root_ds);
199f5e5a2c4SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
200f5e5a2c4SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
201f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: error "
202f5e5a2c4SToomas Soome 			    "interpreting boot config: %d\n"), ret);
203f5e5a2c4SToomas Soome 			bf_fini();
204f5e5a2c4SToomas Soome 			ret = BE_ERR_NO_MENU;
205f5e5a2c4SToomas Soome 			goto cleanup;
206f5e5a2c4SToomas Soome 		}
207f5e5a2c4SToomas Soome 		(void) snprintf(buf, sizeof (buf),
208f5e5a2c4SToomas Soome 		    "include /boot/forth/loader.4th");
209f5e5a2c4SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
210f5e5a2c4SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
211f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: error "
212f5e5a2c4SToomas Soome 			    "interpreting boot config: %d\n"), ret);
213f5e5a2c4SToomas Soome 			bf_fini();
214f5e5a2c4SToomas Soome 			ret = BE_ERR_NO_MENU;
215f5e5a2c4SToomas Soome 			goto cleanup;
216f5e5a2c4SToomas Soome 		}
217f5e5a2c4SToomas Soome 		(void) snprintf(buf, sizeof (buf), "start");
218f5e5a2c4SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
219f5e5a2c4SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
220f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: error "
221f5e5a2c4SToomas Soome 			    "interpreting boot config: %d\n"), ret);
222f5e5a2c4SToomas Soome 			bf_fini();
223f5e5a2c4SToomas Soome 			ret = BE_ERR_NO_MENU;
224f5e5a2c4SToomas Soome 			goto cleanup;
225f5e5a2c4SToomas Soome 		}
226f5e5a2c4SToomas Soome 		(void) snprintf(buf, sizeof (buf), "boot");
227f5e5a2c4SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
228f5e5a2c4SToomas Soome 		bf_fini();
229f5e5a2c4SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
230f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: error "
231f5e5a2c4SToomas Soome 			    "interpreting boot config: %d\n"), ret);
232f5e5a2c4SToomas Soome 			ret = BE_ERR_NO_MENU;
233f5e5a2c4SToomas Soome 			goto cleanup;
234f5e5a2c4SToomas Soome 		}
235f5e5a2c4SToomas Soome 
236f5e5a2c4SToomas Soome 		kernel_options = getenv("boot-args");
237f5e5a2c4SToomas Soome 		kernel = getenv("kernelname");
238f5e5a2c4SToomas Soome 
239f5e5a2c4SToomas Soome 		if (kernel == NULL) {
240f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: no kernel\n"));
241f5e5a2c4SToomas Soome 			ret = BE_ERR_NOENT;
242f5e5a2c4SToomas Soome 			goto cleanup;
243f5e5a2c4SToomas Soome 		}
244f5e5a2c4SToomas Soome 
245f5e5a2c4SToomas Soome 		if ((zph = zpool_open(g_zfs, node->be_rpool)) == NULL) {
246f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: failed to "
247f5e5a2c4SToomas Soome 			    "open root pool (%s): %s\n"), node->be_rpool,
248f5e5a2c4SToomas Soome 			    libzfs_error_description(g_zfs));
249f5e5a2c4SToomas Soome 			ret = zfs_err_to_be_err(g_zfs);
250f5e5a2c4SToomas Soome 			goto cleanup;
251f5e5a2c4SToomas Soome 		}
252f5e5a2c4SToomas Soome 		ret = zpool_get_physpath(zph, buf, sizeof (buf));
253f5e5a2c4SToomas Soome 		zpool_close(zph);
254f5e5a2c4SToomas Soome 		if (ret != 0) {
255f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: failed to "
256f5e5a2c4SToomas Soome 			    "get physpath\n"));
257f5e5a2c4SToomas Soome 			goto cleanup;
258f5e5a2c4SToomas Soome 		}
259f5e5a2c4SToomas Soome 
260f5e5a2c4SToomas Soome 		/* zpool_get_physpath() can return space separated list */
261f5e5a2c4SToomas Soome 		tmp = buf;
262f5e5a2c4SToomas Soome 		tmp = strsep(&tmp, " ");
263f5e5a2c4SToomas Soome 
264f5e5a2c4SToomas Soome 		if (kernel_options == NULL || *kernel_options == '\0')
265f5e5a2c4SToomas Soome 			(void) asprintf(fbarg, "/ %s "
266f5e5a2c4SToomas Soome 			    "-B zfs-bootfs=%s,bootpath=\"%s\"\n", kernel,
267f5e5a2c4SToomas Soome 			    node->be_root_ds, tmp);
268f5e5a2c4SToomas Soome 		else
269f5e5a2c4SToomas Soome 			(void) asprintf(fbarg, "/ %s %s "
270f5e5a2c4SToomas Soome 			    "-B zfs-bootfs=%s,bootpath=\"%s\"\n", kernel,
271f5e5a2c4SToomas Soome 			    kernel_options, node->be_root_ds, tmp);
272f5e5a2c4SToomas Soome 
273f5e5a2c4SToomas Soome 		if (fbarg == NULL)
274f5e5a2c4SToomas Soome 			ret = BE_ERR_NOMEM;
275f5e5a2c4SToomas Soome 		else
276f5e5a2c4SToomas Soome 			ret = 0;
277f5e5a2c4SToomas Soome 	} else
278f5e5a2c4SToomas Soome 		ret = BE_ERR_NOMEM;
279f5e5a2c4SToomas Soome cleanup:
280f5e5a2c4SToomas Soome 	if (be_mounted == B_TRUE)
281f5e5a2c4SToomas Soome 		(void) _be_unmount(node->be_node_name, BE_UNMOUNT_FLAG_FORCE);
282f5e5a2c4SToomas Soome 	be_free_list(be_nodes);
283f5e5a2c4SToomas Soome done:
284f5e5a2c4SToomas Soome 	free(mountpoint);
285f5e5a2c4SToomas Soome 	free(bt.obe_name);
286f5e5a2c4SToomas Soome 	free(bt.obe_root_ds);
287f5e5a2c4SToomas Soome 	free(bt.obe_zpool);
288f5e5a2c4SToomas Soome 	free(bt.obe_snap_name);
289f5e5a2c4SToomas Soome 	free(bt.obe_altroot);
290f5e5a2c4SToomas Soome 	be_zfs_fini();
291f5e5a2c4SToomas Soome 	return (ret);
292f5e5a2c4SToomas Soome }
293f5e5a2c4SToomas Soome 
294f169c0eaSGlenn Lagasse /*
295f169c0eaSGlenn Lagasse  * Function:	be_max_avail
296f169c0eaSGlenn Lagasse  * Description:	Returns the available size for the zfs dataset passed in.
297f169c0eaSGlenn Lagasse  * Parameters:
298f169c0eaSGlenn Lagasse  *		dataset - The dataset we want to get the available space for.
299f169c0eaSGlenn Lagasse  *		ret - The available size will be returned in this.
300f169c0eaSGlenn Lagasse  * Returns:
301f169c0eaSGlenn Lagasse  *		The error returned by the zfs get property function.
302f169c0eaSGlenn Lagasse  * Scope:
303f169c0eaSGlenn Lagasse  *		Public
304f169c0eaSGlenn Lagasse  */
305f169c0eaSGlenn Lagasse int
306f169c0eaSGlenn Lagasse be_max_avail(char *dataset, uint64_t *ret)
307f169c0eaSGlenn Lagasse {
308f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp;
309f169c0eaSGlenn Lagasse 	int err = 0;
310f169c0eaSGlenn Lagasse 
311f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
312f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
313f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
314f169c0eaSGlenn Lagasse 
315f169c0eaSGlenn Lagasse 	zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET);
316f169c0eaSGlenn Lagasse 	if (zhp == NULL) {
317f169c0eaSGlenn Lagasse 		/*
318f169c0eaSGlenn Lagasse 		 * The zfs_open failed return an error
319f169c0eaSGlenn Lagasse 		 */
320f169c0eaSGlenn Lagasse 		err = zfs_err_to_be_err(g_zfs);
321f169c0eaSGlenn Lagasse 	} else {
322f169c0eaSGlenn Lagasse 		err = be_maxsize_avail(zhp, ret);
323f169c0eaSGlenn Lagasse 	}
324f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
325f169c0eaSGlenn Lagasse 	be_zfs_fini();
326f169c0eaSGlenn Lagasse 	return (err);
327f169c0eaSGlenn Lagasse }
328f169c0eaSGlenn Lagasse 
329f169c0eaSGlenn Lagasse /*
330f169c0eaSGlenn Lagasse  * Function:	libbe_print_errors
331f169c0eaSGlenn Lagasse  * Description:	Turns on/off error output for the library.
332f169c0eaSGlenn Lagasse  * Parameter:
333f169c0eaSGlenn Lagasse  *		set_do_print - Boolean that turns library error
334f169c0eaSGlenn Lagasse  *			       printing on or off.
335f169c0eaSGlenn Lagasse  * Returns:
336f169c0eaSGlenn Lagasse  *		None
337f169c0eaSGlenn Lagasse  * Scope:
338f169c0eaSGlenn Lagasse  *		Public;
339f169c0eaSGlenn Lagasse  */
340f169c0eaSGlenn Lagasse void
341f169c0eaSGlenn Lagasse libbe_print_errors(boolean_t set_do_print)
342f169c0eaSGlenn Lagasse {
343f169c0eaSGlenn Lagasse 	do_print = set_do_print;
344f169c0eaSGlenn Lagasse }
345f169c0eaSGlenn Lagasse 
346f169c0eaSGlenn Lagasse /* ********************************************************************	*/
347f169c0eaSGlenn Lagasse /*			Semi-Private Functions				*/
348f169c0eaSGlenn Lagasse /* ******************************************************************** */
349f169c0eaSGlenn Lagasse 
350f169c0eaSGlenn Lagasse /*
351f169c0eaSGlenn Lagasse  * Function:	be_zfs_init
352f169c0eaSGlenn Lagasse  * Description:	Initializes the libary global libzfs handle.
353f169c0eaSGlenn Lagasse  * Parameters:
354f169c0eaSGlenn Lagasse  *		None
355f169c0eaSGlenn Lagasse  * Returns:
356f169c0eaSGlenn Lagasse  *		B_TRUE - Success
357f169c0eaSGlenn Lagasse  *		B_FALSE - Failure
358f169c0eaSGlenn Lagasse  * Scope:
359f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
360f169c0eaSGlenn Lagasse  */
361f169c0eaSGlenn Lagasse boolean_t
362f169c0eaSGlenn Lagasse be_zfs_init(void)
363f169c0eaSGlenn Lagasse {
364f169c0eaSGlenn Lagasse 	be_zfs_fini();
365f169c0eaSGlenn Lagasse 
366f169c0eaSGlenn Lagasse 	if ((g_zfs = libzfs_init()) == NULL) {
367f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
368f169c0eaSGlenn Lagasse 		    "library\n"));
369f169c0eaSGlenn Lagasse 		return (B_FALSE);
370f169c0eaSGlenn Lagasse 	}
371f169c0eaSGlenn Lagasse 
372f169c0eaSGlenn Lagasse 	return (B_TRUE);
373f169c0eaSGlenn Lagasse }
374f169c0eaSGlenn Lagasse 
375f169c0eaSGlenn Lagasse /*
376f169c0eaSGlenn Lagasse  * Function:	be_zfs_fini
377f169c0eaSGlenn Lagasse  * Description:	Closes the library global libzfs handle if it currently open.
378f169c0eaSGlenn Lagasse  * Parameter:
379f169c0eaSGlenn Lagasse  *		None
380f169c0eaSGlenn Lagasse  * Returns:
381f169c0eaSGlenn Lagasse  *		None
382f169c0eaSGlenn Lagasse  * Scope:
383f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
384f169c0eaSGlenn Lagasse  */
385f169c0eaSGlenn Lagasse void
386f169c0eaSGlenn Lagasse be_zfs_fini(void)
387f169c0eaSGlenn Lagasse {
388f169c0eaSGlenn Lagasse 	if (g_zfs)
389f169c0eaSGlenn Lagasse 		libzfs_fini(g_zfs);
390f169c0eaSGlenn Lagasse 
391f169c0eaSGlenn Lagasse 	g_zfs = NULL;
392f169c0eaSGlenn Lagasse }
393f169c0eaSGlenn Lagasse 
394de1ab35cSAlexander Eremin /*
395de1ab35cSAlexander Eremin  * Function:	be_get_defaults
396de1ab35cSAlexander Eremin  * Description:	Open defaults and gets be default paramets
397de1ab35cSAlexander Eremin  * Parameters:
398de1ab35cSAlexander Eremin  *		defaults - be defaults struct
399de1ab35cSAlexander Eremin  * Returns:
400de1ab35cSAlexander Eremin  *		None
401de1ab35cSAlexander Eremin  * Scope:
402de1ab35cSAlexander Eremin  *		Semi-private (library wide use only)
403de1ab35cSAlexander Eremin  */
404de1ab35cSAlexander Eremin void
405de1ab35cSAlexander Eremin be_get_defaults(struct be_defaults *defaults)
406de1ab35cSAlexander Eremin {
407de1ab35cSAlexander Eremin 	void	*defp;
408de1ab35cSAlexander Eremin 
409fa0c327aSToomas Soome 	defaults->be_deflt_grub = B_FALSE;
410de1ab35cSAlexander Eremin 	defaults->be_deflt_rpool_container = B_FALSE;
411de1ab35cSAlexander Eremin 	defaults->be_deflt_bename_starts_with[0] = '\0';
412de1ab35cSAlexander Eremin 
413de1ab35cSAlexander Eremin 	if ((defp = defopen_r(BE_DEFAULTS)) != NULL) {
414de1ab35cSAlexander Eremin 		const char *res = defread_r(BE_DFLT_BENAME_STARTS, defp);
415fa0c327aSToomas Soome 		if (res != NULL && res[0] != '\0') {
416de1ab35cSAlexander Eremin 			(void) strlcpy(defaults->be_deflt_bename_starts_with,
4179adfa60dSMatthew Ahrens 			    res, ZFS_MAX_DATASET_NAME_LEN);
418de1ab35cSAlexander Eremin 			defaults->be_deflt_rpool_container = B_TRUE;
419de1ab35cSAlexander Eremin 		}
420fa0c327aSToomas Soome 		if (be_is_isa("i386")) {
421fa0c327aSToomas Soome 			res = defread_r(BE_DFLT_BE_HAS_GRUB, defp);
422fa0c327aSToomas Soome 			if (res != NULL && res[0] != '\0') {
423fa0c327aSToomas Soome 				if (strcasecmp(res, "true") == 0)
424fa0c327aSToomas Soome 					defaults->be_deflt_grub = B_TRUE;
425fa0c327aSToomas Soome 			}
426fa0c327aSToomas Soome 		}
427de1ab35cSAlexander Eremin 		defclose_r(defp);
428de1ab35cSAlexander Eremin 	}
429de1ab35cSAlexander Eremin }
430de1ab35cSAlexander Eremin 
431f169c0eaSGlenn Lagasse /*
432f169c0eaSGlenn Lagasse  * Function:	be_make_root_ds
433f169c0eaSGlenn Lagasse  * Description:	Generate string for BE's root dataset given the pool
434f169c0eaSGlenn Lagasse  *		it lives in and the BE name.
435f169c0eaSGlenn Lagasse  * Parameters:
436f169c0eaSGlenn Lagasse  *		zpool - pointer zpool name.
437f169c0eaSGlenn Lagasse  *		be_name - pointer to BE name.
438f169c0eaSGlenn Lagasse  *		be_root_ds - pointer to buffer to return BE root dataset in.
439f169c0eaSGlenn Lagasse  *		be_root_ds_size - size of be_root_ds
440f169c0eaSGlenn Lagasse  * Returns:
441f169c0eaSGlenn Lagasse  *		None
442f169c0eaSGlenn Lagasse  * Scope:
443f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
444f169c0eaSGlenn Lagasse  */
445f169c0eaSGlenn Lagasse void
446f169c0eaSGlenn Lagasse be_make_root_ds(const char *zpool, const char *be_name, char *be_root_ds,
447f169c0eaSGlenn Lagasse     int be_root_ds_size)
448f169c0eaSGlenn Lagasse {
449de1ab35cSAlexander Eremin 	struct be_defaults be_defaults;
450de1ab35cSAlexander Eremin 	be_get_defaults(&be_defaults);
4517e0e2549SAlexander Eremin 	char	*root_ds = NULL;
452de1ab35cSAlexander Eremin 
4537e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
4547e0e2549SAlexander Eremin 		if (be_defaults.be_deflt_rpool_container) {
4557e0e2549SAlexander Eremin 			(void) snprintf(be_root_ds, be_root_ds_size,
4567e0e2549SAlexander Eremin 			    "%s/%s", zpool, be_name);
4577e0e2549SAlexander Eremin 		} else {
4587e0e2549SAlexander Eremin 			(void) snprintf(be_root_ds, be_root_ds_size,
4597e0e2549SAlexander Eremin 			    "%s/%s/%s", zpool, BE_CONTAINER_DS_NAME, be_name);
4607e0e2549SAlexander Eremin 		}
4617e0e2549SAlexander Eremin 	} else {
4627e0e2549SAlexander Eremin 		/*
4637e0e2549SAlexander Eremin 		 * In non-global zone we can use path from mounted root dataset
4647e0e2549SAlexander Eremin 		 * to generate BE's root dataset string.
4657e0e2549SAlexander Eremin 		 */
4667e0e2549SAlexander Eremin 		if ((root_ds = be_get_ds_from_dir("/")) != NULL) {
4677e0e2549SAlexander Eremin 			(void) snprintf(be_root_ds, be_root_ds_size, "%s/%s",
4687e0e2549SAlexander Eremin 			    dirname(root_ds), be_name);
4697e0e2549SAlexander Eremin 		} else {
4707e0e2549SAlexander Eremin 			be_print_err(gettext("be_make_root_ds: zone root "
4717e0e2549SAlexander Eremin 			    "dataset is not mounted\n"));
4727e0e2549SAlexander Eremin 			return;
4737e0e2549SAlexander Eremin 		}
4747e0e2549SAlexander Eremin 	}
475f169c0eaSGlenn Lagasse }
476f169c0eaSGlenn Lagasse 
477f169c0eaSGlenn Lagasse /*
478f169c0eaSGlenn Lagasse  * Function:	be_make_container_ds
479f169c0eaSGlenn Lagasse  * Description:	Generate string for the BE container dataset given a pool name.
480f169c0eaSGlenn Lagasse  * Parameters:
481f169c0eaSGlenn Lagasse  *		zpool - pointer zpool name.
482f169c0eaSGlenn Lagasse  *		container_ds - pointer to buffer to return BE container
483f169c0eaSGlenn Lagasse  *			dataset in.
484f169c0eaSGlenn Lagasse  *		container_ds_size - size of container_ds
485f169c0eaSGlenn Lagasse  * Returns:
486f169c0eaSGlenn Lagasse  *		None
487f169c0eaSGlenn Lagasse  * Scope:
488f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
489f169c0eaSGlenn Lagasse  */
490f169c0eaSGlenn Lagasse void
491f169c0eaSGlenn Lagasse be_make_container_ds(const char *zpool,  char *container_ds,
492f169c0eaSGlenn Lagasse     int container_ds_size)
493f169c0eaSGlenn Lagasse {
494de1ab35cSAlexander Eremin 	struct be_defaults be_defaults;
495de1ab35cSAlexander Eremin 	be_get_defaults(&be_defaults);
4967e0e2549SAlexander Eremin 	char	*root_ds = NULL;
497de1ab35cSAlexander Eremin 
4987e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
4997e0e2549SAlexander Eremin 		if (be_defaults.be_deflt_rpool_container) {
5007e0e2549SAlexander Eremin 			(void) snprintf(container_ds, container_ds_size,
5017e0e2549SAlexander Eremin 			    "%s", zpool);
5027e0e2549SAlexander Eremin 		} else {
5037e0e2549SAlexander Eremin 			(void) snprintf(container_ds, container_ds_size,
5047e0e2549SAlexander Eremin 			    "%s/%s", zpool, BE_CONTAINER_DS_NAME);
5057e0e2549SAlexander Eremin 		}
5067e0e2549SAlexander Eremin 	} else {
5077e0e2549SAlexander Eremin 		if ((root_ds = be_get_ds_from_dir("/")) != NULL) {
5087e0e2549SAlexander Eremin 			(void) strlcpy(container_ds, dirname(root_ds),
5097e0e2549SAlexander Eremin 			    container_ds_size);
5107e0e2549SAlexander Eremin 		} else {
5117e0e2549SAlexander Eremin 			be_print_err(gettext("be_make_container_ds: zone root "
5127e0e2549SAlexander Eremin 			    "dataset is not mounted\n"));
5137e0e2549SAlexander Eremin 			return;
5147e0e2549SAlexander Eremin 		}
5157e0e2549SAlexander Eremin 	}
516f169c0eaSGlenn Lagasse }
517f169c0eaSGlenn Lagasse 
518f169c0eaSGlenn Lagasse /*
519f169c0eaSGlenn Lagasse  * Function:	be_make_name_from_ds
520f169c0eaSGlenn Lagasse  * Description:	This function takes a dataset name and strips off the
521f169c0eaSGlenn Lagasse  *		BE container dataset portion from the beginning.  The
522f169c0eaSGlenn Lagasse  *		returned name is allocated in heap storage, so the caller
523f169c0eaSGlenn Lagasse  *		is responsible for freeing it.
524f169c0eaSGlenn Lagasse  * Parameters:
525f169c0eaSGlenn Lagasse  *		dataset - dataset to get name from.
526f169c0eaSGlenn Lagasse  *		rc_loc - dataset underwhich the root container dataset lives.
527f169c0eaSGlenn Lagasse  * Returns:
528f169c0eaSGlenn Lagasse  *		name of dataset relative to BE container dataset.
529f169c0eaSGlenn Lagasse  *		NULL if dataset is not under a BE root dataset.
530f169c0eaSGlenn Lagasse  * Scope:
531f169c0eaSGlenn Lagasse  *		Semi-primate (library wide use only)
532f169c0eaSGlenn Lagasse  */
533f169c0eaSGlenn Lagasse char *
534f169c0eaSGlenn Lagasse be_make_name_from_ds(const char *dataset, char *rc_loc)
535f169c0eaSGlenn Lagasse {
5369adfa60dSMatthew Ahrens 	char	ds[ZFS_MAX_DATASET_NAME_LEN];
537f169c0eaSGlenn Lagasse 	char	*tok = NULL;
538f169c0eaSGlenn Lagasse 	char	*name = NULL;
539de1ab35cSAlexander Eremin 	struct be_defaults be_defaults;
540de1ab35cSAlexander Eremin 	int	rlen = strlen(rc_loc);
541de1ab35cSAlexander Eremin 
542de1ab35cSAlexander Eremin 	be_get_defaults(&be_defaults);
543f169c0eaSGlenn Lagasse 
544f169c0eaSGlenn Lagasse 	/*
545f169c0eaSGlenn Lagasse 	 * First token is the location of where the root container dataset
546f169c0eaSGlenn Lagasse 	 * lives; it must match rc_loc.
547f169c0eaSGlenn Lagasse 	 */
548de1ab35cSAlexander Eremin 	if (strncmp(dataset, rc_loc, rlen) == 0 && dataset[rlen] == '/')
549de1ab35cSAlexander Eremin 		(void) strlcpy(ds, dataset + rlen + 1, sizeof (ds));
550de1ab35cSAlexander Eremin 	else
551f169c0eaSGlenn Lagasse 		return (NULL);
552f169c0eaSGlenn Lagasse 
553de1ab35cSAlexander Eremin 	if (be_defaults.be_deflt_rpool_container) {
554de1ab35cSAlexander Eremin 		if ((name = strdup(ds)) == NULL) {
555de1ab35cSAlexander Eremin 			be_print_err(gettext("be_make_name_from_ds: "
556de1ab35cSAlexander Eremin 			    "memory allocation failed\n"));
557de1ab35cSAlexander Eremin 			return (NULL);
558de1ab35cSAlexander Eremin 		}
559de1ab35cSAlexander Eremin 	} else {
560de1ab35cSAlexander Eremin 		/* Second token must be BE container dataset name */
561de1ab35cSAlexander Eremin 		if ((tok = strtok(ds, "/")) == NULL ||
562de1ab35cSAlexander Eremin 		    strcmp(tok, BE_CONTAINER_DS_NAME) != 0)
563de1ab35cSAlexander Eremin 			return (NULL);
564f169c0eaSGlenn Lagasse 
565de1ab35cSAlexander Eremin 		/* Return the remaining token if one exists */
566de1ab35cSAlexander Eremin 		if ((tok = strtok(NULL, "")) == NULL)
567de1ab35cSAlexander Eremin 			return (NULL);
568f169c0eaSGlenn Lagasse 
569de1ab35cSAlexander Eremin 		if ((name = strdup(tok)) == NULL) {
570de1ab35cSAlexander Eremin 			be_print_err(gettext("be_make_name_from_ds: "
571de1ab35cSAlexander Eremin 			    "memory allocation failed\n"));
572de1ab35cSAlexander Eremin 			return (NULL);
573de1ab35cSAlexander Eremin 		}
574f169c0eaSGlenn Lagasse 	}
575f169c0eaSGlenn Lagasse 
576f169c0eaSGlenn Lagasse 	return (name);
577f169c0eaSGlenn Lagasse }
578f169c0eaSGlenn Lagasse 
579f169c0eaSGlenn Lagasse /*
580f169c0eaSGlenn Lagasse  * Function:	be_maxsize_avail
581f169c0eaSGlenn Lagasse  * Description:	Returns the available size for the zfs handle passed in.
582f169c0eaSGlenn Lagasse  * Parameters:
583f169c0eaSGlenn Lagasse  *		zhp - A pointer to the open zfs handle.
584f169c0eaSGlenn Lagasse  *		ret - The available size will be returned in this.
585f169c0eaSGlenn Lagasse  * Returns:
586f169c0eaSGlenn Lagasse  *		The error returned by the zfs get property function.
587f169c0eaSGlenn Lagasse  * Scope:
588f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
589f169c0eaSGlenn Lagasse  */
590f169c0eaSGlenn Lagasse int
591f169c0eaSGlenn Lagasse be_maxsize_avail(zfs_handle_t *zhp, uint64_t *ret)
592f169c0eaSGlenn Lagasse {
593f169c0eaSGlenn Lagasse 	return ((*ret = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE)));
594f169c0eaSGlenn Lagasse }
595f169c0eaSGlenn Lagasse 
596f169c0eaSGlenn Lagasse /*
597f169c0eaSGlenn Lagasse  * Function:	be_append_menu
598f169c0eaSGlenn Lagasse  * Description:	Appends an entry for a BE into the menu.lst.
599f169c0eaSGlenn Lagasse  * Parameters:
600f169c0eaSGlenn Lagasse  *		be_name - pointer to name of BE to add boot menu entry for.
601f169c0eaSGlenn Lagasse  *		be_root_pool - pointer to name of pool BE lives in.
602f169c0eaSGlenn Lagasse  *		boot_pool - Used if the pool containing the grub menu is
603f169c0eaSGlenn Lagasse  *			    different than the one contaiing the BE. This
604f169c0eaSGlenn Lagasse  *			    will normally be NULL.
605f169c0eaSGlenn Lagasse  *		be_orig_root_ds - The root dataset for the BE. This is
606f169c0eaSGlenn Lagasse  *			used to check to see if an entry already exists
607f169c0eaSGlenn Lagasse  *			for this BE.
608f169c0eaSGlenn Lagasse  *		description - pointer to description of BE to be added in
609f169c0eaSGlenn Lagasse  *			the title line for this BEs entry.
610f169c0eaSGlenn Lagasse  * Returns:
611f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
612f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
613f169c0eaSGlenn Lagasse  * Scope:
614f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
615f169c0eaSGlenn Lagasse  */
616f169c0eaSGlenn Lagasse int
617f169c0eaSGlenn Lagasse be_append_menu(char *be_name, char *be_root_pool, char *boot_pool,
618f169c0eaSGlenn Lagasse     char *be_orig_root_ds, char *description)
619f169c0eaSGlenn Lagasse {
620f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp = NULL;
621f169c0eaSGlenn Lagasse 	char menu_file[MAXPATHLEN];
622f169c0eaSGlenn Lagasse 	char be_root_ds[MAXPATHLEN];
623f169c0eaSGlenn Lagasse 	char line[BUFSIZ];
624f169c0eaSGlenn Lagasse 	char temp_line[BUFSIZ];
625f169c0eaSGlenn Lagasse 	char title[MAXPATHLEN];
626f169c0eaSGlenn Lagasse 	char *entries[BUFSIZ];
627f169c0eaSGlenn Lagasse 	char *tmp_entries[BUFSIZ];
628f169c0eaSGlenn Lagasse 	char *pool_mntpnt = NULL;
629f169c0eaSGlenn Lagasse 	char *ptmp_mntpnt = NULL;
630f169c0eaSGlenn Lagasse 	char *orig_mntpnt = NULL;
631f169c0eaSGlenn Lagasse 	boolean_t found_be = B_FALSE;
632f169c0eaSGlenn Lagasse 	boolean_t found_orig_be = B_FALSE;
633f169c0eaSGlenn Lagasse 	boolean_t found_title = B_FALSE;
634f169c0eaSGlenn Lagasse 	boolean_t pool_mounted = B_FALSE;
635f169c0eaSGlenn Lagasse 	boolean_t collect_lines = B_FALSE;
636f169c0eaSGlenn Lagasse 	FILE *menu_fp = NULL;
637f169c0eaSGlenn Lagasse 	int err = 0, ret = BE_SUCCESS;
638f169c0eaSGlenn Lagasse 	int i, num_tmp_lines = 0, num_lines = 0;
639f169c0eaSGlenn Lagasse 
640f169c0eaSGlenn Lagasse 	if (be_name == NULL || be_root_pool == NULL)
641f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
642f169c0eaSGlenn Lagasse 
643f169c0eaSGlenn Lagasse 	if (boot_pool == NULL)
644f169c0eaSGlenn Lagasse 		boot_pool = be_root_pool;
645f169c0eaSGlenn Lagasse 
646f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
647f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_append_menu: failed to open "
648f169c0eaSGlenn Lagasse 		    "pool dataset for %s: %s\n"), be_root_pool,
649f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
650f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
651f169c0eaSGlenn Lagasse 	}
652f169c0eaSGlenn Lagasse 
653f169c0eaSGlenn Lagasse 	/*
654f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
655f169c0eaSGlenn Lagasse 	 * attempt to mount it.
656f169c0eaSGlenn Lagasse 	 */
657f169c0eaSGlenn Lagasse 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
658f169c0eaSGlenn Lagasse 	    &pool_mounted)) != BE_SUCCESS) {
659f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_append_menu: pool dataset "
660f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), be_root_pool);
661f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
662f169c0eaSGlenn Lagasse 		return (ret);
663f169c0eaSGlenn Lagasse 	}
664f169c0eaSGlenn Lagasse 
665f169c0eaSGlenn Lagasse 	/*
666f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
667f169c0eaSGlenn Lagasse 	 */
668f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
669f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_append_menu: pool "
670f169c0eaSGlenn Lagasse 		    "dataset (%s) is not mounted. Can't set "
671f169c0eaSGlenn Lagasse 		    "the default BE in the grub menu.\n"), be_root_pool);
672f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
673f169c0eaSGlenn Lagasse 		goto cleanup;
674f169c0eaSGlenn Lagasse 	}
675f169c0eaSGlenn Lagasse 
676f169c0eaSGlenn Lagasse 	/*
677f169c0eaSGlenn Lagasse 	 * Check to see if this system supports grub
678f169c0eaSGlenn Lagasse 	 */
679f169c0eaSGlenn Lagasse 	if (be_has_grub()) {
680f169c0eaSGlenn Lagasse 		(void) snprintf(menu_file, sizeof (menu_file),
681f169c0eaSGlenn Lagasse 		    "%s%s", pool_mntpnt, BE_GRUB_MENU);
682f169c0eaSGlenn Lagasse 	} else {
683f169c0eaSGlenn Lagasse 		(void) snprintf(menu_file, sizeof (menu_file),
684f169c0eaSGlenn Lagasse 		    "%s%s", pool_mntpnt, BE_SPARC_MENU);
685f169c0eaSGlenn Lagasse 	}
686f169c0eaSGlenn Lagasse 
687f169c0eaSGlenn Lagasse 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
688f169c0eaSGlenn Lagasse 
689f169c0eaSGlenn Lagasse 	/*
690f169c0eaSGlenn Lagasse 	 * Iterate through menu first to make sure the BE doesn't already
691f169c0eaSGlenn Lagasse 	 * have an entry in the menu.
692f169c0eaSGlenn Lagasse 	 *
693f169c0eaSGlenn Lagasse 	 * Additionally while iterating through the menu, if we have an
694f169c0eaSGlenn Lagasse 	 * original root dataset for a BE we're cloning from, we need to keep
695f169c0eaSGlenn Lagasse 	 * track of that BE's menu entry. We will then use the lines from
696f169c0eaSGlenn Lagasse 	 * that entry to create the entry for the new BE.
697f169c0eaSGlenn Lagasse 	 */
698de1ab35cSAlexander Eremin 	if ((ret = be_open_menu(be_root_pool, menu_file,
699f169c0eaSGlenn Lagasse 	    &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
700f169c0eaSGlenn Lagasse 		goto cleanup;
701f169c0eaSGlenn Lagasse 	} else if (menu_fp == NULL) {
702f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
703f169c0eaSGlenn Lagasse 		goto cleanup;
704f169c0eaSGlenn Lagasse 	}
705f169c0eaSGlenn Lagasse 
706f169c0eaSGlenn Lagasse 	free(pool_mntpnt);
707f169c0eaSGlenn Lagasse 	pool_mntpnt = NULL;
708f169c0eaSGlenn Lagasse 
709f169c0eaSGlenn Lagasse 	while (fgets(line, BUFSIZ, menu_fp)) {
710f169c0eaSGlenn Lagasse 		char *tok = NULL;
711f169c0eaSGlenn Lagasse 
712f169c0eaSGlenn Lagasse 		(void) strlcpy(temp_line, line, BUFSIZ);
713f169c0eaSGlenn Lagasse 		tok = strtok(line, BE_WHITE_SPACE);
714f169c0eaSGlenn Lagasse 
715f169c0eaSGlenn Lagasse 		if (tok == NULL || tok[0] == '#') {
716f169c0eaSGlenn Lagasse 			continue;
717f169c0eaSGlenn Lagasse 		} else if (strcmp(tok, "title") == 0) {
718f169c0eaSGlenn Lagasse 			collect_lines = B_FALSE;
719f169c0eaSGlenn Lagasse 			if ((tok = strtok(NULL, "\n")) == NULL)
720f169c0eaSGlenn Lagasse 				(void) strlcpy(title, "", sizeof (title));
721f169c0eaSGlenn Lagasse 			else
722f169c0eaSGlenn Lagasse 				(void) strlcpy(title, tok, sizeof (title));
723f169c0eaSGlenn Lagasse 			found_title = B_TRUE;
724f169c0eaSGlenn Lagasse 
725f169c0eaSGlenn Lagasse 			if (num_tmp_lines != 0) {
726f169c0eaSGlenn Lagasse 				for (i = 0; i < num_tmp_lines; i++) {
727f169c0eaSGlenn Lagasse 					free(tmp_entries[i]);
728f169c0eaSGlenn Lagasse 					tmp_entries[i] = NULL;
729f169c0eaSGlenn Lagasse 				}
730f169c0eaSGlenn Lagasse 				num_tmp_lines = 0;
731f169c0eaSGlenn Lagasse 			}
732f169c0eaSGlenn Lagasse 		} else if (strcmp(tok, "bootfs") == 0) {
733f169c0eaSGlenn Lagasse 			char *bootfs = strtok(NULL, BE_WHITE_SPACE);
734f169c0eaSGlenn Lagasse 			found_title = B_FALSE;
735f169c0eaSGlenn Lagasse 			if (bootfs == NULL)
736f169c0eaSGlenn Lagasse 				continue;
737f169c0eaSGlenn Lagasse 
738f169c0eaSGlenn Lagasse 			if (strcmp(bootfs, be_root_ds) == 0) {
739f169c0eaSGlenn Lagasse 				found_be = B_TRUE;
740f169c0eaSGlenn Lagasse 				break;
741f169c0eaSGlenn Lagasse 			}
742f169c0eaSGlenn Lagasse 
743f169c0eaSGlenn Lagasse 			if (be_orig_root_ds != NULL &&
744f169c0eaSGlenn Lagasse 			    strcmp(bootfs, be_orig_root_ds) == 0 &&
745f169c0eaSGlenn Lagasse 			    !found_orig_be) {
746f169c0eaSGlenn Lagasse 				char str[BUFSIZ];
747f169c0eaSGlenn Lagasse 				found_orig_be = B_TRUE;
748f169c0eaSGlenn Lagasse 				num_lines = 0;
749f169c0eaSGlenn Lagasse 				/*
750f169c0eaSGlenn Lagasse 				 * Store the new title line
751f169c0eaSGlenn Lagasse 				 */
752f169c0eaSGlenn Lagasse 				(void) snprintf(str, BUFSIZ, "title %s\n",
753f169c0eaSGlenn Lagasse 				    description ? description : be_name);
754f169c0eaSGlenn Lagasse 				entries[num_lines] = strdup(str);
755f169c0eaSGlenn Lagasse 				num_lines++;
756f169c0eaSGlenn Lagasse 				/*
757f169c0eaSGlenn Lagasse 				 * If there are any lines between the title
758f169c0eaSGlenn Lagasse 				 * and the bootfs line store these. Also
759f169c0eaSGlenn Lagasse 				 * free the temporary lines.
760f169c0eaSGlenn Lagasse 				 */
761f169c0eaSGlenn Lagasse 				for (i = 0; i < num_tmp_lines; i++) {
762f169c0eaSGlenn Lagasse 					entries[num_lines] = tmp_entries[i];
763f169c0eaSGlenn Lagasse 					tmp_entries[i] = NULL;
764f169c0eaSGlenn Lagasse 					num_lines++;
765f169c0eaSGlenn Lagasse 				}
766f169c0eaSGlenn Lagasse 				num_tmp_lines = 0;
767f169c0eaSGlenn Lagasse 				/*
768f169c0eaSGlenn Lagasse 				 * Store the new bootfs line.
769f169c0eaSGlenn Lagasse 				 */
770f169c0eaSGlenn Lagasse 				(void) snprintf(str, BUFSIZ, "bootfs %s\n",
771f169c0eaSGlenn Lagasse 				    be_root_ds);
772f169c0eaSGlenn Lagasse 				entries[num_lines] = strdup(str);
773f169c0eaSGlenn Lagasse 				num_lines++;
774f169c0eaSGlenn Lagasse 				collect_lines = B_TRUE;
775f169c0eaSGlenn Lagasse 			}
776f169c0eaSGlenn Lagasse 		} else if (found_orig_be && collect_lines) {
777f169c0eaSGlenn Lagasse 			/*
778f169c0eaSGlenn Lagasse 			 * get the rest of the lines for the original BE and
779f169c0eaSGlenn Lagasse 			 * store them.
780f169c0eaSGlenn Lagasse 			 */
781f169c0eaSGlenn Lagasse 			if (strstr(line, BE_GRUB_COMMENT) != NULL ||
782f169c0eaSGlenn Lagasse 			    strstr(line, "BOOTADM") != NULL)
783f169c0eaSGlenn Lagasse 				continue;
784e77c795bSGarrett D'Amore 			if (strcmp(tok, "splashimage") == 0) {
785e77c795bSGarrett D'Amore 				entries[num_lines] =
786e77c795bSGarrett D'Amore 				    strdup("splashimage "
787e77c795bSGarrett D'Amore 				    "/boot/splashimage.xpm\n");
788e77c795bSGarrett D'Amore 			} else {
789e77c795bSGarrett D'Amore 				entries[num_lines] = strdup(temp_line);
790e77c795bSGarrett D'Amore 			}
791f169c0eaSGlenn Lagasse 			num_lines++;
792f169c0eaSGlenn Lagasse 		} else if (found_title && !found_orig_be) {
793f169c0eaSGlenn Lagasse 			tmp_entries[num_tmp_lines] = strdup(temp_line);
794f169c0eaSGlenn Lagasse 			num_tmp_lines++;
795f169c0eaSGlenn Lagasse 		}
796f169c0eaSGlenn Lagasse 	}
797f169c0eaSGlenn Lagasse 
798f169c0eaSGlenn Lagasse 	(void) fclose(menu_fp);
799f169c0eaSGlenn Lagasse 
800f169c0eaSGlenn Lagasse 	if (found_be) {
801f169c0eaSGlenn Lagasse 		/*
802f169c0eaSGlenn Lagasse 		 * If an entry for this BE was already in the menu, then if
803f169c0eaSGlenn Lagasse 		 * that entry's title matches what we would have put in
804f169c0eaSGlenn Lagasse 		 * return success.  Otherwise return failure.
805f169c0eaSGlenn Lagasse 		 */
806f169c0eaSGlenn Lagasse 		char *new_title = description ? description : be_name;
807f169c0eaSGlenn Lagasse 
808f169c0eaSGlenn Lagasse 		if (strcmp(title, new_title) == 0) {
809f169c0eaSGlenn Lagasse 			ret = BE_SUCCESS;
810f169c0eaSGlenn Lagasse 			goto cleanup;
811f169c0eaSGlenn Lagasse 		} else {
812f169c0eaSGlenn Lagasse 			if (be_remove_menu(be_name, be_root_pool,
813f169c0eaSGlenn Lagasse 			    boot_pool) != BE_SUCCESS) {
814f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_append_menu: "
815f169c0eaSGlenn Lagasse 				    "Failed to remove existing unusable "
816f169c0eaSGlenn Lagasse 				    "entry '%s' in boot menu.\n"), be_name);
817f169c0eaSGlenn Lagasse 				ret = BE_ERR_BE_EXISTS;
818f169c0eaSGlenn Lagasse 				goto cleanup;
819f169c0eaSGlenn Lagasse 			}
820f169c0eaSGlenn Lagasse 		}
821f169c0eaSGlenn Lagasse 	}
822f169c0eaSGlenn Lagasse 
823f169c0eaSGlenn Lagasse 	/* Append BE entry to the end of the file */
824f169c0eaSGlenn Lagasse 	menu_fp = fopen(menu_file, "a+");
825f169c0eaSGlenn Lagasse 	err = errno;
826f169c0eaSGlenn Lagasse 	if (menu_fp == NULL) {
827f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_append_menu: failed "
828f169c0eaSGlenn Lagasse 		    "to open menu.lst file %s\n"), menu_file);
829f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
830f169c0eaSGlenn Lagasse 		goto cleanup;
831f169c0eaSGlenn Lagasse 	}
832f169c0eaSGlenn Lagasse 
833f169c0eaSGlenn Lagasse 	if (found_orig_be) {
834f169c0eaSGlenn Lagasse 		/*
835f169c0eaSGlenn Lagasse 		 * write out all the stored lines
836f169c0eaSGlenn Lagasse 		 */
837f169c0eaSGlenn Lagasse 		for (i = 0; i < num_lines; i++) {
838f169c0eaSGlenn Lagasse 			(void) fprintf(menu_fp, "%s", entries[i]);
839f169c0eaSGlenn Lagasse 			free(entries[i]);
840f169c0eaSGlenn Lagasse 		}
841f169c0eaSGlenn Lagasse 		num_lines = 0;
842f169c0eaSGlenn Lagasse 
843f169c0eaSGlenn Lagasse 		/*
844f169c0eaSGlenn Lagasse 		 * Check to see if this system supports grub
845f169c0eaSGlenn Lagasse 		 */
846f169c0eaSGlenn Lagasse 		if (be_has_grub())
847f169c0eaSGlenn Lagasse 			(void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
848f169c0eaSGlenn Lagasse 		ret = BE_SUCCESS;
849f169c0eaSGlenn Lagasse 	} else {
850f169c0eaSGlenn Lagasse 		(void) fprintf(menu_fp, "title %s\n",
851f169c0eaSGlenn Lagasse 		    description ? description : be_name);
852f169c0eaSGlenn Lagasse 		(void) fprintf(menu_fp, "bootfs %s\n", be_root_ds);
853f169c0eaSGlenn Lagasse 
854f169c0eaSGlenn Lagasse 		/*
855f169c0eaSGlenn Lagasse 		 * Check to see if this system supports grub
856f169c0eaSGlenn Lagasse 		 */
857f169c0eaSGlenn Lagasse 		if (be_has_grub()) {
858f169c0eaSGlenn Lagasse 			(void) fprintf(menu_fp, "kernel$ "
859f169c0eaSGlenn Lagasse 			    "/platform/i86pc/kernel/$ISADIR/unix -B "
860f169c0eaSGlenn Lagasse 			    "$ZFS-BOOTFS\n");
861f169c0eaSGlenn Lagasse 			(void) fprintf(menu_fp, "module$ "
862f169c0eaSGlenn Lagasse 			    "/platform/i86pc/$ISADIR/boot_archive\n");
863f169c0eaSGlenn Lagasse 			(void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
864f169c0eaSGlenn Lagasse 		}
865f169c0eaSGlenn Lagasse 		ret = BE_SUCCESS;
866f169c0eaSGlenn Lagasse 	}
867f169c0eaSGlenn Lagasse 	(void) fclose(menu_fp);
868f169c0eaSGlenn Lagasse cleanup:
869f169c0eaSGlenn Lagasse 	if (pool_mounted) {
870f169c0eaSGlenn Lagasse 		int err = BE_SUCCESS;
871f169c0eaSGlenn Lagasse 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
872f169c0eaSGlenn Lagasse 		if (ret == BE_SUCCESS)
873f169c0eaSGlenn Lagasse 			ret = err;
874f169c0eaSGlenn Lagasse 		free(orig_mntpnt);
875f169c0eaSGlenn Lagasse 		free(ptmp_mntpnt);
876f169c0eaSGlenn Lagasse 	}
877f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
878f169c0eaSGlenn Lagasse 	if (num_tmp_lines > 0) {
879f169c0eaSGlenn Lagasse 		for (i = 0; i < num_tmp_lines; i++) {
880f169c0eaSGlenn Lagasse 			free(tmp_entries[i]);
881f169c0eaSGlenn Lagasse 			tmp_entries[i] = NULL;
882f169c0eaSGlenn Lagasse 		}
883f169c0eaSGlenn Lagasse 	}
884f169c0eaSGlenn Lagasse 	if (num_lines > 0) {
885f169c0eaSGlenn Lagasse 		for (i = 0; i < num_lines; i++) {
886f169c0eaSGlenn Lagasse 			free(entries[i]);
887f169c0eaSGlenn Lagasse 			entries[i] = NULL;
888f169c0eaSGlenn Lagasse 		}
889f169c0eaSGlenn Lagasse 	}
890f169c0eaSGlenn Lagasse 	return (ret);
891f169c0eaSGlenn Lagasse }
892f169c0eaSGlenn Lagasse 
893f169c0eaSGlenn Lagasse /*
894f169c0eaSGlenn Lagasse  * Function:	be_remove_menu
895f169c0eaSGlenn Lagasse  * Description:	Removes a BE's entry from a menu.lst file.
896f169c0eaSGlenn Lagasse  * Parameters:
897f169c0eaSGlenn Lagasse  *		be_name - the name of BE whose entry is to be removed from
898f169c0eaSGlenn Lagasse  *			the menu.lst file.
899f169c0eaSGlenn Lagasse  *		be_root_pool - the pool that be_name lives in.
900f169c0eaSGlenn Lagasse  *		boot_pool - the pool where the BE is, if different than
901f169c0eaSGlenn Lagasse  *			the pool containing the boot menu.  If this is
902f169c0eaSGlenn Lagasse  *			NULL it will be set to be_root_pool.
903f169c0eaSGlenn Lagasse  * Returns:
904f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
905f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
906f169c0eaSGlenn Lagasse  * Scope:
907f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
908f169c0eaSGlenn Lagasse  */
909f169c0eaSGlenn Lagasse int
910f169c0eaSGlenn Lagasse be_remove_menu(char *be_name, char *be_root_pool, char *boot_pool)
911f169c0eaSGlenn Lagasse {
912f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
913f169c0eaSGlenn Lagasse 	char		be_root_ds[MAXPATHLEN];
914f169c0eaSGlenn Lagasse 	char		**buffer = NULL;
915f169c0eaSGlenn Lagasse 	char		menu_buf[BUFSIZ];
916f169c0eaSGlenn Lagasse 	char		menu[MAXPATHLEN];
917f169c0eaSGlenn Lagasse 	char		*pool_mntpnt = NULL;
918f169c0eaSGlenn Lagasse 	char		*ptmp_mntpnt = NULL;
919f169c0eaSGlenn Lagasse 	char		*orig_mntpnt = NULL;
920f169c0eaSGlenn Lagasse 	char		*tmp_menu = NULL;
921f169c0eaSGlenn Lagasse 	FILE		*menu_fp = NULL;
922f169c0eaSGlenn Lagasse 	FILE		*tmp_menu_fp = NULL;
923f169c0eaSGlenn Lagasse 	struct stat	sb;
924f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
925f169c0eaSGlenn Lagasse 	int		i;
926f169c0eaSGlenn Lagasse 	int		fd;
927f169c0eaSGlenn Lagasse 	int		err = 0;
928f169c0eaSGlenn Lagasse 	int		nlines = 0;
929f169c0eaSGlenn Lagasse 	int		default_entry = 0;
930f169c0eaSGlenn Lagasse 	int		entry_cnt = 0;
931f169c0eaSGlenn Lagasse 	int		entry_del = 0;
932f169c0eaSGlenn Lagasse 	int		num_entry_del = 0;
933f169c0eaSGlenn Lagasse 	int		tmp_menu_len = 0;
934f169c0eaSGlenn Lagasse 	boolean_t	write = B_TRUE;
935f169c0eaSGlenn Lagasse 	boolean_t	do_buffer = B_FALSE;
936f169c0eaSGlenn Lagasse 	boolean_t	pool_mounted = B_FALSE;
937f169c0eaSGlenn Lagasse 
938f169c0eaSGlenn Lagasse 	if (boot_pool == NULL)
939f169c0eaSGlenn Lagasse 		boot_pool = be_root_pool;
940f169c0eaSGlenn Lagasse 
941f169c0eaSGlenn Lagasse 	/* Get name of BE's root dataset */
942f169c0eaSGlenn Lagasse 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
943f169c0eaSGlenn Lagasse 
944f169c0eaSGlenn Lagasse 	/* Get handle to pool dataset */
945f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
946f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: "
947f169c0eaSGlenn Lagasse 		    "failed to open pool dataset for %s: %s"),
948f169c0eaSGlenn Lagasse 		    be_root_pool, libzfs_error_description(g_zfs));
949f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
950f169c0eaSGlenn Lagasse 	}
951f169c0eaSGlenn Lagasse 
952f169c0eaSGlenn Lagasse 	/*
953f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
954f169c0eaSGlenn Lagasse 	 * attempt to mount it.
955f169c0eaSGlenn Lagasse 	 */
956f169c0eaSGlenn Lagasse 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
957f169c0eaSGlenn Lagasse 	    &pool_mounted)) != BE_SUCCESS) {
958f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: pool dataset "
959f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), be_root_pool);
960f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
961f169c0eaSGlenn Lagasse 		return (ret);
962f169c0eaSGlenn Lagasse 	}
963f169c0eaSGlenn Lagasse 
964f169c0eaSGlenn Lagasse 	/*
965f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
966f169c0eaSGlenn Lagasse 	 */
967f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
968f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: pool "
969f169c0eaSGlenn Lagasse 		    "dataset (%s) is not mounted. Can't set "
970f169c0eaSGlenn Lagasse 		    "the default BE in the grub menu.\n"), be_root_pool);
971f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
972f169c0eaSGlenn Lagasse 		goto cleanup;
973f169c0eaSGlenn Lagasse 	}
974f169c0eaSGlenn Lagasse 
975f169c0eaSGlenn Lagasse 	/* Get path to boot menu */
976f169c0eaSGlenn Lagasse 	(void) strlcpy(menu, pool_mntpnt, sizeof (menu));
977f169c0eaSGlenn Lagasse 
978f169c0eaSGlenn Lagasse 	/*
979f169c0eaSGlenn Lagasse 	 * Check to see if this system supports grub
980f169c0eaSGlenn Lagasse 	 */
981f169c0eaSGlenn Lagasse 	if (be_has_grub())
982f169c0eaSGlenn Lagasse 		(void) strlcat(menu, BE_GRUB_MENU, sizeof (menu));
983f169c0eaSGlenn Lagasse 	else
984f169c0eaSGlenn Lagasse 		(void) strlcat(menu, BE_SPARC_MENU, sizeof (menu));
985f169c0eaSGlenn Lagasse 
986f169c0eaSGlenn Lagasse 	/* Get handle to boot menu file */
987de1ab35cSAlexander Eremin 	if ((ret = be_open_menu(be_root_pool, menu, &menu_fp, "r",
988f169c0eaSGlenn Lagasse 	    B_TRUE)) != BE_SUCCESS) {
989f169c0eaSGlenn Lagasse 		goto cleanup;
990f169c0eaSGlenn Lagasse 	} else if (menu_fp == NULL) {
991f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
992f169c0eaSGlenn Lagasse 		goto cleanup;
993f169c0eaSGlenn Lagasse 	}
994f169c0eaSGlenn Lagasse 
995f169c0eaSGlenn Lagasse 	free(pool_mntpnt);
996f169c0eaSGlenn Lagasse 	pool_mntpnt = NULL;
997f169c0eaSGlenn Lagasse 
998f169c0eaSGlenn Lagasse 	/* Grab the stats of the original menu file */
999f169c0eaSGlenn Lagasse 	if (stat(menu, &sb) != 0) {
1000f169c0eaSGlenn Lagasse 		err = errno;
1001f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: "
1002f169c0eaSGlenn Lagasse 		    "failed to stat file %s: %s\n"), menu, strerror(err));
1003f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1004f169c0eaSGlenn Lagasse 		goto cleanup;
1005f169c0eaSGlenn Lagasse 	}
1006f169c0eaSGlenn Lagasse 
1007f169c0eaSGlenn Lagasse 	/* Create a tmp file for the modified menu.lst */
1008f169c0eaSGlenn Lagasse 	tmp_menu_len = strlen(menu) + 7;
1009f169c0eaSGlenn Lagasse 	if ((tmp_menu = (char *)malloc(tmp_menu_len)) == NULL) {
1010f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: malloc failed\n"));
1011f169c0eaSGlenn Lagasse 		ret = BE_ERR_NOMEM;
1012f169c0eaSGlenn Lagasse 		goto cleanup;
1013f169c0eaSGlenn Lagasse 	}
1014f169c0eaSGlenn Lagasse 	(void) memset(tmp_menu, 0, tmp_menu_len);
1015f169c0eaSGlenn Lagasse 	(void) strlcpy(tmp_menu, menu, tmp_menu_len);
1016f169c0eaSGlenn Lagasse 	(void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
1017f169c0eaSGlenn Lagasse 	if ((fd = mkstemp(tmp_menu)) == -1) {
1018f169c0eaSGlenn Lagasse 		err = errno;
1019f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: mkstemp failed\n"));
1020f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1021f169c0eaSGlenn Lagasse 		free(tmp_menu);
1022f169c0eaSGlenn Lagasse 		tmp_menu = NULL;
1023f169c0eaSGlenn Lagasse 		goto cleanup;
1024f169c0eaSGlenn Lagasse 	}
1025f169c0eaSGlenn Lagasse 	if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
1026f169c0eaSGlenn Lagasse 		err = errno;
1027f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: "
1028f169c0eaSGlenn Lagasse 		    "could not open tmp file for write: %s\n"), strerror(err));
1029f169c0eaSGlenn Lagasse 		(void) close(fd);
1030f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1031f169c0eaSGlenn Lagasse 		goto cleanup;
1032f169c0eaSGlenn Lagasse 	}
1033f169c0eaSGlenn Lagasse 
1034f169c0eaSGlenn Lagasse 	while (fgets(menu_buf, BUFSIZ, menu_fp)) {
1035f169c0eaSGlenn Lagasse 		char tline [BUFSIZ];
1036f169c0eaSGlenn Lagasse 		char *tok = NULL;
1037f169c0eaSGlenn Lagasse 
1038f169c0eaSGlenn Lagasse 		(void) strlcpy(tline, menu_buf, sizeof (tline));
1039f169c0eaSGlenn Lagasse 
1040f169c0eaSGlenn Lagasse 		/* Tokenize line */
1041f169c0eaSGlenn Lagasse 		tok = strtok(tline, BE_WHITE_SPACE);
1042f169c0eaSGlenn Lagasse 
1043f169c0eaSGlenn Lagasse 		if (tok == NULL || tok[0] == '#') {
1044f169c0eaSGlenn Lagasse 			/* Found empty line or comment line */
1045f169c0eaSGlenn Lagasse 			if (do_buffer) {
1046f169c0eaSGlenn Lagasse 				/* Buffer this line */
1047f169c0eaSGlenn Lagasse 				if ((buffer = (char **)realloc(buffer,
1048f169c0eaSGlenn Lagasse 				    sizeof (char *)*(nlines + 1))) == NULL) {
1049f169c0eaSGlenn Lagasse 					ret = BE_ERR_NOMEM;
1050f169c0eaSGlenn Lagasse 					goto cleanup;
1051f169c0eaSGlenn Lagasse 				}
1052f169c0eaSGlenn Lagasse 				if ((buffer[nlines++] = strdup(menu_buf))
1053f169c0eaSGlenn Lagasse 				    == NULL) {
1054f169c0eaSGlenn Lagasse 					ret = BE_ERR_NOMEM;
1055f169c0eaSGlenn Lagasse 					goto cleanup;
1056f169c0eaSGlenn Lagasse 				}
1057f169c0eaSGlenn Lagasse 
1058f169c0eaSGlenn Lagasse 			} else if (write || strncmp(menu_buf, BE_GRUB_COMMENT,
1059f169c0eaSGlenn Lagasse 			    strlen(BE_GRUB_COMMENT)) != 0) {
1060f169c0eaSGlenn Lagasse 				/* Write this line out */
1061f169c0eaSGlenn Lagasse 				(void) fputs(menu_buf, tmp_menu_fp);
1062f169c0eaSGlenn Lagasse 			}
1063f169c0eaSGlenn Lagasse 		} else if (strcmp(tok, "default") == 0) {
1064f169c0eaSGlenn Lagasse 			/*
1065f169c0eaSGlenn Lagasse 			 * Record what 'default' is set to because we might
1066f169c0eaSGlenn Lagasse 			 * need to adjust this upon deleting an entry.
1067f169c0eaSGlenn Lagasse 			 */
1068f169c0eaSGlenn Lagasse 			tok = strtok(NULL, BE_WHITE_SPACE);
1069f169c0eaSGlenn Lagasse 
1070f169c0eaSGlenn Lagasse 			if (tok != NULL) {
1071f169c0eaSGlenn Lagasse 				default_entry = atoi(tok);
1072f169c0eaSGlenn Lagasse 			}
1073f169c0eaSGlenn Lagasse 
1074f169c0eaSGlenn Lagasse 			(void) fputs(menu_buf, tmp_menu_fp);
1075f169c0eaSGlenn Lagasse 		} else if (strcmp(tok, "title") == 0) {
1076f169c0eaSGlenn Lagasse 			/*
1077f169c0eaSGlenn Lagasse 			 * If we've reached a 'title' line and do_buffer is
1078f169c0eaSGlenn Lagasse 			 * is true, that means we've just buffered an entire
1079f169c0eaSGlenn Lagasse 			 * entry without finding a 'bootfs' directive.  We
1080f169c0eaSGlenn Lagasse 			 * need to write that entry out and keep searching.
1081f169c0eaSGlenn Lagasse 			 */
1082f169c0eaSGlenn Lagasse 			if (do_buffer) {
1083f169c0eaSGlenn Lagasse 				for (i = 0; i < nlines; i++) {
1084f169c0eaSGlenn Lagasse 					(void) fputs(buffer[i], tmp_menu_fp);
1085f169c0eaSGlenn Lagasse 					free(buffer[i]);
1086f169c0eaSGlenn Lagasse 				}
1087f169c0eaSGlenn Lagasse 				free(buffer);
1088f169c0eaSGlenn Lagasse 				buffer = NULL;
1089f169c0eaSGlenn Lagasse 				nlines = 0;
1090f169c0eaSGlenn Lagasse 			}
1091f169c0eaSGlenn Lagasse 
1092f169c0eaSGlenn Lagasse 			/*
1093f169c0eaSGlenn Lagasse 			 * Turn writing off and buffering on, and increment
1094f169c0eaSGlenn Lagasse 			 * our entry counter.
1095f169c0eaSGlenn Lagasse 			 */
1096f169c0eaSGlenn Lagasse 			write = B_FALSE;
1097f169c0eaSGlenn Lagasse 			do_buffer = B_TRUE;
1098f169c0eaSGlenn Lagasse 			entry_cnt++;
1099f169c0eaSGlenn Lagasse 
1100f169c0eaSGlenn Lagasse 			/* Buffer this 'title' line */
1101f169c0eaSGlenn Lagasse 			if ((buffer = (char **)realloc(buffer,
1102f169c0eaSGlenn Lagasse 			    sizeof (char *)*(nlines + 1))) == NULL) {
1103f169c0eaSGlenn Lagasse 				ret = BE_ERR_NOMEM;
1104f169c0eaSGlenn Lagasse 				goto cleanup;
1105f169c0eaSGlenn Lagasse 			}
1106f169c0eaSGlenn Lagasse 			if ((buffer[nlines++] = strdup(menu_buf)) == NULL) {
1107f169c0eaSGlenn Lagasse 				ret = BE_ERR_NOMEM;
1108f169c0eaSGlenn Lagasse 				goto cleanup;
1109f169c0eaSGlenn Lagasse 			}
1110f169c0eaSGlenn Lagasse 
1111f169c0eaSGlenn Lagasse 		} else if (strcmp(tok, "bootfs") == 0) {
1112f169c0eaSGlenn Lagasse 			char *bootfs = NULL;
1113f169c0eaSGlenn Lagasse 
1114f169c0eaSGlenn Lagasse 			/*
1115f169c0eaSGlenn Lagasse 			 * Found a 'bootfs' line.  See if it matches the
1116f169c0eaSGlenn Lagasse 			 * BE we're looking for.
1117f169c0eaSGlenn Lagasse 			 */
1118f169c0eaSGlenn Lagasse 			if ((bootfs = strtok(NULL, BE_WHITE_SPACE)) == NULL ||
1119f169c0eaSGlenn Lagasse 			    strcmp(bootfs, be_root_ds) != 0) {
1120f169c0eaSGlenn Lagasse 				/*
1121f169c0eaSGlenn Lagasse 				 * Either there's nothing after the 'bootfs'
1122f169c0eaSGlenn Lagasse 				 * or this is not the BE we're looking for,
1123f169c0eaSGlenn Lagasse 				 * write out the line(s) we've buffered since
1124f169c0eaSGlenn Lagasse 				 * finding the title.
1125f169c0eaSGlenn Lagasse 				 */
1126f169c0eaSGlenn Lagasse 				for (i = 0; i < nlines; i++) {
1127f169c0eaSGlenn Lagasse 					(void) fputs(buffer[i], tmp_menu_fp);
1128f169c0eaSGlenn Lagasse 					free(buffer[i]);
1129f169c0eaSGlenn Lagasse 				}
1130f169c0eaSGlenn Lagasse 				free(buffer);
1131f169c0eaSGlenn Lagasse 				buffer = NULL;
1132f169c0eaSGlenn Lagasse 				nlines = 0;
1133f169c0eaSGlenn Lagasse 
1134f169c0eaSGlenn Lagasse 				/*
1135f169c0eaSGlenn Lagasse 				 * Turn writing back on, and turn off buffering
1136f169c0eaSGlenn Lagasse 				 * since this isn't the entry we're looking
1137f169c0eaSGlenn Lagasse 				 * for.
1138f169c0eaSGlenn Lagasse 				 */
1139f169c0eaSGlenn Lagasse 				write = B_TRUE;
1140f169c0eaSGlenn Lagasse 				do_buffer = B_FALSE;
1141f169c0eaSGlenn Lagasse 
1142f169c0eaSGlenn Lagasse 				/* Write this 'bootfs' line out. */
1143f169c0eaSGlenn Lagasse 				(void) fputs(menu_buf, tmp_menu_fp);
1144f169c0eaSGlenn Lagasse 			} else {
1145f169c0eaSGlenn Lagasse 				/*
1146f169c0eaSGlenn Lagasse 				 * Found the entry we're looking for.
1147f169c0eaSGlenn Lagasse 				 * Record its entry number, increment the
1148f169c0eaSGlenn Lagasse 				 * number of entries we've deleted, and turn
1149f169c0eaSGlenn Lagasse 				 * writing off.  Also, throw away the lines
1150f169c0eaSGlenn Lagasse 				 * we've buffered for this entry so far, we
1151f169c0eaSGlenn Lagasse 				 * don't need them.
1152f169c0eaSGlenn Lagasse 				 */
1153f169c0eaSGlenn Lagasse 				entry_del = entry_cnt - 1;
1154f169c0eaSGlenn Lagasse 				num_entry_del++;
1155f169c0eaSGlenn Lagasse 				write = B_FALSE;
1156f169c0eaSGlenn Lagasse 				do_buffer = B_FALSE;
1157f169c0eaSGlenn Lagasse 
1158f169c0eaSGlenn Lagasse 				for (i = 0; i < nlines; i++) {
1159f169c0eaSGlenn Lagasse 					free(buffer[i]);
1160f169c0eaSGlenn Lagasse 				}
1161f169c0eaSGlenn Lagasse 				free(buffer);
1162f169c0eaSGlenn Lagasse 				buffer = NULL;
1163f169c0eaSGlenn Lagasse 				nlines = 0;
1164f169c0eaSGlenn Lagasse 			}
1165f169c0eaSGlenn Lagasse 		} else {
1166f169c0eaSGlenn Lagasse 			if (do_buffer) {
1167f169c0eaSGlenn Lagasse 				/* Buffer this line */
1168f169c0eaSGlenn Lagasse 				if ((buffer = (char **)realloc(buffer,
1169f169c0eaSGlenn Lagasse 				    sizeof (char *)*(nlines + 1))) == NULL) {
1170f169c0eaSGlenn Lagasse 					ret = BE_ERR_NOMEM;
1171f169c0eaSGlenn Lagasse 					goto cleanup;
1172f169c0eaSGlenn Lagasse 				}
1173f169c0eaSGlenn Lagasse 				if ((buffer[nlines++] = strdup(menu_buf))
1174f169c0eaSGlenn Lagasse 				    == NULL) {
1175f169c0eaSGlenn Lagasse 					ret = BE_ERR_NOMEM;
1176f169c0eaSGlenn Lagasse 					goto cleanup;
1177f169c0eaSGlenn Lagasse 				}
1178f169c0eaSGlenn Lagasse 			} else if (write) {
1179f169c0eaSGlenn Lagasse 				/* Write this line out */
1180f169c0eaSGlenn Lagasse 				(void) fputs(menu_buf, tmp_menu_fp);
1181f169c0eaSGlenn Lagasse 			}
1182f169c0eaSGlenn Lagasse 		}
1183f169c0eaSGlenn Lagasse 	}
1184f169c0eaSGlenn Lagasse 
1185f169c0eaSGlenn Lagasse 	(void) fclose(menu_fp);
1186f169c0eaSGlenn Lagasse 	menu_fp = NULL;
1187f169c0eaSGlenn Lagasse 	(void) fclose(tmp_menu_fp);
1188f169c0eaSGlenn Lagasse 	tmp_menu_fp = NULL;
1189f169c0eaSGlenn Lagasse 
1190f169c0eaSGlenn Lagasse 	/* Copy the modified menu.lst into place */
1191f169c0eaSGlenn Lagasse 	if (rename(tmp_menu, menu) != 0) {
1192f169c0eaSGlenn Lagasse 		err = errno;
1193f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: "
1194f169c0eaSGlenn Lagasse 		    "failed to rename file %s to %s: %s\n"),
1195f169c0eaSGlenn Lagasse 		    tmp_menu, menu, strerror(err));
1196f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1197f169c0eaSGlenn Lagasse 		goto cleanup;
1198f169c0eaSGlenn Lagasse 	}
1199f169c0eaSGlenn Lagasse 	free(tmp_menu);
1200f169c0eaSGlenn Lagasse 	tmp_menu = NULL;
1201f169c0eaSGlenn Lagasse 
1202f169c0eaSGlenn Lagasse 	/*
1203f169c0eaSGlenn Lagasse 	 * If we've removed an entry, see if we need to
1204f169c0eaSGlenn Lagasse 	 * adjust the default value in the menu.lst.  If the
1205f169c0eaSGlenn Lagasse 	 * entry we've deleted comes before the default entry
1206f169c0eaSGlenn Lagasse 	 * we need to adjust the default value accordingly.
1207f169c0eaSGlenn Lagasse 	 *
1208f169c0eaSGlenn Lagasse 	 * be_has_grub is used here to check to see if this system
1209f169c0eaSGlenn Lagasse 	 * supports grub.
1210f169c0eaSGlenn Lagasse 	 */
1211f169c0eaSGlenn Lagasse 	if (be_has_grub() && num_entry_del > 0) {
1212f169c0eaSGlenn Lagasse 		if (entry_del <= default_entry) {
1213f169c0eaSGlenn Lagasse 			default_entry = default_entry - num_entry_del;
1214f169c0eaSGlenn Lagasse 			if (default_entry < 0)
1215f169c0eaSGlenn Lagasse 				default_entry = 0;
1216f169c0eaSGlenn Lagasse 
1217f169c0eaSGlenn Lagasse 			/*
1218f169c0eaSGlenn Lagasse 			 * Adjust the default value by rewriting the
1219f169c0eaSGlenn Lagasse 			 * menu.lst file.  This may be overkill, but to
1220f169c0eaSGlenn Lagasse 			 * preserve the location of the 'default' entry
1221f169c0eaSGlenn Lagasse 			 * in the file, we need to do this.
1222f169c0eaSGlenn Lagasse 			 */
1223f169c0eaSGlenn Lagasse 
1224f169c0eaSGlenn Lagasse 			/* Get handle to boot menu file */
1225f169c0eaSGlenn Lagasse 			if ((menu_fp = fopen(menu, "r")) == NULL) {
1226f169c0eaSGlenn Lagasse 				err = errno;
1227f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_remove_menu: "
1228f169c0eaSGlenn Lagasse 				    "failed to open menu.lst (%s): %s\n"),
1229f169c0eaSGlenn Lagasse 				    menu, strerror(err));
1230f169c0eaSGlenn Lagasse 				ret = errno_to_be_err(err);
1231f169c0eaSGlenn Lagasse 				goto cleanup;
1232f169c0eaSGlenn Lagasse 			}
1233f169c0eaSGlenn Lagasse 
1234f169c0eaSGlenn Lagasse 			/* Create a tmp file for the modified menu.lst */
1235f169c0eaSGlenn Lagasse 			tmp_menu_len = strlen(menu) + 7;
1236f169c0eaSGlenn Lagasse 			if ((tmp_menu = (char *)malloc(tmp_menu_len))
1237f169c0eaSGlenn Lagasse 			    == NULL) {
1238f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_remove_menu: "
1239f169c0eaSGlenn Lagasse 				    "malloc failed\n"));
1240f169c0eaSGlenn Lagasse 				ret = BE_ERR_NOMEM;
1241f169c0eaSGlenn Lagasse 				goto cleanup;
1242f169c0eaSGlenn Lagasse 			}
1243f169c0eaSGlenn Lagasse 			(void) memset(tmp_menu, 0, tmp_menu_len);
1244f169c0eaSGlenn Lagasse 			(void) strlcpy(tmp_menu, menu, tmp_menu_len);
1245f169c0eaSGlenn Lagasse 			(void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
1246f169c0eaSGlenn Lagasse 			if ((fd = mkstemp(tmp_menu)) == -1) {
1247f169c0eaSGlenn Lagasse 				err = errno;
1248f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_remove_menu: "
1249f169c0eaSGlenn Lagasse 				    "mkstemp failed: %s\n"), strerror(err));
1250f169c0eaSGlenn Lagasse 				ret = errno_to_be_err(err);
1251f169c0eaSGlenn Lagasse 				free(tmp_menu);
1252f169c0eaSGlenn Lagasse 				tmp_menu = NULL;
1253f169c0eaSGlenn Lagasse 				goto cleanup;
1254f169c0eaSGlenn Lagasse 			}
1255f169c0eaSGlenn Lagasse 			if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
1256f169c0eaSGlenn Lagasse 				err = errno;
1257f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_remove_menu: "
1258f169c0eaSGlenn Lagasse 				    "could not open tmp file for write: %s\n"),
1259f169c0eaSGlenn Lagasse 				    strerror(err));
1260f169c0eaSGlenn Lagasse 				(void) close(fd);
1261f169c0eaSGlenn Lagasse 				ret = errno_to_be_err(err);
1262f169c0eaSGlenn Lagasse 				goto cleanup;
1263f169c0eaSGlenn Lagasse 			}
1264f169c0eaSGlenn Lagasse 
1265f169c0eaSGlenn Lagasse 			while (fgets(menu_buf, BUFSIZ, menu_fp)) {
1266f169c0eaSGlenn Lagasse 				char tline [BUFSIZ];
1267f169c0eaSGlenn Lagasse 				char *tok = NULL;
1268f169c0eaSGlenn Lagasse 
1269f169c0eaSGlenn Lagasse 				(void) strlcpy(tline, menu_buf, sizeof (tline));
1270f169c0eaSGlenn Lagasse 
1271f169c0eaSGlenn Lagasse 				/* Tokenize line */
1272f169c0eaSGlenn Lagasse 				tok = strtok(tline, BE_WHITE_SPACE);
1273f169c0eaSGlenn Lagasse 
1274f169c0eaSGlenn Lagasse 				if (tok == NULL) {
1275f169c0eaSGlenn Lagasse 					/* Found empty line, write it out */
1276f169c0eaSGlenn Lagasse 					(void) fputs(menu_buf, tmp_menu_fp);
1277f169c0eaSGlenn Lagasse 				} else if (strcmp(tok, "default") == 0) {
1278f169c0eaSGlenn Lagasse 					/* Found the default line, adjust it */
1279f169c0eaSGlenn Lagasse 					(void) snprintf(tline, sizeof (tline),
1280f169c0eaSGlenn Lagasse 					    "default %d\n", default_entry);
1281f169c0eaSGlenn Lagasse 
1282f169c0eaSGlenn Lagasse 					(void) fputs(tline, tmp_menu_fp);
1283f169c0eaSGlenn Lagasse 				} else {
1284f169c0eaSGlenn Lagasse 					/* Pass through all other lines */
1285f169c0eaSGlenn Lagasse 					(void) fputs(menu_buf, tmp_menu_fp);
1286f169c0eaSGlenn Lagasse 				}
1287f169c0eaSGlenn Lagasse 			}
1288f169c0eaSGlenn Lagasse 
1289f169c0eaSGlenn Lagasse 			(void) fclose(menu_fp);
1290f169c0eaSGlenn Lagasse 			menu_fp = NULL;
1291f169c0eaSGlenn Lagasse 			(void) fclose(tmp_menu_fp);
1292f169c0eaSGlenn Lagasse 			tmp_menu_fp = NULL;
1293f169c0eaSGlenn Lagasse 
1294f169c0eaSGlenn Lagasse 			/* Copy the modified menu.lst into place */
1295f169c0eaSGlenn Lagasse 			if (rename(tmp_menu, menu) != 0) {
1296f169c0eaSGlenn Lagasse 				err = errno;
1297f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_remove_menu: "
1298f169c0eaSGlenn Lagasse 				    "failed to rename file %s to %s: %s\n"),
1299f169c0eaSGlenn Lagasse 				    tmp_menu, menu, strerror(err));
1300f169c0eaSGlenn Lagasse 				ret = errno_to_be_err(err);
1301f169c0eaSGlenn Lagasse 				goto cleanup;
1302f169c0eaSGlenn Lagasse 			}
1303f169c0eaSGlenn Lagasse 
1304f169c0eaSGlenn Lagasse 			free(tmp_menu);
1305f169c0eaSGlenn Lagasse 			tmp_menu = NULL;
1306f169c0eaSGlenn Lagasse 		}
1307f169c0eaSGlenn Lagasse 	}
1308f169c0eaSGlenn Lagasse 
1309f169c0eaSGlenn Lagasse 	/* Set the perms and ownership of the updated file */
1310f169c0eaSGlenn Lagasse 	if (chmod(menu, sb.st_mode) != 0) {
1311f169c0eaSGlenn Lagasse 		err = errno;
1312f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: "
1313f169c0eaSGlenn Lagasse 		    "failed to chmod %s: %s\n"), menu, strerror(err));
1314f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1315f169c0eaSGlenn Lagasse 		goto cleanup;
1316f169c0eaSGlenn Lagasse 	}
1317f169c0eaSGlenn Lagasse 	if (chown(menu, sb.st_uid, sb.st_gid) != 0) {
1318f169c0eaSGlenn Lagasse 		err = errno;
1319f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_remove_menu: "
1320f169c0eaSGlenn Lagasse 		    "failed to chown %s: %s\n"), menu, strerror(err));
1321f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1322f169c0eaSGlenn Lagasse 		goto cleanup;
1323f169c0eaSGlenn Lagasse 	}
1324f169c0eaSGlenn Lagasse 
1325f169c0eaSGlenn Lagasse cleanup:
1326f169c0eaSGlenn Lagasse 	if (pool_mounted) {
1327f169c0eaSGlenn Lagasse 		int err = BE_SUCCESS;
1328f169c0eaSGlenn Lagasse 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1329f169c0eaSGlenn Lagasse 		if (ret == BE_SUCCESS)
1330f169c0eaSGlenn Lagasse 			ret = err;
1331f169c0eaSGlenn Lagasse 		free(orig_mntpnt);
1332f169c0eaSGlenn Lagasse 		free(ptmp_mntpnt);
1333f169c0eaSGlenn Lagasse 	}
1334f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1335f169c0eaSGlenn Lagasse 
1336f169c0eaSGlenn Lagasse 	free(buffer);
1337f169c0eaSGlenn Lagasse 	if (menu_fp != NULL)
1338f169c0eaSGlenn Lagasse 		(void) fclose(menu_fp);
1339f169c0eaSGlenn Lagasse 	if (tmp_menu_fp != NULL)
1340f169c0eaSGlenn Lagasse 		(void) fclose(tmp_menu_fp);
1341f169c0eaSGlenn Lagasse 	if (tmp_menu != NULL) {
1342f169c0eaSGlenn Lagasse 		(void) unlink(tmp_menu);
1343f169c0eaSGlenn Lagasse 		free(tmp_menu);
1344f169c0eaSGlenn Lagasse 	}
1345f169c0eaSGlenn Lagasse 
1346f169c0eaSGlenn Lagasse 	return (ret);
1347f169c0eaSGlenn Lagasse }
1348f169c0eaSGlenn Lagasse 
1349f169c0eaSGlenn Lagasse /*
1350f169c0eaSGlenn Lagasse  * Function:	be_default_grub_bootfs
1351f169c0eaSGlenn Lagasse  * Description:	This function returns the dataset in the default entry of
1352f169c0eaSGlenn Lagasse  *		the grub menu. If no default entry is found with a valid bootfs
1353f169c0eaSGlenn Lagasse  *		entry NULL is returned.
1354f169c0eaSGlenn Lagasse  * Parameters:
1355f169c0eaSGlenn Lagasse  *		be_root_pool - This is the name of the root pool where the
1356f169c0eaSGlenn Lagasse  *			       grub menu can be found.
1357f169c0eaSGlenn Lagasse  *              def_bootfs - This is used to pass back the bootfs string. On
1358f169c0eaSGlenn Lagasse  *				error NULL is returned here.
1359f169c0eaSGlenn Lagasse  * Returns:
1360f169c0eaSGlenn Lagasse  *		Success - BE_SUCCESS is returned.
1361f169c0eaSGlenn Lagasse  *		Failure - a be_errno_t is returned.
1362f169c0eaSGlenn Lagasse  * Scope:
1363f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1364f169c0eaSGlenn Lagasse  */
1365f169c0eaSGlenn Lagasse int
1366f169c0eaSGlenn Lagasse be_default_grub_bootfs(const char *be_root_pool, char **def_bootfs)
1367f169c0eaSGlenn Lagasse {
1368f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1369f169c0eaSGlenn Lagasse 	char		grub_file[MAXPATHLEN];
1370f169c0eaSGlenn Lagasse 	FILE		*menu_fp;
1371f169c0eaSGlenn Lagasse 	char		line[BUFSIZ];
1372f169c0eaSGlenn Lagasse 	char		*pool_mntpnt = NULL;
1373f169c0eaSGlenn Lagasse 	char		*ptmp_mntpnt = NULL;
1374f169c0eaSGlenn Lagasse 	char		*orig_mntpnt = NULL;
1375f169c0eaSGlenn Lagasse 	int		default_entry = 0, entries = 0;
1376f169c0eaSGlenn Lagasse 	int		found_default = 0;
1377f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS;
1378f169c0eaSGlenn Lagasse 	boolean_t	pool_mounted = B_FALSE;
1379f169c0eaSGlenn Lagasse 
1380f169c0eaSGlenn Lagasse 	errno = 0;
1381f169c0eaSGlenn Lagasse 
1382f169c0eaSGlenn Lagasse 	/*
1383f169c0eaSGlenn Lagasse 	 * Check to see if this system supports grub
1384f169c0eaSGlenn Lagasse 	 */
1385f169c0eaSGlenn Lagasse 	if (!be_has_grub()) {
1386f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_default_grub_bootfs: operation "
1387f169c0eaSGlenn Lagasse 		    "not supported on this architecture\n"));
1388f169c0eaSGlenn Lagasse 		return (BE_ERR_NOTSUP);
1389f169c0eaSGlenn Lagasse 	}
1390f169c0eaSGlenn Lagasse 
1391f169c0eaSGlenn Lagasse 	*def_bootfs = NULL;
1392f169c0eaSGlenn Lagasse 
1393f169c0eaSGlenn Lagasse 	/* Get handle to pool dataset */
1394f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1395f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_default_grub_bootfs: "
1396f169c0eaSGlenn Lagasse 		    "failed to open pool dataset for %s: %s"),
1397f169c0eaSGlenn Lagasse 		    be_root_pool, libzfs_error_description(g_zfs));
1398f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1399f169c0eaSGlenn Lagasse 	}
1400f169c0eaSGlenn Lagasse 
1401f169c0eaSGlenn Lagasse 	/*
1402f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1403f169c0eaSGlenn Lagasse 	 * attempt to mount it.
1404f169c0eaSGlenn Lagasse 	 */
1405f169c0eaSGlenn Lagasse 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1406f169c0eaSGlenn Lagasse 	    &pool_mounted)) != BE_SUCCESS) {
1407f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_default_grub_bootfs: pool dataset "
1408f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), be_root_pool);
1409f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1410f169c0eaSGlenn Lagasse 		return (ret);
1411f169c0eaSGlenn Lagasse 	}
1412f169c0eaSGlenn Lagasse 
1413f169c0eaSGlenn Lagasse 	/*
1414f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
1415f169c0eaSGlenn Lagasse 	 */
1416f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1417f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_default_grub_bootfs: failed "
1418f169c0eaSGlenn Lagasse 		    "to get mount point for the root pool. Can't set "
1419f169c0eaSGlenn Lagasse 		    "the default BE in the grub menu.\n"));
1420f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
1421f169c0eaSGlenn Lagasse 		goto cleanup;
1422f169c0eaSGlenn Lagasse 	}
1423f169c0eaSGlenn Lagasse 
1424f169c0eaSGlenn Lagasse 	(void) snprintf(grub_file, MAXPATHLEN, "%s%s",
1425f169c0eaSGlenn Lagasse 	    pool_mntpnt, BE_GRUB_MENU);
1426f169c0eaSGlenn Lagasse 
1427de1ab35cSAlexander Eremin 	if ((ret = be_open_menu((char *)be_root_pool, grub_file,
1428f169c0eaSGlenn Lagasse 	    &menu_fp, "r", B_FALSE)) != BE_SUCCESS) {
1429f169c0eaSGlenn Lagasse 		goto cleanup;
1430f169c0eaSGlenn Lagasse 	} else if (menu_fp == NULL) {
1431f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
1432f169c0eaSGlenn Lagasse 		goto cleanup;
1433f169c0eaSGlenn Lagasse 	}
1434f169c0eaSGlenn Lagasse 
1435f169c0eaSGlenn Lagasse 	free(pool_mntpnt);
1436f169c0eaSGlenn Lagasse 	pool_mntpnt = NULL;
1437f169c0eaSGlenn Lagasse 
1438f169c0eaSGlenn Lagasse 	while (fgets(line, BUFSIZ, menu_fp)) {
1439f169c0eaSGlenn Lagasse 		char *tok = strtok(line, BE_WHITE_SPACE);
1440f169c0eaSGlenn Lagasse 
1441f169c0eaSGlenn Lagasse 		if (tok != NULL && tok[0] != '#') {
1442f169c0eaSGlenn Lagasse 			if (!found_default) {
1443f169c0eaSGlenn Lagasse 				if (strcmp(tok, "default") == 0) {
1444f169c0eaSGlenn Lagasse 					tok = strtok(NULL, BE_WHITE_SPACE);
1445f169c0eaSGlenn Lagasse 					if (tok != NULL) {
1446f169c0eaSGlenn Lagasse 						default_entry = atoi(tok);
1447f169c0eaSGlenn Lagasse 						rewind(menu_fp);
1448f169c0eaSGlenn Lagasse 						found_default = 1;
1449f169c0eaSGlenn Lagasse 					}
1450f169c0eaSGlenn Lagasse 				}
1451f169c0eaSGlenn Lagasse 				continue;
1452f169c0eaSGlenn Lagasse 			}
1453f169c0eaSGlenn Lagasse 			if (strcmp(tok, "title") == 0) {
1454f169c0eaSGlenn Lagasse 				entries++;
1455f169c0eaSGlenn Lagasse 			} else if (default_entry == entries - 1) {
1456f169c0eaSGlenn Lagasse 				if (strcmp(tok, "bootfs") == 0) {
1457f169c0eaSGlenn Lagasse 					tok = strtok(NULL, BE_WHITE_SPACE);
1458f169c0eaSGlenn Lagasse 					(void) fclose(menu_fp);
1459f169c0eaSGlenn Lagasse 
1460f169c0eaSGlenn Lagasse 					if (tok == NULL) {
1461f169c0eaSGlenn Lagasse 						ret = BE_SUCCESS;
1462f169c0eaSGlenn Lagasse 						goto cleanup;
1463f169c0eaSGlenn Lagasse 					}
1464f169c0eaSGlenn Lagasse 
1465f169c0eaSGlenn Lagasse 					if ((*def_bootfs = strdup(tok)) !=
1466f169c0eaSGlenn Lagasse 					    NULL) {
1467f169c0eaSGlenn Lagasse 						ret = BE_SUCCESS;
1468f169c0eaSGlenn Lagasse 						goto cleanup;
1469f169c0eaSGlenn Lagasse 					}
1470f169c0eaSGlenn Lagasse 					be_print_err(gettext(
1471f169c0eaSGlenn Lagasse 					    "be_default_grub_bootfs: "
1472f169c0eaSGlenn Lagasse 					    "memory allocation failed\n"));
1473f169c0eaSGlenn Lagasse 					ret = BE_ERR_NOMEM;
1474f169c0eaSGlenn Lagasse 					goto cleanup;
1475f169c0eaSGlenn Lagasse 				}
1476f169c0eaSGlenn Lagasse 			} else if (default_entry < entries - 1) {
1477f169c0eaSGlenn Lagasse 				/*
1478f169c0eaSGlenn Lagasse 				 * no bootfs entry for the default entry.
1479f169c0eaSGlenn Lagasse 				 */
1480f169c0eaSGlenn Lagasse 				break;
1481f169c0eaSGlenn Lagasse 			}
1482f169c0eaSGlenn Lagasse 		}
1483f169c0eaSGlenn Lagasse 	}
1484f169c0eaSGlenn Lagasse 	(void) fclose(menu_fp);
1485f169c0eaSGlenn Lagasse 
1486f169c0eaSGlenn Lagasse cleanup:
1487f169c0eaSGlenn Lagasse 	if (pool_mounted) {
1488f169c0eaSGlenn Lagasse 		int err = BE_SUCCESS;
1489f169c0eaSGlenn Lagasse 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1490f169c0eaSGlenn Lagasse 		if (ret == BE_SUCCESS)
1491f169c0eaSGlenn Lagasse 			ret = err;
1492f169c0eaSGlenn Lagasse 		free(orig_mntpnt);
1493f169c0eaSGlenn Lagasse 		free(ptmp_mntpnt);
1494f169c0eaSGlenn Lagasse 	}
1495f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1496f169c0eaSGlenn Lagasse 	return (ret);
1497f169c0eaSGlenn Lagasse }
1498f169c0eaSGlenn Lagasse 
1499f169c0eaSGlenn Lagasse /*
1500f169c0eaSGlenn Lagasse  * Function:	be_change_grub_default
1501f169c0eaSGlenn Lagasse  * Description:	This function takes two parameters. These are the name of
1502f169c0eaSGlenn Lagasse  *		the BE we want to have as the default booted in the grub
1503f169c0eaSGlenn Lagasse  *		menu and the root pool where the path to the grub menu exists.
1504f169c0eaSGlenn Lagasse  *		The code takes this and finds the BE's entry in the grub menu
1505f169c0eaSGlenn Lagasse  *		and changes the default entry to point to that entry in the
1506f169c0eaSGlenn Lagasse  *		list.
1507f169c0eaSGlenn Lagasse  * Parameters:
1508f169c0eaSGlenn Lagasse  *		be_name - This is the name of the BE wanted as the default
1509f169c0eaSGlenn Lagasse  *			for the next boot.
1510f169c0eaSGlenn Lagasse  *		be_root_pool - This is the name of the root pool where the
1511f169c0eaSGlenn Lagasse  *			grub menu can be found.
1512f169c0eaSGlenn Lagasse  * Returns:
1513f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1514f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1515f169c0eaSGlenn Lagasse  * Scope:
1516f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1517f169c0eaSGlenn Lagasse  */
1518f169c0eaSGlenn Lagasse int
1519f169c0eaSGlenn Lagasse be_change_grub_default(char *be_name, char *be_root_pool)
1520f169c0eaSGlenn Lagasse {
1521f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1522f169c0eaSGlenn Lagasse 	char	grub_file[MAXPATHLEN];
1523fafb665dSToomas Soome 	char	*temp_grub = NULL;
1524f169c0eaSGlenn Lagasse 	char	*pool_mntpnt = NULL;
1525f169c0eaSGlenn Lagasse 	char	*ptmp_mntpnt = NULL;
1526f169c0eaSGlenn Lagasse 	char	*orig_mntpnt = NULL;
1527f169c0eaSGlenn Lagasse 	char	line[BUFSIZ];
1528f169c0eaSGlenn Lagasse 	char	temp_line[BUFSIZ];
1529f169c0eaSGlenn Lagasse 	char	be_root_ds[MAXPATHLEN];
1530f169c0eaSGlenn Lagasse 	FILE	*grub_fp = NULL;
1531f169c0eaSGlenn Lagasse 	FILE	*temp_fp = NULL;
1532f169c0eaSGlenn Lagasse 	struct stat	sb;
1533f169c0eaSGlenn Lagasse 	int	temp_grub_len = 0;
1534f169c0eaSGlenn Lagasse 	int	fd, entries = 0;
1535f169c0eaSGlenn Lagasse 	int	err = 0;
1536f169c0eaSGlenn Lagasse 	int	ret = BE_SUCCESS;
1537f169c0eaSGlenn Lagasse 	boolean_t	found_default = B_FALSE;
1538f169c0eaSGlenn Lagasse 	boolean_t	pool_mounted = B_FALSE;
1539f169c0eaSGlenn Lagasse 
1540f169c0eaSGlenn Lagasse 	errno = 0;
1541f169c0eaSGlenn Lagasse 
1542f169c0eaSGlenn Lagasse 	/*
1543f169c0eaSGlenn Lagasse 	 * Check to see if this system supports grub
1544f169c0eaSGlenn Lagasse 	 */
1545f169c0eaSGlenn Lagasse 	if (!be_has_grub()) {
1546f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: operation "
1547f169c0eaSGlenn Lagasse 		    "not supported on this architecture\n"));
1548f169c0eaSGlenn Lagasse 		return (BE_ERR_NOTSUP);
1549f169c0eaSGlenn Lagasse 	}
1550f169c0eaSGlenn Lagasse 
1551f169c0eaSGlenn Lagasse 	/* Generate string for BE's root dataset */
1552f169c0eaSGlenn Lagasse 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
1553f169c0eaSGlenn Lagasse 
1554f169c0eaSGlenn Lagasse 	/* Get handle to pool dataset */
1555f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1556f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: "
1557f169c0eaSGlenn Lagasse 		    "failed to open pool dataset for %s: %s"),
1558f169c0eaSGlenn Lagasse 		    be_root_pool, libzfs_error_description(g_zfs));
1559f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1560f169c0eaSGlenn Lagasse 	}
1561f169c0eaSGlenn Lagasse 
1562f169c0eaSGlenn Lagasse 	/*
1563f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1564f169c0eaSGlenn Lagasse 	 * attempt to mount it.
1565f169c0eaSGlenn Lagasse 	 */
1566f169c0eaSGlenn Lagasse 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1567f169c0eaSGlenn Lagasse 	    &pool_mounted)) != BE_SUCCESS) {
1568f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: pool dataset "
1569f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), be_root_pool);
1570f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1571f169c0eaSGlenn Lagasse 		return (ret);
1572f169c0eaSGlenn Lagasse 	}
1573f169c0eaSGlenn Lagasse 
1574f169c0eaSGlenn Lagasse 	/*
1575f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
1576f169c0eaSGlenn Lagasse 	 */
1577f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1578f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: pool "
1579f169c0eaSGlenn Lagasse 		    "dataset (%s) is not mounted. Can't set "
1580f169c0eaSGlenn Lagasse 		    "the default BE in the grub menu.\n"), be_root_pool);
1581f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
1582f169c0eaSGlenn Lagasse 		goto cleanup;
1583f169c0eaSGlenn Lagasse 	}
1584f169c0eaSGlenn Lagasse 
1585f169c0eaSGlenn Lagasse 	(void) snprintf(grub_file, MAXPATHLEN, "%s%s",
1586f169c0eaSGlenn Lagasse 	    pool_mntpnt, BE_GRUB_MENU);
1587f169c0eaSGlenn Lagasse 
1588de1ab35cSAlexander Eremin 	if ((ret = be_open_menu(be_root_pool, grub_file,
1589f169c0eaSGlenn Lagasse 	    &grub_fp, "r+", B_TRUE)) != BE_SUCCESS) {
1590f169c0eaSGlenn Lagasse 		goto cleanup;
1591f169c0eaSGlenn Lagasse 	} else if (grub_fp == NULL) {
1592f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
1593f169c0eaSGlenn Lagasse 		goto cleanup;
1594f169c0eaSGlenn Lagasse 	}
1595f169c0eaSGlenn Lagasse 
1596f169c0eaSGlenn Lagasse 	free(pool_mntpnt);
1597f169c0eaSGlenn Lagasse 	pool_mntpnt = NULL;
1598f169c0eaSGlenn Lagasse 
1599f169c0eaSGlenn Lagasse 	/* Grab the stats of the original menu file */
1600f169c0eaSGlenn Lagasse 	if (stat(grub_file, &sb) != 0) {
1601f169c0eaSGlenn Lagasse 		err = errno;
1602f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: "
1603f169c0eaSGlenn Lagasse 		    "failed to stat file %s: %s\n"), grub_file, strerror(err));
1604f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1605f169c0eaSGlenn Lagasse 		goto cleanup;
1606f169c0eaSGlenn Lagasse 	}
1607f169c0eaSGlenn Lagasse 
1608f169c0eaSGlenn Lagasse 	/* Create a tmp file for the modified menu.lst */
1609f169c0eaSGlenn Lagasse 	temp_grub_len = strlen(grub_file) + 7;
1610f169c0eaSGlenn Lagasse 	if ((temp_grub = (char *)malloc(temp_grub_len)) == NULL) {
1611f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: "
1612f169c0eaSGlenn Lagasse 		    "malloc failed\n"));
1613f169c0eaSGlenn Lagasse 		ret = BE_ERR_NOMEM;
1614f169c0eaSGlenn Lagasse 		goto cleanup;
1615f169c0eaSGlenn Lagasse 	}
1616f169c0eaSGlenn Lagasse 	(void) memset(temp_grub, 0, temp_grub_len);
1617f169c0eaSGlenn Lagasse 	(void) strlcpy(temp_grub, grub_file, temp_grub_len);
1618f169c0eaSGlenn Lagasse 	(void) strlcat(temp_grub, "XXXXXX", temp_grub_len);
1619f169c0eaSGlenn Lagasse 	if ((fd = mkstemp(temp_grub)) == -1) {
1620f169c0eaSGlenn Lagasse 		err = errno;
1621f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: "
1622f169c0eaSGlenn Lagasse 		    "mkstemp failed: %s\n"), strerror(err));
1623f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1624f169c0eaSGlenn Lagasse 		free(temp_grub);
1625f169c0eaSGlenn Lagasse 		temp_grub = NULL;
1626f169c0eaSGlenn Lagasse 		goto cleanup;
1627f169c0eaSGlenn Lagasse 	}
1628f169c0eaSGlenn Lagasse 	if ((temp_fp = fdopen(fd, "w")) == NULL) {
1629f169c0eaSGlenn Lagasse 		err = errno;
1630f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: "
1631f169c0eaSGlenn Lagasse 		    "failed to open %s file: %s\n"),
1632f169c0eaSGlenn Lagasse 		    temp_grub, strerror(err));
1633f169c0eaSGlenn Lagasse 		(void) close(fd);
1634f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1635f169c0eaSGlenn Lagasse 		goto cleanup;
1636f169c0eaSGlenn Lagasse 	}
1637f169c0eaSGlenn Lagasse 
1638f169c0eaSGlenn Lagasse 	while (fgets(line, BUFSIZ, grub_fp)) {
1639f169c0eaSGlenn Lagasse 		char *tok = strtok(line, BE_WHITE_SPACE);
1640f169c0eaSGlenn Lagasse 
1641f169c0eaSGlenn Lagasse 		if (tok == NULL || tok[0] == '#') {
1642f169c0eaSGlenn Lagasse 			continue;
1643f169c0eaSGlenn Lagasse 		} else if (strcmp(tok, "title") == 0) {
1644f169c0eaSGlenn Lagasse 			entries++;
1645f169c0eaSGlenn Lagasse 			continue;
1646f169c0eaSGlenn Lagasse 		} else if (strcmp(tok, "bootfs") == 0) {
1647f169c0eaSGlenn Lagasse 			char *bootfs = strtok(NULL, BE_WHITE_SPACE);
1648f169c0eaSGlenn Lagasse 			if (bootfs == NULL)
1649f169c0eaSGlenn Lagasse 				continue;
1650f169c0eaSGlenn Lagasse 
1651f169c0eaSGlenn Lagasse 			if (strcmp(bootfs, be_root_ds) == 0) {
1652f169c0eaSGlenn Lagasse 				found_default = B_TRUE;
1653f169c0eaSGlenn Lagasse 				break;
1654f169c0eaSGlenn Lagasse 			}
1655f169c0eaSGlenn Lagasse 		}
1656f169c0eaSGlenn Lagasse 	}
1657f169c0eaSGlenn Lagasse 
1658f169c0eaSGlenn Lagasse 	if (!found_default) {
1659f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: failed "
1660f169c0eaSGlenn Lagasse 		    "to find entry for %s in the grub menu\n"),
1661f169c0eaSGlenn Lagasse 		    be_name);
1662f169c0eaSGlenn Lagasse 		ret = BE_ERR_BE_NOENT;
1663f169c0eaSGlenn Lagasse 		goto cleanup;
1664f169c0eaSGlenn Lagasse 	}
1665f169c0eaSGlenn Lagasse 
1666f169c0eaSGlenn Lagasse 	rewind(grub_fp);
1667f169c0eaSGlenn Lagasse 
1668f169c0eaSGlenn Lagasse 	while (fgets(line, BUFSIZ, grub_fp)) {
1669f169c0eaSGlenn Lagasse 		char *tok = NULL;
1670f169c0eaSGlenn Lagasse 
1671f169c0eaSGlenn Lagasse 		(void) strncpy(temp_line, line, BUFSIZ);
1672f169c0eaSGlenn Lagasse 
1673f169c0eaSGlenn Lagasse 		if ((tok = strtok(temp_line, BE_WHITE_SPACE)) != NULL &&
1674f169c0eaSGlenn Lagasse 		    strcmp(tok, "default") == 0) {
1675f169c0eaSGlenn Lagasse 			(void) snprintf(temp_line, BUFSIZ, "default %d\n",
1676f169c0eaSGlenn Lagasse 			    entries - 1 >= 0 ? entries - 1 : 0);
1677f169c0eaSGlenn Lagasse 			(void) fputs(temp_line, temp_fp);
1678f169c0eaSGlenn Lagasse 		} else {
1679f169c0eaSGlenn Lagasse 			(void) fputs(line, temp_fp);
1680f169c0eaSGlenn Lagasse 		}
1681f169c0eaSGlenn Lagasse 	}
1682f169c0eaSGlenn Lagasse 
1683f169c0eaSGlenn Lagasse 	(void) fclose(grub_fp);
1684f169c0eaSGlenn Lagasse 	grub_fp = NULL;
1685f169c0eaSGlenn Lagasse 	(void) fclose(temp_fp);
1686f169c0eaSGlenn Lagasse 	temp_fp = NULL;
1687f169c0eaSGlenn Lagasse 
1688f169c0eaSGlenn Lagasse 	if (rename(temp_grub, grub_file) != 0) {
1689f169c0eaSGlenn Lagasse 		err = errno;
1690f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: "
1691f169c0eaSGlenn Lagasse 		    "failed to rename file %s to %s: %s\n"),
1692f169c0eaSGlenn Lagasse 		    temp_grub, grub_file, strerror(err));
1693f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1694f169c0eaSGlenn Lagasse 		goto cleanup;
1695f169c0eaSGlenn Lagasse 	}
1696f169c0eaSGlenn Lagasse 	free(temp_grub);
1697f169c0eaSGlenn Lagasse 	temp_grub = NULL;
1698f169c0eaSGlenn Lagasse 
1699f169c0eaSGlenn Lagasse 	/* Set the perms and ownership of the updated file */
1700f169c0eaSGlenn Lagasse 	if (chmod(grub_file, sb.st_mode) != 0) {
1701f169c0eaSGlenn Lagasse 		err = errno;
1702f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: "
1703f169c0eaSGlenn Lagasse 		    "failed to chmod %s: %s\n"), grub_file, strerror(err));
1704f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1705f169c0eaSGlenn Lagasse 		goto cleanup;
1706f169c0eaSGlenn Lagasse 	}
1707f169c0eaSGlenn Lagasse 	if (chown(grub_file, sb.st_uid, sb.st_gid) != 0) {
1708f169c0eaSGlenn Lagasse 		err = errno;
1709f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_change_grub_default: "
1710f169c0eaSGlenn Lagasse 		    "failed to chown %s: %s\n"), grub_file, strerror(err));
1711f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1712f169c0eaSGlenn Lagasse 	}
1713f169c0eaSGlenn Lagasse 
1714f169c0eaSGlenn Lagasse cleanup:
1715f169c0eaSGlenn Lagasse 	if (pool_mounted) {
1716f169c0eaSGlenn Lagasse 		int err = BE_SUCCESS;
1717f169c0eaSGlenn Lagasse 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1718f169c0eaSGlenn Lagasse 		if (ret == BE_SUCCESS)
1719f169c0eaSGlenn Lagasse 			ret = err;
1720f169c0eaSGlenn Lagasse 		free(orig_mntpnt);
1721f169c0eaSGlenn Lagasse 		free(ptmp_mntpnt);
1722f169c0eaSGlenn Lagasse 	}
1723f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1724f169c0eaSGlenn Lagasse 	if (grub_fp != NULL)
1725f169c0eaSGlenn Lagasse 		(void) fclose(grub_fp);
1726f169c0eaSGlenn Lagasse 	if (temp_fp != NULL)
1727f169c0eaSGlenn Lagasse 		(void) fclose(temp_fp);
1728f169c0eaSGlenn Lagasse 	if (temp_grub != NULL) {
1729f169c0eaSGlenn Lagasse 		(void) unlink(temp_grub);
1730f169c0eaSGlenn Lagasse 		free(temp_grub);
1731f169c0eaSGlenn Lagasse 	}
1732f169c0eaSGlenn Lagasse 
1733f169c0eaSGlenn Lagasse 	return (ret);
1734f169c0eaSGlenn Lagasse }
1735f169c0eaSGlenn Lagasse 
1736f169c0eaSGlenn Lagasse /*
1737f169c0eaSGlenn Lagasse  * Function:	be_update_menu
1738f169c0eaSGlenn Lagasse  * Description:	This function is used by be_rename to change the BE name in
1739f169c0eaSGlenn Lagasse  *		an existing entry in the grub menu to the new name of the BE.
1740f169c0eaSGlenn Lagasse  * Parameters:
1741f169c0eaSGlenn Lagasse  *		be_orig_name - the original name of the BE
1742f169c0eaSGlenn Lagasse  *		be_new_name - the new name the BE is being renameed to.
1743f169c0eaSGlenn Lagasse  *		be_root_pool - The pool which contains the grub menu
1744f169c0eaSGlenn Lagasse  *		boot_pool - the pool where the BE is, if different than
1745f169c0eaSGlenn Lagasse  *			the pool containing the boot menu.  If this is
1746f169c0eaSGlenn Lagasse  *			NULL it will be set to be_root_pool.
1747f169c0eaSGlenn Lagasse  * Returns:
1748f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1749f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1750f169c0eaSGlenn Lagasse  * Scope:
1751f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
1752f169c0eaSGlenn Lagasse  */
1753f169c0eaSGlenn Lagasse int
1754f169c0eaSGlenn Lagasse be_update_menu(char *be_orig_name, char *be_new_name, char *be_root_pool,
1755f169c0eaSGlenn Lagasse     char *boot_pool)
1756f169c0eaSGlenn Lagasse {
1757f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp = NULL;
1758f169c0eaSGlenn Lagasse 	char menu_file[MAXPATHLEN];
1759f169c0eaSGlenn Lagasse 	char be_root_ds[MAXPATHLEN];
1760f169c0eaSGlenn Lagasse 	char be_new_root_ds[MAXPATHLEN];
1761f169c0eaSGlenn Lagasse 	char line[BUFSIZ];
1762f169c0eaSGlenn Lagasse 	char *pool_mntpnt = NULL;
1763f169c0eaSGlenn Lagasse 	char *ptmp_mntpnt = NULL;
1764f169c0eaSGlenn Lagasse 	char *orig_mntpnt = NULL;
1765f169c0eaSGlenn Lagasse 	char *temp_menu = NULL;
1766f169c0eaSGlenn Lagasse 	FILE *menu_fp = NULL;
1767f169c0eaSGlenn Lagasse 	FILE *new_fp = NULL;
1768f169c0eaSGlenn Lagasse 	struct stat sb;
1769f169c0eaSGlenn Lagasse 	int temp_menu_len = 0;
1770f169c0eaSGlenn Lagasse 	int tmp_fd;
1771f169c0eaSGlenn Lagasse 	int ret = BE_SUCCESS;
1772f169c0eaSGlenn Lagasse 	int err = 0;
1773f169c0eaSGlenn Lagasse 	boolean_t pool_mounted = B_FALSE;
1774f169c0eaSGlenn Lagasse 
1775f169c0eaSGlenn Lagasse 	errno = 0;
1776f169c0eaSGlenn Lagasse 
1777f169c0eaSGlenn Lagasse 	if (boot_pool == NULL)
1778f169c0eaSGlenn Lagasse 		boot_pool = be_root_pool;
1779f169c0eaSGlenn Lagasse 
1780f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1781f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: failed to open "
1782f169c0eaSGlenn Lagasse 		    "pool dataset for %s: %s\n"), be_root_pool,
1783f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1784f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1785f169c0eaSGlenn Lagasse 	}
1786f169c0eaSGlenn Lagasse 
1787f169c0eaSGlenn Lagasse 	/*
1788f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1789f169c0eaSGlenn Lagasse 	 * attempt to mount it.
1790f169c0eaSGlenn Lagasse 	 */
1791f169c0eaSGlenn Lagasse 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1792f169c0eaSGlenn Lagasse 	    &pool_mounted)) != BE_SUCCESS) {
1793f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: pool dataset "
1794f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), be_root_pool);
1795f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1796f169c0eaSGlenn Lagasse 		return (ret);
1797f169c0eaSGlenn Lagasse 	}
1798f169c0eaSGlenn Lagasse 
1799f169c0eaSGlenn Lagasse 	/*
1800f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
1801f169c0eaSGlenn Lagasse 	 */
1802f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1803f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: failed "
1804f169c0eaSGlenn Lagasse 		    "to get mount point for the root pool. Can't set "
1805f169c0eaSGlenn Lagasse 		    "the default BE in the grub menu.\n"));
1806f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
1807f169c0eaSGlenn Lagasse 		goto cleanup;
1808f169c0eaSGlenn Lagasse 	}
1809f169c0eaSGlenn Lagasse 
1810f169c0eaSGlenn Lagasse 	/*
1811f169c0eaSGlenn Lagasse 	 * Check to see if this system supports grub
1812f169c0eaSGlenn Lagasse 	 */
1813f169c0eaSGlenn Lagasse 	if (be_has_grub()) {
1814f169c0eaSGlenn Lagasse 		(void) snprintf(menu_file, sizeof (menu_file),
1815f169c0eaSGlenn Lagasse 		    "%s%s", pool_mntpnt, BE_GRUB_MENU);
1816f169c0eaSGlenn Lagasse 	} else {
1817f169c0eaSGlenn Lagasse 		(void) snprintf(menu_file, sizeof (menu_file),
1818f169c0eaSGlenn Lagasse 		    "%s%s", pool_mntpnt, BE_SPARC_MENU);
1819f169c0eaSGlenn Lagasse 	}
1820f169c0eaSGlenn Lagasse 
1821f169c0eaSGlenn Lagasse 	be_make_root_ds(be_root_pool, be_orig_name, be_root_ds,
1822f169c0eaSGlenn Lagasse 	    sizeof (be_root_ds));
1823f169c0eaSGlenn Lagasse 	be_make_root_ds(be_root_pool, be_new_name, be_new_root_ds,
1824f169c0eaSGlenn Lagasse 	    sizeof (be_new_root_ds));
1825f169c0eaSGlenn Lagasse 
1826de1ab35cSAlexander Eremin 	if ((ret = be_open_menu(be_root_pool, menu_file,
1827f169c0eaSGlenn Lagasse 	    &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
1828f169c0eaSGlenn Lagasse 		goto cleanup;
1829f169c0eaSGlenn Lagasse 	} else if (menu_fp == NULL) {
1830f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
1831f169c0eaSGlenn Lagasse 		goto cleanup;
1832f169c0eaSGlenn Lagasse 	}
1833f169c0eaSGlenn Lagasse 
1834f169c0eaSGlenn Lagasse 	free(pool_mntpnt);
1835f169c0eaSGlenn Lagasse 	pool_mntpnt = NULL;
1836f169c0eaSGlenn Lagasse 
1837f169c0eaSGlenn Lagasse 	/* Grab the stat of the original menu file */
1838f169c0eaSGlenn Lagasse 	if (stat(menu_file, &sb) != 0) {
1839f169c0eaSGlenn Lagasse 		err = errno;
1840f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: "
1841f169c0eaSGlenn Lagasse 		    "failed to stat file %s: %s\n"), menu_file, strerror(err));
1842f169c0eaSGlenn Lagasse 		(void) fclose(menu_fp);
1843f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1844f169c0eaSGlenn Lagasse 		goto cleanup;
1845f169c0eaSGlenn Lagasse 	}
1846f169c0eaSGlenn Lagasse 
1847f169c0eaSGlenn Lagasse 	/* Create tmp file for modified menu.lst */
1848f169c0eaSGlenn Lagasse 	temp_menu_len = strlen(menu_file) + 7;
1849f169c0eaSGlenn Lagasse 	if ((temp_menu = (char *)malloc(temp_menu_len))
1850f169c0eaSGlenn Lagasse 	    == NULL) {
1851f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: "
1852f169c0eaSGlenn Lagasse 		    "malloc failed\n"));
1853f169c0eaSGlenn Lagasse 		(void) fclose(menu_fp);
1854f169c0eaSGlenn Lagasse 		ret = BE_ERR_NOMEM;
1855f169c0eaSGlenn Lagasse 		goto cleanup;
1856f169c0eaSGlenn Lagasse 	}
1857f169c0eaSGlenn Lagasse 	(void) memset(temp_menu, 0, temp_menu_len);
1858f169c0eaSGlenn Lagasse 	(void) strlcpy(temp_menu, menu_file, temp_menu_len);
1859f169c0eaSGlenn Lagasse 	(void) strlcat(temp_menu, "XXXXXX", temp_menu_len);
1860f169c0eaSGlenn Lagasse 	if ((tmp_fd = mkstemp(temp_menu)) == -1) {
1861f169c0eaSGlenn Lagasse 		err = errno;
1862f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: "
1863f169c0eaSGlenn Lagasse 		    "mkstemp failed: %s\n"), strerror(err));
1864f169c0eaSGlenn Lagasse 		(void) fclose(menu_fp);
1865f169c0eaSGlenn Lagasse 		free(temp_menu);
1866f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1867f169c0eaSGlenn Lagasse 		goto cleanup;
1868f169c0eaSGlenn Lagasse 	}
1869f169c0eaSGlenn Lagasse 	if ((new_fp = fdopen(tmp_fd, "w")) == NULL) {
1870f169c0eaSGlenn Lagasse 		err = errno;
1871f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: "
1872f169c0eaSGlenn Lagasse 		    "fdopen failed: %s\n"), strerror(err));
1873f169c0eaSGlenn Lagasse 		(void) close(tmp_fd);
1874f169c0eaSGlenn Lagasse 		(void) fclose(menu_fp);
1875f169c0eaSGlenn Lagasse 		free(temp_menu);
1876f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1877f169c0eaSGlenn Lagasse 		goto cleanup;
1878f169c0eaSGlenn Lagasse 	}
1879f169c0eaSGlenn Lagasse 
1880f169c0eaSGlenn Lagasse 	while (fgets(line, BUFSIZ, menu_fp)) {
1881f169c0eaSGlenn Lagasse 		char tline[BUFSIZ];
1882f169c0eaSGlenn Lagasse 		char new_line[BUFSIZ];
1883f169c0eaSGlenn Lagasse 		char *c = NULL;
1884f169c0eaSGlenn Lagasse 
1885f169c0eaSGlenn Lagasse 		(void) strlcpy(tline, line, sizeof (tline));
1886f169c0eaSGlenn Lagasse 
1887f169c0eaSGlenn Lagasse 		/* Tokenize line */
1888f169c0eaSGlenn Lagasse 		c = strtok(tline, BE_WHITE_SPACE);
1889f169c0eaSGlenn Lagasse 
1890f169c0eaSGlenn Lagasse 		if (c == NULL) {
1891f169c0eaSGlenn Lagasse 			/* Found empty line, write it out. */
1892f169c0eaSGlenn Lagasse 			(void) fputs(line, new_fp);
1893f169c0eaSGlenn Lagasse 		} else if (c[0] == '#') {
1894f169c0eaSGlenn Lagasse 			/* Found a comment line, write it out. */
1895f169c0eaSGlenn Lagasse 			(void) fputs(line, new_fp);
1896f169c0eaSGlenn Lagasse 		} else if (strcmp(c, "title") == 0) {
1897f169c0eaSGlenn Lagasse 			char *name = NULL;
1898f169c0eaSGlenn Lagasse 			char *desc = NULL;
1899f169c0eaSGlenn Lagasse 
1900f169c0eaSGlenn Lagasse 			/*
1901f169c0eaSGlenn Lagasse 			 * Found a 'title' line, parse out BE name or
1902f169c0eaSGlenn Lagasse 			 * the description.
1903f169c0eaSGlenn Lagasse 			 */
1904f169c0eaSGlenn Lagasse 			name = strtok(NULL, BE_WHITE_SPACE);
1905f169c0eaSGlenn Lagasse 
1906f169c0eaSGlenn Lagasse 			if (name == NULL) {
1907f169c0eaSGlenn Lagasse 				/*
1908f169c0eaSGlenn Lagasse 				 * Nothing after 'title', just push
1909f169c0eaSGlenn Lagasse 				 * this line through
1910f169c0eaSGlenn Lagasse 				 */
1911f169c0eaSGlenn Lagasse 				(void) fputs(line, new_fp);
1912f169c0eaSGlenn Lagasse 			} else {
1913f169c0eaSGlenn Lagasse 				/*
1914f169c0eaSGlenn Lagasse 				 * Grab the remainder of the title which
1915f169c0eaSGlenn Lagasse 				 * could be a multi worded description
1916f169c0eaSGlenn Lagasse 				 */
1917f169c0eaSGlenn Lagasse 				desc = strtok(NULL, "\n");
1918f169c0eaSGlenn Lagasse 
1919f169c0eaSGlenn Lagasse 				if (strcmp(name, be_orig_name) == 0) {
1920f169c0eaSGlenn Lagasse 					/*
1921f169c0eaSGlenn Lagasse 					 * The first token of the title is
1922f169c0eaSGlenn Lagasse 					 * the old BE name, replace it with
1923f169c0eaSGlenn Lagasse 					 * the new one, and write it out
1924f169c0eaSGlenn Lagasse 					 * along with the remainder of
1925f169c0eaSGlenn Lagasse 					 * description if there is one.
1926f169c0eaSGlenn Lagasse 					 */
1927f169c0eaSGlenn Lagasse 					if (desc) {
1928f169c0eaSGlenn Lagasse 						(void) snprintf(new_line,
1929f169c0eaSGlenn Lagasse 						    sizeof (new_line),
1930f169c0eaSGlenn Lagasse 						    "title %s %s\n",
1931f169c0eaSGlenn Lagasse 						    be_new_name, desc);
1932f169c0eaSGlenn Lagasse 					} else {
1933f169c0eaSGlenn Lagasse 						(void) snprintf(new_line,
1934f169c0eaSGlenn Lagasse 						    sizeof (new_line),
1935f169c0eaSGlenn Lagasse 						    "title %s\n", be_new_name);
1936f169c0eaSGlenn Lagasse 					}
1937f169c0eaSGlenn Lagasse 
1938f169c0eaSGlenn Lagasse 					(void) fputs(new_line, new_fp);
1939f169c0eaSGlenn Lagasse 				} else {
1940f169c0eaSGlenn Lagasse 					(void) fputs(line, new_fp);
1941f169c0eaSGlenn Lagasse 				}
1942f169c0eaSGlenn Lagasse 			}
1943f169c0eaSGlenn Lagasse 		} else if (strcmp(c, "bootfs") == 0) {
1944f169c0eaSGlenn Lagasse 			/*
1945f169c0eaSGlenn Lagasse 			 * Found a 'bootfs' line, parse out the BE root
1946f169c0eaSGlenn Lagasse 			 * dataset value.
1947f169c0eaSGlenn Lagasse 			 */
1948f169c0eaSGlenn Lagasse 			char *root_ds = strtok(NULL, BE_WHITE_SPACE);
1949f169c0eaSGlenn Lagasse 
1950f169c0eaSGlenn Lagasse 			if (root_ds == NULL) {
1951f169c0eaSGlenn Lagasse 				/*
1952f169c0eaSGlenn Lagasse 				 * Nothing after 'bootfs', just push
1953f169c0eaSGlenn Lagasse 				 * this line through
1954f169c0eaSGlenn Lagasse 				 */
1955f169c0eaSGlenn Lagasse 				(void) fputs(line, new_fp);
1956f169c0eaSGlenn Lagasse 			} else {
1957f169c0eaSGlenn Lagasse 				/*
1958f169c0eaSGlenn Lagasse 				 * If this bootfs is the one we're renaming,
1959f169c0eaSGlenn Lagasse 				 * write out the new root dataset value
1960f169c0eaSGlenn Lagasse 				 */
1961f169c0eaSGlenn Lagasse 				if (strcmp(root_ds, be_root_ds) == 0) {
1962f169c0eaSGlenn Lagasse 					(void) snprintf(new_line,
1963f169c0eaSGlenn Lagasse 					    sizeof (new_line), "bootfs %s\n",
1964f169c0eaSGlenn Lagasse 					    be_new_root_ds);
1965f169c0eaSGlenn Lagasse 
1966f169c0eaSGlenn Lagasse 					(void) fputs(new_line, new_fp);
1967f169c0eaSGlenn Lagasse 				} else {
1968f169c0eaSGlenn Lagasse 					(void) fputs(line, new_fp);
1969f169c0eaSGlenn Lagasse 				}
1970f169c0eaSGlenn Lagasse 			}
1971f169c0eaSGlenn Lagasse 		} else {
1972f169c0eaSGlenn Lagasse 			/*
1973f169c0eaSGlenn Lagasse 			 * Found some other line we don't care
1974f169c0eaSGlenn Lagasse 			 * about, write it out.
1975f169c0eaSGlenn Lagasse 			 */
1976f169c0eaSGlenn Lagasse 			(void) fputs(line, new_fp);
1977f169c0eaSGlenn Lagasse 		}
1978f169c0eaSGlenn Lagasse 	}
1979f169c0eaSGlenn Lagasse 
1980f169c0eaSGlenn Lagasse 	(void) fclose(menu_fp);
1981f169c0eaSGlenn Lagasse 	(void) fclose(new_fp);
1982f169c0eaSGlenn Lagasse 	(void) close(tmp_fd);
1983f169c0eaSGlenn Lagasse 
1984f169c0eaSGlenn Lagasse 	if (rename(temp_menu, menu_file) != 0) {
1985f169c0eaSGlenn Lagasse 		err = errno;
1986f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: "
1987f169c0eaSGlenn Lagasse 		    "failed to rename file %s to %s: %s\n"),
1988f169c0eaSGlenn Lagasse 		    temp_menu, menu_file, strerror(err));
1989f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1990f169c0eaSGlenn Lagasse 	}
1991f169c0eaSGlenn Lagasse 	free(temp_menu);
1992f169c0eaSGlenn Lagasse 
1993f169c0eaSGlenn Lagasse 	/* Set the perms and ownership of the updated file */
1994f169c0eaSGlenn Lagasse 	if (chmod(menu_file, sb.st_mode) != 0) {
1995f169c0eaSGlenn Lagasse 		err = errno;
1996f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: "
1997f169c0eaSGlenn Lagasse 		    "failed to chmod %s: %s\n"), menu_file, strerror(err));
1998f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1999f169c0eaSGlenn Lagasse 		goto cleanup;
2000f169c0eaSGlenn Lagasse 	}
2001f169c0eaSGlenn Lagasse 	if (chown(menu_file, sb.st_uid, sb.st_gid) != 0) {
2002f169c0eaSGlenn Lagasse 		err = errno;
2003f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_update_menu: "
2004f169c0eaSGlenn Lagasse 		    "failed to chown %s: %s\n"), menu_file, strerror(err));
2005f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
2006f169c0eaSGlenn Lagasse 	}
2007f169c0eaSGlenn Lagasse 
2008f169c0eaSGlenn Lagasse cleanup:
2009f169c0eaSGlenn Lagasse 	if (pool_mounted) {
2010f169c0eaSGlenn Lagasse 		int err = BE_SUCCESS;
2011f169c0eaSGlenn Lagasse 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
2012f169c0eaSGlenn Lagasse 		if (ret == BE_SUCCESS)
2013f169c0eaSGlenn Lagasse 			ret = err;
2014f169c0eaSGlenn Lagasse 		free(orig_mntpnt);
2015f169c0eaSGlenn Lagasse 		free(ptmp_mntpnt);
2016f169c0eaSGlenn Lagasse 	}
2017f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2018f169c0eaSGlenn Lagasse 	return (ret);
2019f169c0eaSGlenn Lagasse }
2020f169c0eaSGlenn Lagasse 
2021f169c0eaSGlenn Lagasse /*
2022f169c0eaSGlenn Lagasse  * Function:	be_has_menu_entry
2023f169c0eaSGlenn Lagasse  * Description:	Checks to see if the BEs root dataset has an entry in the grub
2024f169c0eaSGlenn Lagasse  *		menu.
2025f169c0eaSGlenn Lagasse  * Parameters:
2026f169c0eaSGlenn Lagasse  *		be_dataset - The root dataset of the BE
2027f169c0eaSGlenn Lagasse  *		be_root_pool - The pool which contains the boot menu
2028f169c0eaSGlenn Lagasse  *		entry - A pointer the the entry number of the BE if found.
2029f169c0eaSGlenn Lagasse  * Returns:
2030f169c0eaSGlenn Lagasse  *		B_TRUE - Success
2031f169c0eaSGlenn Lagasse  *		B_FALSE - Failure
2032f169c0eaSGlenn Lagasse  * Scope:
2033f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2034f169c0eaSGlenn Lagasse  */
2035f169c0eaSGlenn Lagasse boolean_t
2036f169c0eaSGlenn Lagasse be_has_menu_entry(char *be_dataset, char *be_root_pool, int *entry)
2037f169c0eaSGlenn Lagasse {
2038f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp = NULL;
2039f169c0eaSGlenn Lagasse 	char		menu_file[MAXPATHLEN];
2040f169c0eaSGlenn Lagasse 	FILE		*menu_fp;
2041f169c0eaSGlenn Lagasse 	char		line[BUFSIZ];
2042f169c0eaSGlenn Lagasse 	char		*last;
2043f169c0eaSGlenn Lagasse 	char		*rpool_mntpnt = NULL;
2044f169c0eaSGlenn Lagasse 	char		*ptmp_mntpnt = NULL;
2045f169c0eaSGlenn Lagasse 	char		*orig_mntpnt = NULL;
2046f169c0eaSGlenn Lagasse 	int		ent_num = 0;
2047f169c0eaSGlenn Lagasse 	boolean_t	ret = 0;
2048f169c0eaSGlenn Lagasse 	boolean_t	pool_mounted = B_FALSE;
2049f169c0eaSGlenn Lagasse 
2050f169c0eaSGlenn Lagasse 
2051f169c0eaSGlenn Lagasse 	/*
2052f169c0eaSGlenn Lagasse 	 * Check to see if this system supports grub
2053f169c0eaSGlenn Lagasse 	 */
2054f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
2055f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_has_menu_entry: failed to open "
2056f169c0eaSGlenn Lagasse 		    "pool dataset for %s: %s\n"), be_root_pool,
2057f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2058f169c0eaSGlenn Lagasse 		return (B_FALSE);
2059f169c0eaSGlenn Lagasse 	}
2060f169c0eaSGlenn Lagasse 
2061f169c0eaSGlenn Lagasse 	/*
2062f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
2063f169c0eaSGlenn Lagasse 	 * attempt to mount it.
2064f169c0eaSGlenn Lagasse 	 */
2065f169c0eaSGlenn Lagasse 	if (be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
2066f169c0eaSGlenn Lagasse 	    &pool_mounted) != 0) {
2067f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_has_menu_entry: pool dataset "
2068f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), be_root_pool);
2069f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2070f169c0eaSGlenn Lagasse 		return (B_FALSE);
2071f169c0eaSGlenn Lagasse 	}
2072f169c0eaSGlenn Lagasse 
2073f169c0eaSGlenn Lagasse 	/*
2074f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
2075f169c0eaSGlenn Lagasse 	 */
2076f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &rpool_mntpnt)) {
2077f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_has_menu_entry: pool "
2078f169c0eaSGlenn Lagasse 		    "dataset (%s) is not mounted. Can't set "
2079f169c0eaSGlenn Lagasse 		    "the default BE in the grub menu.\n"), be_root_pool);
2080f169c0eaSGlenn Lagasse 		ret = B_FALSE;
2081f169c0eaSGlenn Lagasse 		goto cleanup;
2082f169c0eaSGlenn Lagasse 	}
2083f169c0eaSGlenn Lagasse 
2084f169c0eaSGlenn Lagasse 	if (be_has_grub()) {
2085f169c0eaSGlenn Lagasse 		(void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
2086f169c0eaSGlenn Lagasse 		    rpool_mntpnt, BE_GRUB_MENU);
2087f169c0eaSGlenn Lagasse 	} else {
2088f169c0eaSGlenn Lagasse 		(void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
2089f169c0eaSGlenn Lagasse 		    rpool_mntpnt, BE_SPARC_MENU);
2090f169c0eaSGlenn Lagasse 	}
2091f169c0eaSGlenn Lagasse 
2092de1ab35cSAlexander Eremin 	if (be_open_menu(be_root_pool, menu_file, &menu_fp, "r",
2093f169c0eaSGlenn Lagasse 	    B_FALSE) != 0) {
2094f169c0eaSGlenn Lagasse 		ret = B_FALSE;
2095f169c0eaSGlenn Lagasse 		goto cleanup;
2096f169c0eaSGlenn Lagasse 	} else if (menu_fp == NULL) {
2097f169c0eaSGlenn Lagasse 		ret = B_FALSE;
2098f169c0eaSGlenn Lagasse 		goto cleanup;
2099f169c0eaSGlenn Lagasse 	}
2100f169c0eaSGlenn Lagasse 
2101f169c0eaSGlenn Lagasse 	free(rpool_mntpnt);
2102f169c0eaSGlenn Lagasse 	rpool_mntpnt = NULL;
2103f169c0eaSGlenn Lagasse 
2104f169c0eaSGlenn Lagasse 	while (fgets(line, BUFSIZ, menu_fp)) {
2105f169c0eaSGlenn Lagasse 		char *tok = strtok_r(line, BE_WHITE_SPACE, &last);
2106f169c0eaSGlenn Lagasse 
2107f169c0eaSGlenn Lagasse 		if (tok != NULL && tok[0] != '#') {
2108f169c0eaSGlenn Lagasse 			if (strcmp(tok, "bootfs") == 0) {
2109f169c0eaSGlenn Lagasse 				tok = strtok_r(last, BE_WHITE_SPACE, &last);
2110f169c0eaSGlenn Lagasse 				if (tok != NULL && strcmp(tok,
2111f169c0eaSGlenn Lagasse 				    be_dataset) == 0) {
2112f169c0eaSGlenn Lagasse 					(void) fclose(menu_fp);
2113f169c0eaSGlenn Lagasse 					/*
2114f169c0eaSGlenn Lagasse 					 * The entry number needs to be
2115f169c0eaSGlenn Lagasse 					 * decremented here because the title
2116f169c0eaSGlenn Lagasse 					 * will always be the first line for
2117f169c0eaSGlenn Lagasse 					 * an entry. Because of this we'll
2118f169c0eaSGlenn Lagasse 					 * always be off by one entry when we
2119f169c0eaSGlenn Lagasse 					 * check for bootfs.
2120f169c0eaSGlenn Lagasse 					 */
2121f169c0eaSGlenn Lagasse 					*entry = ent_num - 1;
2122f169c0eaSGlenn Lagasse 					ret = B_TRUE;
2123f169c0eaSGlenn Lagasse 					goto cleanup;
2124f169c0eaSGlenn Lagasse 				}
2125f169c0eaSGlenn Lagasse 			} else if (strcmp(tok, "title") == 0)
2126f169c0eaSGlenn Lagasse 				ent_num++;
2127f169c0eaSGlenn Lagasse 		}
2128f169c0eaSGlenn Lagasse 	}
2129f169c0eaSGlenn Lagasse 
2130f169c0eaSGlenn Lagasse cleanup:
2131f169c0eaSGlenn Lagasse 	if (pool_mounted) {
2132f169c0eaSGlenn Lagasse 		(void) be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
2133f169c0eaSGlenn Lagasse 		free(orig_mntpnt);
2134f169c0eaSGlenn Lagasse 		free(ptmp_mntpnt);
2135f169c0eaSGlenn Lagasse 	}
2136f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2137f169c0eaSGlenn Lagasse 	(void) fclose(menu_fp);
2138f169c0eaSGlenn Lagasse 	return (ret);
2139f169c0eaSGlenn Lagasse }
2140f169c0eaSGlenn Lagasse 
2141f169c0eaSGlenn Lagasse /*
2142f169c0eaSGlenn Lagasse  * Function:	be_update_vfstab
2143f169c0eaSGlenn Lagasse  * Description:	This function digs into a BE's vfstab and updates all
2144f169c0eaSGlenn Lagasse  *		entries with file systems listed in be_fs_list_data_t.
2145f169c0eaSGlenn Lagasse  *		The entry's root container dataset and be_name will be
2146f169c0eaSGlenn Lagasse  *		updated with the parameters passed in.
2147f169c0eaSGlenn Lagasse  * Parameters:
2148f169c0eaSGlenn Lagasse  *		be_name - name of BE to update
2149f169c0eaSGlenn Lagasse  *		old_rc_loc - dataset under which the root container dataset
2150f169c0eaSGlenn Lagasse  *			of the old BE resides in.
2151f169c0eaSGlenn Lagasse  *		new_rc_loc - dataset under which the root container dataset
2152f169c0eaSGlenn Lagasse  *			of the new BE resides in.
2153f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer providing the list of
2154f169c0eaSGlenn Lagasse  *			file systems to look for in vfstab.
2155f169c0eaSGlenn Lagasse  *		mountpoint - directory of where BE is currently mounted.
2156f169c0eaSGlenn Lagasse  *			If NULL, then BE is not currently mounted.
2157f169c0eaSGlenn Lagasse  * Returns:
2158f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2159f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2160f169c0eaSGlenn Lagasse  * Scope:
2161f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2162f169c0eaSGlenn Lagasse  */
2163f169c0eaSGlenn Lagasse int
2164f169c0eaSGlenn Lagasse be_update_vfstab(char *be_name, char *old_rc_loc, char *new_rc_loc,
2165f169c0eaSGlenn Lagasse     be_fs_list_data_t *fld, char *mountpoint)
2166f169c0eaSGlenn Lagasse {
2167f169c0eaSGlenn Lagasse 	char		*tmp_mountpoint = NULL;
2168f169c0eaSGlenn Lagasse 	char		alt_vfstab[MAXPATHLEN];
2169f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS, err = BE_SUCCESS;
2170f169c0eaSGlenn Lagasse 
2171f169c0eaSGlenn Lagasse 	if (fld == NULL || fld->fs_list == NULL || fld->fs_num == 0)
2172f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2173f169c0eaSGlenn Lagasse 
2174f169c0eaSGlenn Lagasse 	/* If BE not already mounted, mount the BE */
2175f169c0eaSGlenn Lagasse 	if (mountpoint == NULL) {
2176f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(be_name, &tmp_mountpoint,
2177f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
2178f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_update_vfstab: "
2179f169c0eaSGlenn Lagasse 			    "failed to mount BE (%s)\n"), be_name);
2180f169c0eaSGlenn Lagasse 			return (ret);
2181f169c0eaSGlenn Lagasse 		}
2182f169c0eaSGlenn Lagasse 	} else {
2183f169c0eaSGlenn Lagasse 		tmp_mountpoint = mountpoint;
2184f169c0eaSGlenn Lagasse 	}
2185f169c0eaSGlenn Lagasse 
2186f169c0eaSGlenn Lagasse 	/* Get string for vfstab in the mounted BE. */
2187f169c0eaSGlenn Lagasse 	(void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
2188f169c0eaSGlenn Lagasse 	    tmp_mountpoint);
2189f169c0eaSGlenn Lagasse 
2190f169c0eaSGlenn Lagasse 	/* Update the vfstab */
2191f169c0eaSGlenn Lagasse 	ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
2192f169c0eaSGlenn Lagasse 	    fld);
2193f169c0eaSGlenn Lagasse 
2194f169c0eaSGlenn Lagasse 	/* Unmount BE if we mounted it */
2195f169c0eaSGlenn Lagasse 	if (mountpoint == NULL) {
2196f169c0eaSGlenn Lagasse 		if ((err = _be_unmount(be_name, 0)) == BE_SUCCESS) {
2197f169c0eaSGlenn Lagasse 			/* Remove temporary mountpoint */
2198f169c0eaSGlenn Lagasse 			(void) rmdir(tmp_mountpoint);
2199f169c0eaSGlenn Lagasse 		} else {
2200f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_update_vfstab: "
2201f169c0eaSGlenn Lagasse 			    "failed to unmount BE %s mounted at %s\n"),
2202f169c0eaSGlenn Lagasse 			    be_name, tmp_mountpoint);
2203f169c0eaSGlenn Lagasse 			if (ret == BE_SUCCESS)
2204f169c0eaSGlenn Lagasse 				ret = err;
2205f169c0eaSGlenn Lagasse 		}
2206f169c0eaSGlenn Lagasse 
2207f169c0eaSGlenn Lagasse 		free(tmp_mountpoint);
2208f169c0eaSGlenn Lagasse 	}
2209f169c0eaSGlenn Lagasse 
2210f169c0eaSGlenn Lagasse 	return (ret);
2211f169c0eaSGlenn Lagasse }
2212f169c0eaSGlenn Lagasse 
2213f169c0eaSGlenn Lagasse /*
2214f169c0eaSGlenn Lagasse  * Function:	be_update_zone_vfstab
2215f169c0eaSGlenn Lagasse  * Description:	This function digs into a zone BE's vfstab and updates all
2216f169c0eaSGlenn Lagasse  *		entries with file systems listed in be_fs_list_data_t.
2217f169c0eaSGlenn Lagasse  *		The entry's root container dataset and be_name will be
2218f169c0eaSGlenn Lagasse  *		updated with the parameters passed in.
2219f169c0eaSGlenn Lagasse  * Parameters:
2220f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to zone root dataset.
2221f169c0eaSGlenn Lagasse  *		be_name - name of zone BE to update
2222f169c0eaSGlenn Lagasse  *		old_rc_loc - dataset under which the root container dataset
2223f169c0eaSGlenn Lagasse  *			of the old zone BE resides in.
2224f169c0eaSGlenn Lagasse  *		new_rc_loc - dataset under which the root container dataset
2225f169c0eaSGlenn Lagasse  *			of the new zone BE resides in.
2226f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer providing the list of
2227f169c0eaSGlenn Lagasse  *			file systems to look for in vfstab.
2228f169c0eaSGlenn Lagasse  * Returns:
2229f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2230f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
2231f169c0eaSGlenn Lagasse  * Scope:
2232f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2233f169c0eaSGlenn Lagasse  */
2234f169c0eaSGlenn Lagasse int
2235f169c0eaSGlenn Lagasse be_update_zone_vfstab(zfs_handle_t *zhp, char *be_name, char *old_rc_loc,
2236f169c0eaSGlenn Lagasse     char *new_rc_loc, be_fs_list_data_t *fld)
2237f169c0eaSGlenn Lagasse {
2238f169c0eaSGlenn Lagasse 	be_mount_data_t		md = { 0 };
2239f169c0eaSGlenn Lagasse 	be_unmount_data_t	ud = { 0 };
2240f169c0eaSGlenn Lagasse 	char			alt_vfstab[MAXPATHLEN];
2241f169c0eaSGlenn Lagasse 	boolean_t		mounted_here = B_FALSE;
2242f169c0eaSGlenn Lagasse 	int			ret = BE_SUCCESS;
2243f169c0eaSGlenn Lagasse 
2244f169c0eaSGlenn Lagasse 	/*
2245f169c0eaSGlenn Lagasse 	 * If zone root not already mounted, mount it at a
2246f169c0eaSGlenn Lagasse 	 * temporary location.
2247f169c0eaSGlenn Lagasse 	 */
2248f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &md.altroot)) {
2249f169c0eaSGlenn Lagasse 		/* Generate temporary mountpoint to mount zone root */
2250f169c0eaSGlenn Lagasse 		if ((ret = be_make_tmp_mountpoint(&md.altroot)) != BE_SUCCESS) {
2251f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_update_zone_vfstab: "
2252f169c0eaSGlenn Lagasse 			    "failed to make temporary mountpoint to "
2253f169c0eaSGlenn Lagasse 			    "mount zone root\n"));
2254f169c0eaSGlenn Lagasse 			return (ret);
2255f169c0eaSGlenn Lagasse 		}
2256f169c0eaSGlenn Lagasse 
2257f169c0eaSGlenn Lagasse 		if (be_mount_zone_root(zhp, &md) != BE_SUCCESS) {
2258f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_update_zone_vfstab: "
2259f169c0eaSGlenn Lagasse 			    "failed to mount zone root %s\n"),
2260f169c0eaSGlenn Lagasse 			    zfs_get_name(zhp));
2261f169c0eaSGlenn Lagasse 			free(md.altroot);
2262f169c0eaSGlenn Lagasse 			return (BE_ERR_MOUNT_ZONEROOT);
2263f169c0eaSGlenn Lagasse 		}
2264f169c0eaSGlenn Lagasse 		mounted_here = B_TRUE;
2265f169c0eaSGlenn Lagasse 	}
2266f169c0eaSGlenn Lagasse 
2267f169c0eaSGlenn Lagasse 	/* Get string from vfstab in the mounted zone BE */
2268f169c0eaSGlenn Lagasse 	(void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
2269f169c0eaSGlenn Lagasse 	    md.altroot);
2270f169c0eaSGlenn Lagasse 
2271f169c0eaSGlenn Lagasse 	/* Update the vfstab */
2272f169c0eaSGlenn Lagasse 	ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
2273f169c0eaSGlenn Lagasse 	    fld);
2274f169c0eaSGlenn Lagasse 
2275f169c0eaSGlenn Lagasse 	/* Unmount zone root if we mounted it */
2276f169c0eaSGlenn Lagasse 	if (mounted_here) {
2277f169c0eaSGlenn Lagasse 		ud.force = B_TRUE;
2278f169c0eaSGlenn Lagasse 
2279f169c0eaSGlenn Lagasse 		if (be_unmount_zone_root(zhp, &ud) == BE_SUCCESS) {
2280f169c0eaSGlenn Lagasse 			/* Remove the temporary mountpoint */
2281f169c0eaSGlenn Lagasse 			(void) rmdir(md.altroot);
2282f169c0eaSGlenn Lagasse 		} else {
2283f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_update_zone_vfstab: "
2284f169c0eaSGlenn Lagasse 			    "failed to unmount zone root %s from %s\n"),
2285f169c0eaSGlenn Lagasse 			    zfs_get_name(zhp), md.altroot);
2286f169c0eaSGlenn Lagasse 			if (ret == 0)
2287f169c0eaSGlenn Lagasse 				ret = BE_ERR_UMOUNT_ZONEROOT;
2288f169c0eaSGlenn Lagasse 		}
2289f169c0eaSGlenn Lagasse 	}
2290f169c0eaSGlenn Lagasse 
2291f169c0eaSGlenn Lagasse 	free(md.altroot);
2292f169c0eaSGlenn Lagasse 	return (ret);
2293f169c0eaSGlenn Lagasse }
2294f169c0eaSGlenn Lagasse 
2295f169c0eaSGlenn Lagasse /*
2296f169c0eaSGlenn Lagasse  * Function:	be_auto_snap_name
2297f169c0eaSGlenn Lagasse  * Description:	Generate an auto snapshot name constructed based on the
2298f169c0eaSGlenn Lagasse  *		current date and time.  The auto snapshot name is of the form:
2299f169c0eaSGlenn Lagasse  *
2300f169c0eaSGlenn Lagasse  *			<date>-<time>
2301f169c0eaSGlenn Lagasse  *
2302f169c0eaSGlenn Lagasse  *		where <date> is in ISO standard format, so the resultant name
2303f169c0eaSGlenn Lagasse  *		is of the form:
2304f169c0eaSGlenn Lagasse  *
2305f169c0eaSGlenn Lagasse  *			%Y-%m-%d-%H:%M:%S
2306f169c0eaSGlenn Lagasse  *
2307f169c0eaSGlenn Lagasse  * Parameters:
2308f169c0eaSGlenn Lagasse  *		None
2309f169c0eaSGlenn Lagasse  * Returns:
2310f169c0eaSGlenn Lagasse  *		Success - pointer to auto generated snapshot name.  The name
2311f169c0eaSGlenn Lagasse  *			is allocated in heap storage so the caller is
2312f169c0eaSGlenn Lagasse  *			responsible for free'ing the name.
2313f169c0eaSGlenn Lagasse  *		Failure - NULL
2314f169c0eaSGlenn Lagasse  * Scope:
2315f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2316f169c0eaSGlenn Lagasse  */
2317f169c0eaSGlenn Lagasse char *
2318f169c0eaSGlenn Lagasse be_auto_snap_name(void)
2319f169c0eaSGlenn Lagasse {
2320f169c0eaSGlenn Lagasse 	time_t		utc_tm = NULL;
2321f169c0eaSGlenn Lagasse 	struct tm	*gmt_tm = NULL;
2322f169c0eaSGlenn Lagasse 	char		gmt_time_str[64];
2323f169c0eaSGlenn Lagasse 	char		*auto_snap_name = NULL;
2324f169c0eaSGlenn Lagasse 
2325f169c0eaSGlenn Lagasse 	if (time(&utc_tm) == -1) {
2326f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_auto_snap_name: time() failed\n"));
2327f169c0eaSGlenn Lagasse 		return (NULL);
2328f169c0eaSGlenn Lagasse 	}
2329f169c0eaSGlenn Lagasse 
2330f169c0eaSGlenn Lagasse 	if ((gmt_tm = gmtime(&utc_tm)) == NULL) {
2331f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_auto_snap_name: gmtime() failed\n"));
2332f169c0eaSGlenn Lagasse 		return (NULL);
2333f169c0eaSGlenn Lagasse 	}
2334f169c0eaSGlenn Lagasse 
2335f169c0eaSGlenn Lagasse 	(void) strftime(gmt_time_str, sizeof (gmt_time_str), "%F-%T", gmt_tm);
2336f169c0eaSGlenn Lagasse 
2337f169c0eaSGlenn Lagasse 	if ((auto_snap_name = strdup(gmt_time_str)) == NULL) {
2338f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_auto_snap_name: "
2339f169c0eaSGlenn Lagasse 		    "memory allocation failed\n"));
2340f169c0eaSGlenn Lagasse 		return (NULL);
2341f169c0eaSGlenn Lagasse 	}
2342f169c0eaSGlenn Lagasse 
2343f169c0eaSGlenn Lagasse 	return (auto_snap_name);
2344f169c0eaSGlenn Lagasse }
2345f169c0eaSGlenn Lagasse 
2346f169c0eaSGlenn Lagasse /*
2347f169c0eaSGlenn Lagasse  * Function:	be_auto_be_name
2348f169c0eaSGlenn Lagasse  * Description:	Generate an auto BE name constructed based on the BE name
2349f169c0eaSGlenn Lagasse  *		of the original BE being cloned.
2350f169c0eaSGlenn Lagasse  * Parameters:
2351f169c0eaSGlenn Lagasse  *		obe_name - name of the original BE being cloned.
2352f169c0eaSGlenn Lagasse  * Returns:
2353f169c0eaSGlenn Lagasse  *		Success - pointer to auto generated BE name.  The name
2354f169c0eaSGlenn Lagasse  *			is allocated in heap storage so the caller is
2355f169c0eaSGlenn Lagasse  *			responsible for free'ing the name.
2356f169c0eaSGlenn Lagasse  *		Failure - NULL
2357f169c0eaSGlenn Lagasse  * Scope:
2358f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2359f169c0eaSGlenn Lagasse  */
2360f169c0eaSGlenn Lagasse char *
2361f169c0eaSGlenn Lagasse be_auto_be_name(char *obe_name)
2362f169c0eaSGlenn Lagasse {
2363f169c0eaSGlenn Lagasse 	return (be_get_auto_name(obe_name, NULL, B_FALSE));
2364f169c0eaSGlenn Lagasse }
2365f169c0eaSGlenn Lagasse 
2366f169c0eaSGlenn Lagasse /*
2367f169c0eaSGlenn Lagasse  * Function:	be_auto_zone_be_name
2368f169c0eaSGlenn Lagasse  * Description:	Generate an auto BE name for a zone constructed based on
2369f169c0eaSGlenn Lagasse  *              the BE name of the original zone BE being cloned.
2370f169c0eaSGlenn Lagasse  * Parameters:
2371f169c0eaSGlenn Lagasse  *              container_ds - container dataset for the zone.
2372f169c0eaSGlenn Lagasse  *		zbe_name - name of the original zone BE being cloned.
2373f169c0eaSGlenn Lagasse  * Returns:
2374f169c0eaSGlenn Lagasse  *		Success - pointer to auto generated BE name.  The name
2375f169c0eaSGlenn Lagasse  *			is allocated in heap storage so the caller is
2376f169c0eaSGlenn Lagasse  *			responsible for free'ing the name.
2377f169c0eaSGlenn Lagasse  *		Failure - NULL
2378f169c0eaSGlenn Lagasse  * Scope:
2379f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2380f169c0eaSGlenn Lagasse  */
2381f169c0eaSGlenn Lagasse char *
2382f169c0eaSGlenn Lagasse be_auto_zone_be_name(char *container_ds, char *zbe_name)
2383f169c0eaSGlenn Lagasse {
2384f169c0eaSGlenn Lagasse 	return (be_get_auto_name(zbe_name, container_ds, B_TRUE));
2385f169c0eaSGlenn Lagasse }
2386f169c0eaSGlenn Lagasse 
2387f169c0eaSGlenn Lagasse /*
2388f169c0eaSGlenn Lagasse  * Function:	be_valid_be_name
2389f169c0eaSGlenn Lagasse  * Description:	Validates a BE name.
2390f169c0eaSGlenn Lagasse  * Parameters:
2391f169c0eaSGlenn Lagasse  *		be_name - name of BE to validate
2392f169c0eaSGlenn Lagasse  * Returns:
2393f169c0eaSGlenn Lagasse  *		B_TRUE - be_name is valid
2394f169c0eaSGlenn Lagasse  *		B_FALSE - be_name is invalid
2395f169c0eaSGlenn Lagasse  * Scope:
2396f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2397f169c0eaSGlenn Lagasse  */
2398f169c0eaSGlenn Lagasse 
2399f169c0eaSGlenn Lagasse boolean_t
2400f169c0eaSGlenn Lagasse be_valid_be_name(const char *be_name)
2401f169c0eaSGlenn Lagasse {
2402f169c0eaSGlenn Lagasse 	const char	*c = NULL;
2403de1ab35cSAlexander Eremin 	struct be_defaults be_defaults;
2404f169c0eaSGlenn Lagasse 
2405f169c0eaSGlenn Lagasse 	if (be_name == NULL)
2406f169c0eaSGlenn Lagasse 		return (B_FALSE);
2407f169c0eaSGlenn Lagasse 
2408de1ab35cSAlexander Eremin 	be_get_defaults(&be_defaults);
2409de1ab35cSAlexander Eremin 
2410f169c0eaSGlenn Lagasse 	/*
2411f169c0eaSGlenn Lagasse 	 * A BE name must not be a multi-level dataset name.  We also check
2412f169c0eaSGlenn Lagasse 	 * that it does not contain the ' ' and '%' characters.  The ' ' is
2413f169c0eaSGlenn Lagasse 	 * a valid character for datasets, however we don't allow that in a
2414f169c0eaSGlenn Lagasse 	 * BE name.  The '%' is invalid, but zfs_name_valid() allows it for
2415f169c0eaSGlenn Lagasse 	 * internal reasons, so we explicitly check for it here.
2416f169c0eaSGlenn Lagasse 	 */
2417f169c0eaSGlenn Lagasse 	c = be_name;
2418f169c0eaSGlenn Lagasse 	while (*c != '\0' && *c != '/' && *c != ' ' && *c != '%')
2419f169c0eaSGlenn Lagasse 		c++;
2420f169c0eaSGlenn Lagasse 
2421f169c0eaSGlenn Lagasse 	if (*c != '\0')
2422f169c0eaSGlenn Lagasse 		return (B_FALSE);
2423f169c0eaSGlenn Lagasse 
2424f169c0eaSGlenn Lagasse 	/*
2425f169c0eaSGlenn Lagasse 	 * The BE name must comply with a zfs dataset filesystem. We also
2426f169c0eaSGlenn Lagasse 	 * verify its length to be < BE_NAME_MAX_LEN.
2427f169c0eaSGlenn Lagasse 	 */
2428f169c0eaSGlenn Lagasse 	if (!zfs_name_valid(be_name, ZFS_TYPE_FILESYSTEM) ||
2429f169c0eaSGlenn Lagasse 	    strlen(be_name) > BE_NAME_MAX_LEN)
2430f169c0eaSGlenn Lagasse 		return (B_FALSE);
2431f169c0eaSGlenn Lagasse 
2432de1ab35cSAlexander Eremin 	if (be_defaults.be_deflt_bename_starts_with[0] != '\0' &&
2433de1ab35cSAlexander Eremin 	    strstr(be_name, be_defaults.be_deflt_bename_starts_with) == NULL) {
2434de1ab35cSAlexander Eremin 		return (B_FALSE);
2435de1ab35cSAlexander Eremin 	}
2436de1ab35cSAlexander Eremin 
2437f169c0eaSGlenn Lagasse 	return (B_TRUE);
2438f169c0eaSGlenn Lagasse }
2439f169c0eaSGlenn Lagasse 
2440f169c0eaSGlenn Lagasse /*
2441f169c0eaSGlenn Lagasse  * Function:	be_valid_auto_snap_name
2442f169c0eaSGlenn Lagasse  * Description:	This function checks that a snapshot name is a valid auto
2443f169c0eaSGlenn Lagasse  *		generated snapshot name.  A valid auto generated snapshot
2444f169c0eaSGlenn Lagasse  *		name is of the form:
2445f169c0eaSGlenn Lagasse  *
2446f169c0eaSGlenn Lagasse  *			%Y-%m-%d-%H:%M:%S
2447f169c0eaSGlenn Lagasse  *
2448f169c0eaSGlenn Lagasse  *		An older form of the auto generated snapshot name also
2449f169c0eaSGlenn Lagasse  *		included the snapshot's BE cleanup policy and a reserved
2450f169c0eaSGlenn Lagasse  *		field.  Those names will also be verified by this function.
2451f169c0eaSGlenn Lagasse  *
2452f169c0eaSGlenn Lagasse  *		Examples of valid auto snapshot names are:
2453f169c0eaSGlenn Lagasse  *
2454f169c0eaSGlenn Lagasse  *			2008-03-31-18:41:30
2455f169c0eaSGlenn Lagasse  *			2008-03-31-22:17:24
2456f169c0eaSGlenn Lagasse  *			<policy>:-:2008:04-05-09:12:55
2457f169c0eaSGlenn Lagasse  *			<policy>:-:2008:04-06-15:34:12
2458f169c0eaSGlenn Lagasse  *
2459f169c0eaSGlenn Lagasse  * Parameters:
2460f169c0eaSGlenn Lagasse  *		name - name of the snapshot to be validated.
2461f169c0eaSGlenn Lagasse  * Returns:
2462f169c0eaSGlenn Lagasse  *		B_TRUE - the name is a valid auto snapshot name.
2463f169c0eaSGlenn Lagasse  *		B_FALSE - the name is not a valid auto snapshot name.
2464f169c0eaSGlenn Lagasse  * Scope:
2465f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2466f169c0eaSGlenn Lagasse  */
2467f169c0eaSGlenn Lagasse boolean_t
2468f169c0eaSGlenn Lagasse be_valid_auto_snap_name(char *name)
2469f169c0eaSGlenn Lagasse {
2470f169c0eaSGlenn Lagasse 	struct tm gmt_tm;
2471f169c0eaSGlenn Lagasse 
2472f169c0eaSGlenn Lagasse 	char *policy = NULL;
2473f169c0eaSGlenn Lagasse 	char *reserved = NULL;
2474f169c0eaSGlenn Lagasse 	char *date = NULL;
2475f169c0eaSGlenn Lagasse 	char *c = NULL;
2476f169c0eaSGlenn Lagasse 
2477f169c0eaSGlenn Lagasse 	/* Validate the snapshot name by converting it into utc time */
2478f169c0eaSGlenn Lagasse 	if (strptime(name, "%Y-%m-%d-%T", &gmt_tm) != NULL &&
2479f169c0eaSGlenn Lagasse 	    (mktime(&gmt_tm) != -1)) {
2480f169c0eaSGlenn Lagasse 		return (B_TRUE);
2481f169c0eaSGlenn Lagasse 	}
2482f169c0eaSGlenn Lagasse 
2483f169c0eaSGlenn Lagasse 	/*
2484f169c0eaSGlenn Lagasse 	 * Validate the snapshot name against the older form of an
2485f169c0eaSGlenn Lagasse 	 * auto generated snapshot name.
2486f169c0eaSGlenn Lagasse 	 */
2487f169c0eaSGlenn Lagasse 	policy = strdup(name);
2488f169c0eaSGlenn Lagasse 
2489f169c0eaSGlenn Lagasse 	/*
2490f169c0eaSGlenn Lagasse 	 * Get the first field from the snapshot name,
2491f169c0eaSGlenn Lagasse 	 * which is the BE policy
2492f169c0eaSGlenn Lagasse 	 */
2493f169c0eaSGlenn Lagasse 	c = strchr(policy, ':');
2494f169c0eaSGlenn Lagasse 	if (c == NULL) {
2495f169c0eaSGlenn Lagasse 		free(policy);
2496f169c0eaSGlenn Lagasse 		return (B_FALSE);
2497f169c0eaSGlenn Lagasse 	}
2498f169c0eaSGlenn Lagasse 	c[0] = '\0';
2499f169c0eaSGlenn Lagasse 
2500f169c0eaSGlenn Lagasse 	/* Validate the policy name */
2501f169c0eaSGlenn Lagasse 	if (!valid_be_policy(policy)) {
2502f169c0eaSGlenn Lagasse 		free(policy);
2503f169c0eaSGlenn Lagasse 		return (B_FALSE);
2504f169c0eaSGlenn Lagasse 	}
2505f169c0eaSGlenn Lagasse 
2506f169c0eaSGlenn Lagasse 	/* Get the next field, which is the reserved field. */
2507f169c0eaSGlenn Lagasse 	if (c[1] == NULL || c[1] == '\0') {
2508f169c0eaSGlenn Lagasse 		free(policy);
2509f169c0eaSGlenn Lagasse 		return (B_FALSE);
2510f169c0eaSGlenn Lagasse 	}
2511f169c0eaSGlenn Lagasse 	reserved = c+1;
2512f169c0eaSGlenn Lagasse 	c = strchr(reserved, ':');
2513f169c0eaSGlenn Lagasse 	if (c == NULL) {
2514f169c0eaSGlenn Lagasse 		free(policy);
2515f169c0eaSGlenn Lagasse 		return (B_FALSE);
2516f169c0eaSGlenn Lagasse 	}
2517f169c0eaSGlenn Lagasse 	c[0] = '\0';
2518f169c0eaSGlenn Lagasse 
2519f169c0eaSGlenn Lagasse 	/* Validate the reserved field */
2520f169c0eaSGlenn Lagasse 	if (strcmp(reserved, "-") != 0) {
2521f169c0eaSGlenn Lagasse 		free(policy);
2522f169c0eaSGlenn Lagasse 		return (B_FALSE);
2523f169c0eaSGlenn Lagasse 	}
2524f169c0eaSGlenn Lagasse 
2525f169c0eaSGlenn Lagasse 	/* The remaining string should be the date field */
2526f169c0eaSGlenn Lagasse 	if (c[1] == NULL || c[1] == '\0') {
2527f169c0eaSGlenn Lagasse 		free(policy);
2528f169c0eaSGlenn Lagasse 		return (B_FALSE);
2529f169c0eaSGlenn Lagasse 	}
2530f169c0eaSGlenn Lagasse 	date = c+1;
2531f169c0eaSGlenn Lagasse 
2532f169c0eaSGlenn Lagasse 	/* Validate the date string by converting it into utc time */
2533f169c0eaSGlenn Lagasse 	if (strptime(date, "%Y-%m-%d-%T", &gmt_tm) == NULL ||
2534f169c0eaSGlenn Lagasse 	    (mktime(&gmt_tm) == -1)) {
2535f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_valid_auto_snap_name: "
2536f169c0eaSGlenn Lagasse 		    "invalid auto snapshot name\n"));
2537f169c0eaSGlenn Lagasse 		free(policy);
2538f169c0eaSGlenn Lagasse 		return (B_FALSE);
2539f169c0eaSGlenn Lagasse 	}
2540f169c0eaSGlenn Lagasse 
2541f169c0eaSGlenn Lagasse 	free(policy);
2542f169c0eaSGlenn Lagasse 	return (B_TRUE);
2543f169c0eaSGlenn Lagasse }
2544f169c0eaSGlenn Lagasse 
2545f169c0eaSGlenn Lagasse /*
2546f169c0eaSGlenn Lagasse  * Function:	be_default_policy
2547f169c0eaSGlenn Lagasse  * Description:	Temporary hardcoded policy support.  This function returns
2548f169c0eaSGlenn Lagasse  *		the default policy type to be used to create a BE or a BE
2549f169c0eaSGlenn Lagasse  *		snapshot.
2550f169c0eaSGlenn Lagasse  * Parameters:
2551f169c0eaSGlenn Lagasse  *		None
2552f169c0eaSGlenn Lagasse  * Returns:
2553f169c0eaSGlenn Lagasse  *		Name of default BE policy.
2554f169c0eaSGlenn Lagasse  * Scope:
2555f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2556f169c0eaSGlenn Lagasse  */
2557f169c0eaSGlenn Lagasse char *
2558f169c0eaSGlenn Lagasse be_default_policy(void)
2559f169c0eaSGlenn Lagasse {
2560f169c0eaSGlenn Lagasse 	return (BE_PLCY_STATIC);
2561f169c0eaSGlenn Lagasse }
2562f169c0eaSGlenn Lagasse 
2563f169c0eaSGlenn Lagasse /*
2564f169c0eaSGlenn Lagasse  * Function:	valid_be_policy
2565f169c0eaSGlenn Lagasse  * Description:	Temporary hardcoded policy support.  This function valids
2566f169c0eaSGlenn Lagasse  *		whether a policy is a valid known policy or not.
2567f169c0eaSGlenn Lagasse  * Paramters:
2568f169c0eaSGlenn Lagasse  *		policy - name of policy to validate.
2569f169c0eaSGlenn Lagasse  * Returns:
2570f169c0eaSGlenn Lagasse  *		B_TRUE - policy is a valid.
2571f169c0eaSGlenn Lagasse  *		B_FALSE - policy is invalid.
2572f169c0eaSGlenn Lagasse  * Scope:
2573f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2574f169c0eaSGlenn Lagasse  */
2575f169c0eaSGlenn Lagasse boolean_t
2576f169c0eaSGlenn Lagasse valid_be_policy(char *policy)
2577f169c0eaSGlenn Lagasse {
2578f169c0eaSGlenn Lagasse 	if (policy == NULL)
2579f169c0eaSGlenn Lagasse 		return (B_FALSE);
2580f169c0eaSGlenn Lagasse 
2581f169c0eaSGlenn Lagasse 	if (strcmp(policy, BE_PLCY_STATIC) == 0 ||
2582f169c0eaSGlenn Lagasse 	    strcmp(policy, BE_PLCY_VOLATILE) == 0) {
2583f169c0eaSGlenn Lagasse 		return (B_TRUE);
2584f169c0eaSGlenn Lagasse 	}
2585f169c0eaSGlenn Lagasse 
2586f169c0eaSGlenn Lagasse 	return (B_FALSE);
2587f169c0eaSGlenn Lagasse }
2588f169c0eaSGlenn Lagasse 
2589f169c0eaSGlenn Lagasse /*
2590f169c0eaSGlenn Lagasse  * Function:	be_print_err
2591f169c0eaSGlenn Lagasse  * Description:	This function prints out error messages if do_print is
2592f169c0eaSGlenn Lagasse  *		set to B_TRUE or if the BE_PRINT_ERR environment variable
2593f169c0eaSGlenn Lagasse  *		is set to true.
2594f169c0eaSGlenn Lagasse  * Paramters:
2595f169c0eaSGlenn Lagasse  *		prnt_str - the string we wish to print and any arguments
2596f169c0eaSGlenn Lagasse  *		for the format of that string.
2597f169c0eaSGlenn Lagasse  * Returns:
2598f169c0eaSGlenn Lagasse  *		void
2599f169c0eaSGlenn Lagasse  * Scope:
2600f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2601f169c0eaSGlenn Lagasse  */
2602f169c0eaSGlenn Lagasse void
2603f169c0eaSGlenn Lagasse be_print_err(char *prnt_str, ...)
2604f169c0eaSGlenn Lagasse {
2605f169c0eaSGlenn Lagasse 	va_list ap;
2606f169c0eaSGlenn Lagasse 	char buf[BUFSIZ];
2607f169c0eaSGlenn Lagasse 	char *env_buf;
2608f169c0eaSGlenn Lagasse 	static boolean_t env_checked = B_FALSE;
2609f169c0eaSGlenn Lagasse 
2610f169c0eaSGlenn Lagasse 	if (!env_checked) {
2611f169c0eaSGlenn Lagasse 		if ((env_buf = getenv("BE_PRINT_ERR")) != NULL) {
2612f169c0eaSGlenn Lagasse 			if (strcasecmp(env_buf, "true") == 0) {
2613f169c0eaSGlenn Lagasse 				do_print = B_TRUE;
2614f169c0eaSGlenn Lagasse 			}
2615f169c0eaSGlenn Lagasse 		}
2616f169c0eaSGlenn Lagasse 		env_checked = B_TRUE;
2617f169c0eaSGlenn Lagasse 	}
2618f169c0eaSGlenn Lagasse 
2619f169c0eaSGlenn Lagasse 	if (do_print) {
2620f169c0eaSGlenn Lagasse 		va_start(ap, prnt_str);
2621f169c0eaSGlenn Lagasse 		/* LINTED variable format specifier */
2622f169c0eaSGlenn Lagasse 		(void) vsnprintf(buf, BUFSIZ, prnt_str, ap);
2623f169c0eaSGlenn Lagasse 		(void) fputs(buf, stderr);
2624f169c0eaSGlenn Lagasse 		va_end(ap);
2625f169c0eaSGlenn Lagasse 	}
2626f169c0eaSGlenn Lagasse }
2627f169c0eaSGlenn Lagasse 
2628f169c0eaSGlenn Lagasse /*
2629f169c0eaSGlenn Lagasse  * Function:	be_find_current_be
2630f169c0eaSGlenn Lagasse  * Description:	Find the currently "active" BE. Fill in the
2631*a897f28bSAndy Fiddaman  *		passed in be_transaction_data_t reference with the
2632f169c0eaSGlenn Lagasse  *		active BE's data.
2633f169c0eaSGlenn Lagasse  * Paramters:
2634f169c0eaSGlenn Lagasse  *		none
2635f169c0eaSGlenn Lagasse  * Returns:
2636f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
2637f169c0eaSGlenn Lagasse  *		be_errnot_t - Failure
2638f169c0eaSGlenn Lagasse  * Scope:
2639f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2640f169c0eaSGlenn Lagasse  * Notes:
2641f169c0eaSGlenn Lagasse  *		The caller is responsible for initializing the libzfs handle
2642f169c0eaSGlenn Lagasse  *		and freeing the memory used by the active be_name.
2643f169c0eaSGlenn Lagasse  */
2644f169c0eaSGlenn Lagasse int
2645f169c0eaSGlenn Lagasse be_find_current_be(be_transaction_data_t *bt)
2646f169c0eaSGlenn Lagasse {
2647f169c0eaSGlenn Lagasse 	int	zret;
2648f169c0eaSGlenn Lagasse 
2649f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_zpool_find_current_be_callback,
2650f169c0eaSGlenn Lagasse 	    bt)) == 0) {
2651f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_find_current_be: failed to "
2652f169c0eaSGlenn Lagasse 		    "find current BE name\n"));
2653f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
2654f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
2655f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_find_current_be: "
2656f169c0eaSGlenn Lagasse 		    "zpool_iter failed: %s\n"),
2657f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
2658f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
2659f169c0eaSGlenn Lagasse 	}
2660f169c0eaSGlenn Lagasse 
2661f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
2662f169c0eaSGlenn Lagasse }
2663f169c0eaSGlenn Lagasse 
2664f169c0eaSGlenn Lagasse /*
2665f169c0eaSGlenn Lagasse  * Function:	be_zpool_find_current_be_callback
2666f169c0eaSGlenn Lagasse  * Description: Callback function used to iterate through all existing pools
2667f169c0eaSGlenn Lagasse  *		to find the BE that is the currently booted BE.
2668f169c0eaSGlenn Lagasse  * Parameters:
2669f169c0eaSGlenn Lagasse  *		zlp - zpool_handle_t pointer to the current pool being
2670f169c0eaSGlenn Lagasse  *			looked at.
2671f169c0eaSGlenn Lagasse  *		data - be_transaction_data_t pointer.
2672f169c0eaSGlenn Lagasse  *			Upon successfully finding the current BE, the
2673f169c0eaSGlenn Lagasse  *			obe_zpool member of this parameter is set to the
2674f169c0eaSGlenn Lagasse  *			pool it is found in.
2675f169c0eaSGlenn Lagasse  * Return:
2676f169c0eaSGlenn Lagasse  *		1 - Found current BE in this pool.
2677f169c0eaSGlenn Lagasse  *		0 - Did not find current BE in this pool.
2678f169c0eaSGlenn Lagasse  * Scope:
2679f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2680f169c0eaSGlenn Lagasse  */
2681f169c0eaSGlenn Lagasse int
2682f169c0eaSGlenn Lagasse be_zpool_find_current_be_callback(zpool_handle_t *zlp, void *data)
2683f169c0eaSGlenn Lagasse {
2684f169c0eaSGlenn Lagasse 	be_transaction_data_t	*bt = data;
2685f169c0eaSGlenn Lagasse 	zfs_handle_t		*zhp = NULL;
2686f169c0eaSGlenn Lagasse 	const char		*zpool =  zpool_get_name(zlp);
2687f169c0eaSGlenn Lagasse 	char			be_container_ds[MAXPATHLEN];
26887e0e2549SAlexander Eremin 	char			*zpath = NULL;
2689f169c0eaSGlenn Lagasse 
2690f169c0eaSGlenn Lagasse 	/*
2691f169c0eaSGlenn Lagasse 	 * Generate string for BE container dataset
2692f169c0eaSGlenn Lagasse 	 */
26937e0e2549SAlexander Eremin 	if (getzoneid() != GLOBAL_ZONEID) {
26947e0e2549SAlexander Eremin 		if ((zpath = be_get_ds_from_dir("/")) != NULL) {
26957e0e2549SAlexander Eremin 			(void) strlcpy(be_container_ds, dirname(zpath),
26967e0e2549SAlexander Eremin 			    sizeof (be_container_ds));
26977e0e2549SAlexander Eremin 		} else {
26987e0e2549SAlexander Eremin 			be_print_err(gettext(
26997e0e2549SAlexander Eremin 			    "be_zpool_find_current_be_callback: "
27007e0e2549SAlexander Eremin 			    "zone root dataset is not mounted\n"));
27017e0e2549SAlexander Eremin 			return (0);
27027e0e2549SAlexander Eremin 		}
27037e0e2549SAlexander Eremin 	} else {
27047e0e2549SAlexander Eremin 		be_make_container_ds(zpool, be_container_ds,
27057e0e2549SAlexander Eremin 		    sizeof (be_container_ds));
27067e0e2549SAlexander Eremin 	}
2707f169c0eaSGlenn Lagasse 
2708f169c0eaSGlenn Lagasse 	/*
2709f169c0eaSGlenn Lagasse 	 * Check if a BE container dataset exists in this pool.
2710f169c0eaSGlenn Lagasse 	 */
2711f169c0eaSGlenn Lagasse 	if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2712f169c0eaSGlenn Lagasse 		zpool_close(zlp);
2713f169c0eaSGlenn Lagasse 		return (0);
2714f169c0eaSGlenn Lagasse 	}
2715f169c0eaSGlenn Lagasse 
2716f169c0eaSGlenn Lagasse 	/*
2717f169c0eaSGlenn Lagasse 	 * Get handle to this zpool's BE container dataset.
2718f169c0eaSGlenn Lagasse 	 */
2719f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) ==
2720f169c0eaSGlenn Lagasse 	    NULL) {
2721f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_zpool_find_current_be_callback: "
2722f169c0eaSGlenn Lagasse 		    "failed to open BE container dataset (%s)\n"),
2723f169c0eaSGlenn Lagasse 		    be_container_ds);
2724f169c0eaSGlenn Lagasse 		zpool_close(zlp);
2725f169c0eaSGlenn Lagasse 		return (0);
2726f169c0eaSGlenn Lagasse 	}
2727f169c0eaSGlenn Lagasse 
2728f169c0eaSGlenn Lagasse 	/*
2729f169c0eaSGlenn Lagasse 	 * Iterate through all potential BEs in this zpool
2730f169c0eaSGlenn Lagasse 	 */
2731f169c0eaSGlenn Lagasse 	if (zfs_iter_filesystems(zhp, be_zfs_find_current_be_callback, bt)) {
2732f169c0eaSGlenn Lagasse 		/*
2733f169c0eaSGlenn Lagasse 		 * Found current BE dataset; set obe_zpool
2734f169c0eaSGlenn Lagasse 		 */
2735f169c0eaSGlenn Lagasse 		if ((bt->obe_zpool = strdup(zpool)) == NULL) {
2736f169c0eaSGlenn Lagasse 			be_print_err(gettext(
2737f169c0eaSGlenn Lagasse 			    "be_zpool_find_current_be_callback: "
2738f169c0eaSGlenn Lagasse 			    "memory allocation failed\n"));
2739f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2740f169c0eaSGlenn Lagasse 			zpool_close(zlp);
2741f169c0eaSGlenn Lagasse 			return (0);
2742f169c0eaSGlenn Lagasse 		}
2743f169c0eaSGlenn Lagasse 
2744f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
2745f169c0eaSGlenn Lagasse 		zpool_close(zlp);
2746f169c0eaSGlenn Lagasse 		return (1);
2747f169c0eaSGlenn Lagasse 	}
2748f169c0eaSGlenn Lagasse 
2749f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2750f169c0eaSGlenn Lagasse 	zpool_close(zlp);
2751f169c0eaSGlenn Lagasse 
2752f169c0eaSGlenn Lagasse 	return (0);
2753f169c0eaSGlenn Lagasse }
2754f169c0eaSGlenn Lagasse 
2755f169c0eaSGlenn Lagasse /*
2756f169c0eaSGlenn Lagasse  * Function:	be_zfs_find_current_be_callback
2757f169c0eaSGlenn Lagasse  * Description:	Callback function used to iterate through all BEs in a
2758f169c0eaSGlenn Lagasse  *		pool to find the BE that is the currently booted BE.
2759f169c0eaSGlenn Lagasse  * Parameters:
2760f169c0eaSGlenn Lagasse  *		zhp - zfs_handle_t pointer to current filesystem being checked.
2761f169c0eaSGlenn Lagasse  *		data - be_transaction-data_t pointer
2762f169c0eaSGlenn Lagasse  *			Upon successfully finding the current BE, the
2763f169c0eaSGlenn Lagasse  *			obe_name and obe_root_ds members of this parameter
2764f169c0eaSGlenn Lagasse  *			are set to the BE name and BE's root dataset
2765f169c0eaSGlenn Lagasse  *			respectively.
2766f169c0eaSGlenn Lagasse  * Return:
2767f169c0eaSGlenn Lagasse  *		1 - Found current BE.
2768f169c0eaSGlenn Lagasse  *		0 - Did not find current BE.
2769f169c0eaSGlenn Lagasse  * Scope:
2770f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2771f169c0eaSGlenn Lagasse  */
2772f169c0eaSGlenn Lagasse int
2773f169c0eaSGlenn Lagasse be_zfs_find_current_be_callback(zfs_handle_t *zhp, void *data)
2774f169c0eaSGlenn Lagasse {
2775f169c0eaSGlenn Lagasse 	be_transaction_data_t	*bt = data;
2776f169c0eaSGlenn Lagasse 	char			*mp = NULL;
2777f169c0eaSGlenn Lagasse 
2778f169c0eaSGlenn Lagasse 	/*
2779f169c0eaSGlenn Lagasse 	 * Check if dataset is mounted, and if so where.
2780f169c0eaSGlenn Lagasse 	 */
2781f169c0eaSGlenn Lagasse 	if (zfs_is_mounted(zhp, &mp)) {
2782f169c0eaSGlenn Lagasse 		/*
2783f169c0eaSGlenn Lagasse 		 * If mounted at root, set obe_root_ds and obe_name
2784f169c0eaSGlenn Lagasse 		 */
2785f169c0eaSGlenn Lagasse 		if (mp != NULL && strcmp(mp, "/") == 0) {
2786f169c0eaSGlenn Lagasse 			free(mp);
2787f169c0eaSGlenn Lagasse 
2788f169c0eaSGlenn Lagasse 			if ((bt->obe_root_ds = strdup(zfs_get_name(zhp)))
2789f169c0eaSGlenn Lagasse 			    == NULL) {
2790f169c0eaSGlenn Lagasse 				be_print_err(gettext(
2791f169c0eaSGlenn Lagasse 				    "be_zfs_find_current_be_callback: "
2792f169c0eaSGlenn Lagasse 				    "memory allocation failed\n"));
2793f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
2794f169c0eaSGlenn Lagasse 				return (0);
2795f169c0eaSGlenn Lagasse 			}
2796de1ab35cSAlexander Eremin 
2797f169c0eaSGlenn Lagasse 			if ((bt->obe_name = strdup(basename(bt->obe_root_ds)))
2798f169c0eaSGlenn Lagasse 			    == NULL) {
2799f169c0eaSGlenn Lagasse 				be_print_err(gettext(
2800f169c0eaSGlenn Lagasse 				    "be_zfs_find_current_be_callback: "
2801f169c0eaSGlenn Lagasse 				    "memory allocation failed\n"));
2802f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
2803f169c0eaSGlenn Lagasse 				return (0);
2804f169c0eaSGlenn Lagasse 			}
2805f169c0eaSGlenn Lagasse 
2806f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
2807f169c0eaSGlenn Lagasse 			return (1);
2808f169c0eaSGlenn Lagasse 		}
2809f169c0eaSGlenn Lagasse 
2810f169c0eaSGlenn Lagasse 		free(mp);
2811f169c0eaSGlenn Lagasse 	}
2812f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
2813f169c0eaSGlenn Lagasse 
2814f169c0eaSGlenn Lagasse 	return (0);
2815f169c0eaSGlenn Lagasse }
2816f169c0eaSGlenn Lagasse 
2817f169c0eaSGlenn Lagasse /*
2818f169c0eaSGlenn Lagasse  * Function:	be_check_be_roots_callback
2819f169c0eaSGlenn Lagasse  * Description:	This function checks whether or not the dataset name passed
2820f169c0eaSGlenn Lagasse  *		is hierachically located under the BE root container dataset
2821f169c0eaSGlenn Lagasse  *		for this pool.
2822f169c0eaSGlenn Lagasse  * Parameters:
2823f169c0eaSGlenn Lagasse  *		zlp - zpool_handle_t pointer to current pool being processed.
2824f169c0eaSGlenn Lagasse  *		data - name of dataset to check
2825f169c0eaSGlenn Lagasse  * Returns:
2826f169c0eaSGlenn Lagasse  *		0 - dataset is not in this pool's BE root container dataset
2827f169c0eaSGlenn Lagasse  *		1 - dataset is in this pool's BE root container dataset
2828f169c0eaSGlenn Lagasse  * Scope:
2829f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2830f169c0eaSGlenn Lagasse  */
2831f169c0eaSGlenn Lagasse int
2832f169c0eaSGlenn Lagasse be_check_be_roots_callback(zpool_handle_t *zlp, void *data)
2833f169c0eaSGlenn Lagasse {
2834f169c0eaSGlenn Lagasse 	const char	*zpool = zpool_get_name(zlp);
2835f169c0eaSGlenn Lagasse 	char		*ds = data;
2836f169c0eaSGlenn Lagasse 	char		be_container_ds[MAXPATHLEN];
2837f169c0eaSGlenn Lagasse 
2838f169c0eaSGlenn Lagasse 	/* Generate string for this pool's BE root container dataset */
2839f169c0eaSGlenn Lagasse 	be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds));
2840f169c0eaSGlenn Lagasse 
2841f169c0eaSGlenn Lagasse 	/*
2842f169c0eaSGlenn Lagasse 	 * If dataset lives under the BE root container dataset
2843f169c0eaSGlenn Lagasse 	 * of this pool, return failure.
2844f169c0eaSGlenn Lagasse 	 */
2845f169c0eaSGlenn Lagasse 	if (strncmp(be_container_ds, ds, strlen(be_container_ds)) == 0 &&
2846f169c0eaSGlenn Lagasse 	    ds[strlen(be_container_ds)] == '/') {
2847f169c0eaSGlenn Lagasse 		zpool_close(zlp);
2848f169c0eaSGlenn Lagasse 		return (1);
2849f169c0eaSGlenn Lagasse 	}
2850f169c0eaSGlenn Lagasse 
2851f169c0eaSGlenn Lagasse 	zpool_close(zlp);
2852f169c0eaSGlenn Lagasse 	return (0);
2853f169c0eaSGlenn Lagasse }
2854f169c0eaSGlenn Lagasse 
2855f169c0eaSGlenn Lagasse /*
2856f169c0eaSGlenn Lagasse  * Function:	zfs_err_to_be_err
2857f169c0eaSGlenn Lagasse  * Description:	This function takes the error stored in the libzfs handle
2858f169c0eaSGlenn Lagasse  *		and maps it to an be_errno_t. If there are no matching
2859f169c0eaSGlenn Lagasse  *		be_errno_t's then BE_ERR_ZFS is returned.
2860f169c0eaSGlenn Lagasse  * Paramters:
2861f169c0eaSGlenn Lagasse  *		zfsh - The libzfs handle containing the error we're looking up.
2862f169c0eaSGlenn Lagasse  * Returns:
2863f169c0eaSGlenn Lagasse  *		be_errno_t
2864f169c0eaSGlenn Lagasse  * Scope:
2865f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2866f169c0eaSGlenn Lagasse  */
2867f169c0eaSGlenn Lagasse int
2868f169c0eaSGlenn Lagasse zfs_err_to_be_err(libzfs_handle_t *zfsh)
2869f169c0eaSGlenn Lagasse {
2870f169c0eaSGlenn Lagasse 	int err = libzfs_errno(zfsh);
2871f169c0eaSGlenn Lagasse 
2872f169c0eaSGlenn Lagasse 	switch (err) {
2873f169c0eaSGlenn Lagasse 	case 0:
2874f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
2875f169c0eaSGlenn Lagasse 	case EZFS_PERM:
2876f169c0eaSGlenn Lagasse 		return (BE_ERR_PERM);
2877f169c0eaSGlenn Lagasse 	case EZFS_INTR:
2878f169c0eaSGlenn Lagasse 		return (BE_ERR_INTR);
2879f169c0eaSGlenn Lagasse 	case EZFS_NOENT:
2880f169c0eaSGlenn Lagasse 		return (BE_ERR_NOENT);
2881f169c0eaSGlenn Lagasse 	case EZFS_NOSPC:
2882f169c0eaSGlenn Lagasse 		return (BE_ERR_NOSPC);
2883f169c0eaSGlenn Lagasse 	case EZFS_MOUNTFAILED:
2884f169c0eaSGlenn Lagasse 		return (BE_ERR_MOUNT);
2885f169c0eaSGlenn Lagasse 	case EZFS_UMOUNTFAILED:
2886f169c0eaSGlenn Lagasse 		return (BE_ERR_UMOUNT);
2887f169c0eaSGlenn Lagasse 	case EZFS_EXISTS:
2888f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_EXISTS);
2889f169c0eaSGlenn Lagasse 	case EZFS_BUSY:
2890f169c0eaSGlenn Lagasse 		return (BE_ERR_DEV_BUSY);
2891f9af39baSGeorge Wilson 	case EZFS_POOLREADONLY:
2892f169c0eaSGlenn Lagasse 		return (BE_ERR_ROFS);
2893f169c0eaSGlenn Lagasse 	case EZFS_NAMETOOLONG:
2894f169c0eaSGlenn Lagasse 		return (BE_ERR_NAMETOOLONG);
2895f169c0eaSGlenn Lagasse 	case EZFS_NODEVICE:
2896f169c0eaSGlenn Lagasse 		return (BE_ERR_NODEV);
2897f169c0eaSGlenn Lagasse 	case EZFS_POOL_INVALARG:
2898f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
2899f169c0eaSGlenn Lagasse 	case EZFS_PROPTYPE:
2900f169c0eaSGlenn Lagasse 		return (BE_ERR_INVALPROP);
2901f169c0eaSGlenn Lagasse 	case EZFS_BADTYPE:
2902f169c0eaSGlenn Lagasse 		return (BE_ERR_DSTYPE);
2903f169c0eaSGlenn Lagasse 	case EZFS_PROPNONINHERIT:
2904f169c0eaSGlenn Lagasse 		return (BE_ERR_NONINHERIT);
2905f169c0eaSGlenn Lagasse 	case EZFS_PROPREADONLY:
2906f169c0eaSGlenn Lagasse 		return (BE_ERR_READONLYPROP);
2907f169c0eaSGlenn Lagasse 	case EZFS_RESILVERING:
2908f169c0eaSGlenn Lagasse 	case EZFS_POOLUNAVAIL:
2909f169c0eaSGlenn Lagasse 		return (BE_ERR_UNAVAIL);
2910f169c0eaSGlenn Lagasse 	case EZFS_DSREADONLY:
2911f169c0eaSGlenn Lagasse 		return (BE_ERR_READONLYDS);
2912f169c0eaSGlenn Lagasse 	default:
2913f169c0eaSGlenn Lagasse 		return (BE_ERR_ZFS);
2914f169c0eaSGlenn Lagasse 	}
2915f169c0eaSGlenn Lagasse }
2916f169c0eaSGlenn Lagasse 
2917f169c0eaSGlenn Lagasse /*
2918f169c0eaSGlenn Lagasse  * Function:	errno_to_be_err
2919f169c0eaSGlenn Lagasse  * Description:	This function takes an errno and maps it to an be_errno_t.
2920f169c0eaSGlenn Lagasse  *		If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
2921f169c0eaSGlenn Lagasse  *		returned.
2922f169c0eaSGlenn Lagasse  * Paramters:
2923f169c0eaSGlenn Lagasse  *		err - The errno we're compairing against.
2924f169c0eaSGlenn Lagasse  * Returns:
2925f169c0eaSGlenn Lagasse  *		be_errno_t
2926f169c0eaSGlenn Lagasse  * Scope:
2927f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2928f169c0eaSGlenn Lagasse  */
2929f169c0eaSGlenn Lagasse int
2930f169c0eaSGlenn Lagasse errno_to_be_err(int err)
2931f169c0eaSGlenn Lagasse {
2932f169c0eaSGlenn Lagasse 	switch (err) {
2933f169c0eaSGlenn Lagasse 	case EPERM:
2934f169c0eaSGlenn Lagasse 		return (BE_ERR_PERM);
2935f169c0eaSGlenn Lagasse 	case EACCES:
2936f169c0eaSGlenn Lagasse 		return (BE_ERR_ACCESS);
2937f169c0eaSGlenn Lagasse 	case ECANCELED:
2938f169c0eaSGlenn Lagasse 		return (BE_ERR_CANCELED);
2939f169c0eaSGlenn Lagasse 	case EINTR:
2940f169c0eaSGlenn Lagasse 		return (BE_ERR_INTR);
2941f169c0eaSGlenn Lagasse 	case ENOENT:
2942f169c0eaSGlenn Lagasse 		return (BE_ERR_NOENT);
2943f169c0eaSGlenn Lagasse 	case ENOSPC:
2944f169c0eaSGlenn Lagasse 	case EDQUOT:
2945f169c0eaSGlenn Lagasse 		return (BE_ERR_NOSPC);
2946f169c0eaSGlenn Lagasse 	case EEXIST:
2947f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_EXISTS);
2948f169c0eaSGlenn Lagasse 	case EBUSY:
2949f169c0eaSGlenn Lagasse 		return (BE_ERR_BUSY);
2950f169c0eaSGlenn Lagasse 	case EROFS:
2951f169c0eaSGlenn Lagasse 		return (BE_ERR_ROFS);
2952f169c0eaSGlenn Lagasse 	case ENAMETOOLONG:
2953f169c0eaSGlenn Lagasse 		return (BE_ERR_NAMETOOLONG);
2954f169c0eaSGlenn Lagasse 	case ENXIO:
2955f169c0eaSGlenn Lagasse 		return (BE_ERR_NXIO);
2956f169c0eaSGlenn Lagasse 	case EINVAL:
2957f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
2958f169c0eaSGlenn Lagasse 	case EFAULT:
2959f169c0eaSGlenn Lagasse 		return (BE_ERR_FAULT);
2960f169c0eaSGlenn Lagasse 	default:
2961f169c0eaSGlenn Lagasse 		return (BE_ERR_UNKNOWN);
2962f169c0eaSGlenn Lagasse 	}
2963f169c0eaSGlenn Lagasse }
2964f169c0eaSGlenn Lagasse 
2965f169c0eaSGlenn Lagasse /*
2966f169c0eaSGlenn Lagasse  * Function:	be_err_to_str
2967f169c0eaSGlenn Lagasse  * Description:	This function takes a be_errno_t and maps it to a message.
2968f169c0eaSGlenn Lagasse  *		If there are no matching be_errno_t's then NULL is returned.
2969f169c0eaSGlenn Lagasse  * Paramters:
2970f169c0eaSGlenn Lagasse  *		be_errno_t - The be_errno_t we're mapping.
2971f169c0eaSGlenn Lagasse  * Returns:
2972f169c0eaSGlenn Lagasse  *		string or NULL if the error code is not known.
2973f169c0eaSGlenn Lagasse  * Scope:
2974f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
2975f169c0eaSGlenn Lagasse  */
2976f169c0eaSGlenn Lagasse char *
2977f169c0eaSGlenn Lagasse be_err_to_str(int err)
2978f169c0eaSGlenn Lagasse {
2979f169c0eaSGlenn Lagasse 	switch (err) {
2980f169c0eaSGlenn Lagasse 	case BE_ERR_ACCESS:
2981f169c0eaSGlenn Lagasse 		return (gettext("Permission denied."));
2982f169c0eaSGlenn Lagasse 	case BE_ERR_ACTIVATE_CURR:
2983f169c0eaSGlenn Lagasse 		return (gettext("Activation of current BE failed."));
2984f169c0eaSGlenn Lagasse 	case BE_ERR_AUTONAME:
2985f169c0eaSGlenn Lagasse 		return (gettext("Auto naming failed."));
2986f169c0eaSGlenn Lagasse 	case BE_ERR_BE_NOENT:
2987f169c0eaSGlenn Lagasse 		return (gettext("No such BE."));
2988f169c0eaSGlenn Lagasse 	case BE_ERR_BUSY:
2989f169c0eaSGlenn Lagasse 		return (gettext("Mount busy."));
2990f169c0eaSGlenn Lagasse 	case BE_ERR_DEV_BUSY:
2991f169c0eaSGlenn Lagasse 		return (gettext("Device busy."));
2992f169c0eaSGlenn Lagasse 	case BE_ERR_CANCELED:
2993f169c0eaSGlenn Lagasse 		return (gettext("Operation canceled."));
2994f169c0eaSGlenn Lagasse 	case BE_ERR_CLONE:
2995f169c0eaSGlenn Lagasse 		return (gettext("BE clone failed."));
2996f169c0eaSGlenn Lagasse 	case BE_ERR_COPY:
2997f169c0eaSGlenn Lagasse 		return (gettext("BE copy failed."));
2998f169c0eaSGlenn Lagasse 	case BE_ERR_CREATDS:
2999f169c0eaSGlenn Lagasse 		return (gettext("Dataset creation failed."));
3000f169c0eaSGlenn Lagasse 	case BE_ERR_CURR_BE_NOT_FOUND:
3001f169c0eaSGlenn Lagasse 		return (gettext("Can't find current BE."));
3002f169c0eaSGlenn Lagasse 	case BE_ERR_DESTROY:
3003f169c0eaSGlenn Lagasse 		return (gettext("Failed to destroy BE or snapshot."));
3004f169c0eaSGlenn Lagasse 	case BE_ERR_DESTROY_CURR_BE:
3005f169c0eaSGlenn Lagasse 		return (gettext("Cannot destroy current BE."));
3006f169c0eaSGlenn Lagasse 	case BE_ERR_DEMOTE:
3007f169c0eaSGlenn Lagasse 		return (gettext("BE demotion failed."));
3008f169c0eaSGlenn Lagasse 	case BE_ERR_DSTYPE:
3009f169c0eaSGlenn Lagasse 		return (gettext("Invalid dataset type."));
3010f169c0eaSGlenn Lagasse 	case BE_ERR_BE_EXISTS:
3011f169c0eaSGlenn Lagasse 		return (gettext("BE exists."));
3012f169c0eaSGlenn Lagasse 	case BE_ERR_INIT:
3013f169c0eaSGlenn Lagasse 		return (gettext("be_zfs_init failed."));
3014f169c0eaSGlenn Lagasse 	case BE_ERR_INTR:
3015f169c0eaSGlenn Lagasse 		return (gettext("Interupted system call."));
3016f169c0eaSGlenn Lagasse 	case BE_ERR_INVAL:
3017f169c0eaSGlenn Lagasse 		return (gettext("Invalid argument."));
3018f169c0eaSGlenn Lagasse 	case BE_ERR_INVALPROP:
3019f169c0eaSGlenn Lagasse 		return (gettext("Invalid property for dataset."));
3020f169c0eaSGlenn Lagasse 	case BE_ERR_INVALMOUNTPOINT:
3021f169c0eaSGlenn Lagasse 		return (gettext("Unexpected mountpoint."));
3022f169c0eaSGlenn Lagasse 	case BE_ERR_MOUNT:
3023f169c0eaSGlenn Lagasse 		return (gettext("Mount failed."));
3024f169c0eaSGlenn Lagasse 	case BE_ERR_MOUNTED:
3025f169c0eaSGlenn Lagasse 		return (gettext("Already mounted."));
3026f169c0eaSGlenn Lagasse 	case BE_ERR_NAMETOOLONG:
3027f169c0eaSGlenn Lagasse 		return (gettext("name > BUFSIZ."));
3028f169c0eaSGlenn Lagasse 	case BE_ERR_NOENT:
3029f169c0eaSGlenn Lagasse 		return (gettext("Doesn't exist."));
3030f169c0eaSGlenn Lagasse 	case BE_ERR_POOL_NOENT:
3031f169c0eaSGlenn Lagasse 		return (gettext("No such pool."));
3032f169c0eaSGlenn Lagasse 	case BE_ERR_NODEV:
3033f169c0eaSGlenn Lagasse 		return (gettext("No such device."));
3034f169c0eaSGlenn Lagasse 	case BE_ERR_NOTMOUNTED:
3035f169c0eaSGlenn Lagasse 		return (gettext("File system not mounted."));
3036f169c0eaSGlenn Lagasse 	case BE_ERR_NOMEM:
3037f169c0eaSGlenn Lagasse 		return (gettext("Not enough memory."));
3038f169c0eaSGlenn Lagasse 	case BE_ERR_NONINHERIT:
3039f169c0eaSGlenn Lagasse 		return (gettext(
3040f169c0eaSGlenn Lagasse 		    "Property is not inheritable for the BE dataset."));
3041f169c0eaSGlenn Lagasse 	case BE_ERR_NXIO:
3042f169c0eaSGlenn Lagasse 		return (gettext("No such device or address."));
3043f169c0eaSGlenn Lagasse 	case BE_ERR_NOSPC:
3044f169c0eaSGlenn Lagasse 		return (gettext("No space on device."));
3045f169c0eaSGlenn Lagasse 	case BE_ERR_NOTSUP:
3046f169c0eaSGlenn Lagasse 		return (gettext("Operation not supported."));
3047f169c0eaSGlenn Lagasse 	case BE_ERR_OPEN:
3048f169c0eaSGlenn Lagasse 		return (gettext("Open failed."));
3049f169c0eaSGlenn Lagasse 	case BE_ERR_PERM:
3050f169c0eaSGlenn Lagasse 		return (gettext("Not owner."));
3051f169c0eaSGlenn Lagasse 	case BE_ERR_UNAVAIL:
3052f169c0eaSGlenn Lagasse 		return (gettext("The BE is currently unavailable."));
3053f169c0eaSGlenn Lagasse 	case BE_ERR_PROMOTE:
3054f169c0eaSGlenn Lagasse 		return (gettext("BE promotion failed."));
3055f169c0eaSGlenn Lagasse 	case BE_ERR_ROFS:
3056f169c0eaSGlenn Lagasse 		return (gettext("Read only file system."));
3057f169c0eaSGlenn Lagasse 	case BE_ERR_READONLYDS:
3058f169c0eaSGlenn Lagasse 		return (gettext("Read only dataset."));
3059f169c0eaSGlenn Lagasse 	case BE_ERR_READONLYPROP:
3060f169c0eaSGlenn Lagasse 		return (gettext("Read only property."));
3061f169c0eaSGlenn Lagasse 	case BE_ERR_RENAME_ACTIVE:
3062f169c0eaSGlenn Lagasse 		return (gettext("Renaming the active BE is not supported."));
3063f169c0eaSGlenn Lagasse 	case BE_ERR_SS_EXISTS:
3064f169c0eaSGlenn Lagasse 		return (gettext("Snapshot exists."));
3065f169c0eaSGlenn Lagasse 	case BE_ERR_SS_NOENT:
3066f169c0eaSGlenn Lagasse 		return (gettext("No such snapshot."));
3067f169c0eaSGlenn Lagasse 	case BE_ERR_UMOUNT:
3068f169c0eaSGlenn Lagasse 		return (gettext("Unmount failed."));
3069f169c0eaSGlenn Lagasse 	case BE_ERR_UMOUNT_CURR_BE:
3070f169c0eaSGlenn Lagasse 		return (gettext("Can't unmount the current BE."));
3071f169c0eaSGlenn Lagasse 	case BE_ERR_UMOUNT_SHARED:
3072f169c0eaSGlenn Lagasse 		return (gettext("Unmount of a shared File System failed."));
3073f169c0eaSGlenn Lagasse 	case BE_ERR_FAULT:
3074f169c0eaSGlenn Lagasse 		return (gettext("Bad address."));
3075f169c0eaSGlenn Lagasse 	case BE_ERR_UNKNOWN:
3076f169c0eaSGlenn Lagasse 		return (gettext("Unknown error."));
3077f169c0eaSGlenn Lagasse 	case BE_ERR_ZFS:
3078f169c0eaSGlenn Lagasse 		return (gettext("ZFS returned an error."));
3079f169c0eaSGlenn Lagasse 	case BE_ERR_GEN_UUID:
3080f169c0eaSGlenn Lagasse 		return (gettext("Failed to generate uuid."));
3081f169c0eaSGlenn Lagasse 	case BE_ERR_PARSE_UUID:
3082f169c0eaSGlenn Lagasse 		return (gettext("Failed to parse uuid."));
3083f169c0eaSGlenn Lagasse 	case BE_ERR_NO_UUID:
3084f169c0eaSGlenn Lagasse 		return (gettext("No uuid"));
3085f169c0eaSGlenn Lagasse 	case BE_ERR_ZONE_NO_PARENTBE:
3086f169c0eaSGlenn Lagasse 		return (gettext("No parent uuid"));
3087f169c0eaSGlenn Lagasse 	case BE_ERR_ZONE_MULTIPLE_ACTIVE:
3088f169c0eaSGlenn Lagasse 		return (gettext("Multiple active zone roots"));
3089f169c0eaSGlenn Lagasse 	case BE_ERR_ZONE_NO_ACTIVE_ROOT:
3090f169c0eaSGlenn Lagasse 		return (gettext("No active zone root"));
3091f169c0eaSGlenn Lagasse 	case BE_ERR_ZONE_ROOT_NOT_LEGACY:
3092f169c0eaSGlenn Lagasse 		return (gettext("Zone root not legacy"));
3093f169c0eaSGlenn Lagasse 	case BE_ERR_MOUNT_ZONEROOT:
3094f169c0eaSGlenn Lagasse 		return (gettext("Failed to mount a zone root."));
3095f169c0eaSGlenn Lagasse 	case BE_ERR_UMOUNT_ZONEROOT:
3096f169c0eaSGlenn Lagasse 		return (gettext("Failed to unmount a zone root."));
3097f169c0eaSGlenn Lagasse 	case BE_ERR_NO_MOUNTED_ZONE:
3098f169c0eaSGlenn Lagasse 		return (gettext("Zone is not mounted"));
3099f169c0eaSGlenn Lagasse 	case BE_ERR_ZONES_UNMOUNT:
3100f169c0eaSGlenn Lagasse 		return (gettext("Unable to unmount a zone BE."));
3101f169c0eaSGlenn Lagasse 	case BE_ERR_NO_MENU:
3102f169c0eaSGlenn Lagasse 		return (gettext("Missing boot menu file."));
3103f169c0eaSGlenn Lagasse 	case BE_ERR_BAD_MENU_PATH:
3104f169c0eaSGlenn Lagasse 		return (gettext("Invalid path for menu.lst file"));
3105f169c0eaSGlenn Lagasse 	case BE_ERR_ZONE_SS_EXISTS:
3106f169c0eaSGlenn Lagasse 		return (gettext("Zone snapshot exists."));
3107f169c0eaSGlenn Lagasse 	case BE_ERR_BOOTFILE_INST:
3108f169c0eaSGlenn Lagasse 		return (gettext("Error installing boot files."));
3109f169c0eaSGlenn Lagasse 	case BE_ERR_EXTCMD:
3110f169c0eaSGlenn Lagasse 		return (gettext("Error running an external command."));
3111f169c0eaSGlenn Lagasse 	default:
3112f169c0eaSGlenn Lagasse 		return (NULL);
3113f169c0eaSGlenn Lagasse 	}
3114f169c0eaSGlenn Lagasse }
3115f169c0eaSGlenn Lagasse 
3116f169c0eaSGlenn Lagasse /*
3117f169c0eaSGlenn Lagasse  * Function:    be_has_grub
3118f169c0eaSGlenn Lagasse  * Description: Boolean function indicating whether the current system
3119f169c0eaSGlenn Lagasse  *		uses grub.
3120f169c0eaSGlenn Lagasse  * Return:      B_FALSE - the system does not have grub
3121f169c0eaSGlenn Lagasse  *              B_TRUE - the system does have grub.
3122f169c0eaSGlenn Lagasse  * Scope:
3123f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
3124f169c0eaSGlenn Lagasse  */
3125f169c0eaSGlenn Lagasse boolean_t
3126f169c0eaSGlenn Lagasse be_has_grub(void)
3127f169c0eaSGlenn Lagasse {
3128fa0c327aSToomas Soome 	static struct be_defaults be_defaults;
3129fa0c327aSToomas Soome 	static boolean_t be_deflts_set = B_FALSE;
3130fa0c327aSToomas Soome 
3131fa0c327aSToomas Soome 	/* Cache the defaults, because be_has_grub is used often. */
3132fa0c327aSToomas Soome 	if (be_deflts_set == B_FALSE) {
3133fa0c327aSToomas Soome 		be_get_defaults(&be_defaults);
3134fa0c327aSToomas Soome 		be_deflts_set = B_TRUE;
3135fa0c327aSToomas Soome 	}
3136fa0c327aSToomas Soome 
3137fa0c327aSToomas Soome 	return (be_defaults.be_deflt_grub);
3138f169c0eaSGlenn Lagasse }
3139f169c0eaSGlenn Lagasse 
3140f169c0eaSGlenn Lagasse /*
3141f169c0eaSGlenn Lagasse  * Function:    be_is_isa
3142f169c0eaSGlenn Lagasse  * Description: Boolean function indicating whether the instruction set
3143f169c0eaSGlenn Lagasse  *              architecture of the executing system matches the name provided.
3144f169c0eaSGlenn Lagasse  *              The string must match a system defined architecture (e.g.
3145f169c0eaSGlenn Lagasse  *              "i386", "sparc") and is case sensitive.
3146f169c0eaSGlenn Lagasse  * Parameters:  name - string representing the name of instruction set
3147f169c0eaSGlenn Lagasse  *			architecture being tested
3148f169c0eaSGlenn Lagasse  * Returns:     B_FALSE - the system instruction set architecture is different
3149f169c0eaSGlenn Lagasse  *			from the one specified
3150f169c0eaSGlenn Lagasse  *              B_TRUE - the system instruction set architecture is the same
3151f169c0eaSGlenn Lagasse  *			as the one specified
3152f169c0eaSGlenn Lagasse  * Scope:
3153f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
3154f169c0eaSGlenn Lagasse  */
3155f169c0eaSGlenn Lagasse boolean_t
3156f169c0eaSGlenn Lagasse be_is_isa(char *name)
3157f169c0eaSGlenn Lagasse {
3158f169c0eaSGlenn Lagasse 	return ((strcmp((char *)be_get_default_isa(), name) == 0));
3159f169c0eaSGlenn Lagasse }
3160f169c0eaSGlenn Lagasse 
3161f169c0eaSGlenn Lagasse /*
3162f169c0eaSGlenn Lagasse  * Function: be_get_default_isa
3163f169c0eaSGlenn Lagasse  * Description:
3164f169c0eaSGlenn Lagasse  *      Returns the default instruction set architecture of the
3165f169c0eaSGlenn Lagasse  *      machine it is executed on. (eg. sparc, i386, ...)
3166f169c0eaSGlenn Lagasse  *      NOTE:   SYS_INST environment variable may override default
3167f169c0eaSGlenn Lagasse  *              return value
3168f169c0eaSGlenn Lagasse  * Parameters:
3169f169c0eaSGlenn Lagasse  *		none
3170f169c0eaSGlenn Lagasse  * Returns:
3171f169c0eaSGlenn Lagasse  *		NULL - the architecture returned by sysinfo() was too
3172f169c0eaSGlenn Lagasse  *			long for local variables
3173f169c0eaSGlenn Lagasse  *		char * - pointer to a string containing the default
3174f169c0eaSGlenn Lagasse  *			implementation
3175f169c0eaSGlenn Lagasse  * Scope:
3176f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
3177f169c0eaSGlenn Lagasse  */
3178f169c0eaSGlenn Lagasse char *
3179f169c0eaSGlenn Lagasse be_get_default_isa(void)
3180f169c0eaSGlenn Lagasse {
3181f169c0eaSGlenn Lagasse 	int	i;
3182f169c0eaSGlenn Lagasse 	char	*envp;
3183f169c0eaSGlenn Lagasse 	static char	default_inst[ARCH_LENGTH] = "";
3184f169c0eaSGlenn Lagasse 
3185f169c0eaSGlenn Lagasse 	if (default_inst[0] == '\0') {
3186f169c0eaSGlenn Lagasse 		if ((envp = getenv("SYS_INST")) != NULL) {
3187f169c0eaSGlenn Lagasse 			if ((int)strlen(envp) >= ARCH_LENGTH)
3188f169c0eaSGlenn Lagasse 				return (NULL);
3189f169c0eaSGlenn Lagasse 			else
3190f169c0eaSGlenn Lagasse 				(void) strcpy(default_inst, envp);
3191f169c0eaSGlenn Lagasse 		} else  {
3192f169c0eaSGlenn Lagasse 			i = sysinfo(SI_ARCHITECTURE, default_inst, ARCH_LENGTH);
3193f169c0eaSGlenn Lagasse 			if (i < 0 || i > ARCH_LENGTH)
3194f169c0eaSGlenn Lagasse 				return (NULL);
3195f169c0eaSGlenn Lagasse 		}
3196f169c0eaSGlenn Lagasse 	}
3197f169c0eaSGlenn Lagasse 	return (default_inst);
3198f169c0eaSGlenn Lagasse }
3199f169c0eaSGlenn Lagasse 
3200a63c99a2SToomas Soome /*
3201a63c99a2SToomas Soome  * Function: be_get_platform
3202a63c99a2SToomas Soome  * Description:
3203a63c99a2SToomas Soome  *      Returns the platfom name
3204a63c99a2SToomas Soome  * Parameters:
3205a63c99a2SToomas Soome  *		none
3206a63c99a2SToomas Soome  * Returns:
3207a63c99a2SToomas Soome  *		NULL - the platform name returned by sysinfo() was too
3208a63c99a2SToomas Soome  *			long for local variables
3209a63c99a2SToomas Soome  *		char * - pointer to a string containing the platform name
3210a63c99a2SToomas Soome  * Scope:
3211a63c99a2SToomas Soome  *		Semi-private (library wide use only)
3212a63c99a2SToomas Soome  */
3213a63c99a2SToomas Soome char *
3214a63c99a2SToomas Soome be_get_platform(void)
3215a63c99a2SToomas Soome {
3216a63c99a2SToomas Soome 	int	i;
3217a63c99a2SToomas Soome 	static char	default_inst[ARCH_LENGTH] = "";
3218a63c99a2SToomas Soome 
3219a63c99a2SToomas Soome 	if (default_inst[0] == '\0') {
3220a63c99a2SToomas Soome 		i = sysinfo(SI_PLATFORM, default_inst, ARCH_LENGTH);
3221a63c99a2SToomas Soome 		if (i < 0 || i > ARCH_LENGTH)
3222a63c99a2SToomas Soome 			return (NULL);
3223a63c99a2SToomas Soome 	}
3224a63c99a2SToomas Soome 	return (default_inst);
3225a63c99a2SToomas Soome }
3226a63c99a2SToomas Soome 
3227f169c0eaSGlenn Lagasse /*
3228f169c0eaSGlenn Lagasse  * Function: be_run_cmd
3229f169c0eaSGlenn Lagasse  * Description:
3230f169c0eaSGlenn Lagasse  *	Runs a command in a separate subprocess.  Splits out stdout from stderr
3231f169c0eaSGlenn Lagasse  *	and sends each to its own buffer.  Buffers must be pre-allocated and
3232f169c0eaSGlenn Lagasse  *	passed in as arguments.  Buffer sizes are also passed in as arguments.
3233f169c0eaSGlenn Lagasse  *
3234f169c0eaSGlenn Lagasse  *	Notes / caveats:
3235f169c0eaSGlenn Lagasse  *	- Command being run is assumed to not have any stdout or stderr
3236f169c0eaSGlenn Lagasse  *		redirection.
3237f169c0eaSGlenn Lagasse  *	- Commands which emit total stderr output of greater than PIPE_BUF
3238f169c0eaSGlenn Lagasse  *		bytes can hang.  For such commands, a different implementation
3239f169c0eaSGlenn Lagasse  *		which uses poll(2) must be used.
3240f169c0eaSGlenn Lagasse  *	- stdout_buf can be NULL.  In this case, stdout_bufsize is ignored, and
3241f169c0eaSGlenn Lagasse  *		the stream which would have gone to it is sent to the bit
3242f169c0eaSGlenn Lagasse  *		bucket.
3243f169c0eaSGlenn Lagasse  *	- stderr_buf cannot be NULL.
3244f169c0eaSGlenn Lagasse  *	- Only subprocess errors are appended to the stderr_buf.  Errors
3245f169c0eaSGlenn Lagasse  *		running the command are reported through be_print_err().
3246f169c0eaSGlenn Lagasse  *	- Data which would overflow its respective buffer is sent to the bit
3247f169c0eaSGlenn Lagasse  *		bucket.
3248f169c0eaSGlenn Lagasse  *
3249f169c0eaSGlenn Lagasse  * Parameters:
3250f169c0eaSGlenn Lagasse  *		command: command to run.  Assumed not to have embedded stdout
3251f169c0eaSGlenn Lagasse  *			or stderr redirection.  May have stdin redirection,
3252f169c0eaSGlenn Lagasse  *			however.
3253f169c0eaSGlenn Lagasse  *		stderr_buf: buffer returning subprocess stderr data.  Errors
3254f169c0eaSGlenn Lagasse  *			reported by this function are reported through
3255f169c0eaSGlenn Lagasse  *			be_print_err().
3256f169c0eaSGlenn Lagasse  *		stderr_bufsize: size of stderr_buf
3257f169c0eaSGlenn Lagasse  *		stdout_buf: buffer returning subprocess stdout data.
3258f169c0eaSGlenn Lagasse  *		stdout_bufsize: size of stdout_buf
3259f169c0eaSGlenn Lagasse  * Returns:
3260f169c0eaSGlenn Lagasse  *		BE_SUCCESS - The command ran successfully without returning
3261f169c0eaSGlenn Lagasse  *			errors.
3262f169c0eaSGlenn Lagasse  *		BE_ERR_EXTCMD
3263f169c0eaSGlenn Lagasse  *			- The command could not be run.
3264f169c0eaSGlenn Lagasse  *			- The command terminated with error status.
3265f169c0eaSGlenn Lagasse  *			- There were errors extracting or returning subprocess
3266f169c0eaSGlenn Lagasse  *				data.
3267f169c0eaSGlenn Lagasse  *		BE_ERR_NOMEM - The command exceeds the command buffer size.
3268f169c0eaSGlenn Lagasse  *		BE_ERR_INVAL - An invalid argument was specified.
3269f169c0eaSGlenn Lagasse  * Scope:
3270f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
3271f169c0eaSGlenn Lagasse  */
3272f169c0eaSGlenn Lagasse int
3273f169c0eaSGlenn Lagasse be_run_cmd(char *command, char *stderr_buf, int stderr_bufsize,
3274f169c0eaSGlenn Lagasse     char *stdout_buf, int stdout_bufsize)
3275f169c0eaSGlenn Lagasse {
3276f169c0eaSGlenn Lagasse 	char *temp_filename = strdup(tmpnam(NULL));
3277f169c0eaSGlenn Lagasse 	FILE *stdout_str = NULL;
3278f169c0eaSGlenn Lagasse 	FILE *stderr_str = NULL;
3279f169c0eaSGlenn Lagasse 	char cmdline[BUFSIZ];
3280f169c0eaSGlenn Lagasse 	char oneline[BUFSIZ];
3281f169c0eaSGlenn Lagasse 	int exit_status;
3282f169c0eaSGlenn Lagasse 	int rval = BE_SUCCESS;
3283f169c0eaSGlenn Lagasse 
3284f169c0eaSGlenn Lagasse 	if ((command == NULL) || (stderr_buf == NULL) ||
3285f169c0eaSGlenn Lagasse 	    (stderr_bufsize <= 0) || (stdout_bufsize <  0) ||
3286f169c0eaSGlenn Lagasse 	    ((stdout_buf != NULL) ^ (stdout_bufsize != 0))) {
3287f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
32882b66e652SToomas Soome 	}
3289f169c0eaSGlenn Lagasse 
3290f169c0eaSGlenn Lagasse 	/* Set up command so popen returns stderr, not stdout */
3291f169c0eaSGlenn Lagasse 	if (snprintf(cmdline, BUFSIZ, "%s 2> %s", command,
3292f169c0eaSGlenn Lagasse 	    temp_filename) >= BUFSIZ) {
3293f169c0eaSGlenn Lagasse 		rval = BE_ERR_NOMEM;
3294f169c0eaSGlenn Lagasse 		goto cleanup;
3295f169c0eaSGlenn Lagasse 	}
3296f169c0eaSGlenn Lagasse 
3297f169c0eaSGlenn Lagasse 	/* Set up the fifo that will make stderr available. */
3298f169c0eaSGlenn Lagasse 	if (mkfifo(temp_filename, 0600) != 0) {
3299f169c0eaSGlenn Lagasse 		(void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"),
3300f169c0eaSGlenn Lagasse 		    strerror(errno));
3301f169c0eaSGlenn Lagasse 		rval = BE_ERR_EXTCMD;
3302f169c0eaSGlenn Lagasse 		goto cleanup;
3303f169c0eaSGlenn Lagasse 	}
3304f169c0eaSGlenn Lagasse 
3305f169c0eaSGlenn Lagasse 	if ((stdout_str = popen(cmdline, "r")) == NULL) {
3306f169c0eaSGlenn Lagasse 		(void) be_print_err(gettext("be_run_cmd: popen: %s\n"),
3307f169c0eaSGlenn Lagasse 		    strerror(errno));
3308f169c0eaSGlenn Lagasse 		rval = BE_ERR_EXTCMD;
3309f169c0eaSGlenn Lagasse 		goto cleanup;
3310f169c0eaSGlenn Lagasse 	}
3311f169c0eaSGlenn Lagasse 
3312f169c0eaSGlenn Lagasse 	if ((stderr_str = fopen(temp_filename, "r")) == NULL) {
3313f169c0eaSGlenn Lagasse 		(void) be_print_err(gettext("be_run_cmd: fopen: %s\n"),
3314f169c0eaSGlenn Lagasse 		    strerror(errno));
3315f169c0eaSGlenn Lagasse 		(void) pclose(stdout_str);
3316f169c0eaSGlenn Lagasse 		rval = BE_ERR_EXTCMD;
3317f169c0eaSGlenn Lagasse 		goto cleanup;
3318f169c0eaSGlenn Lagasse 	}
3319f169c0eaSGlenn Lagasse 
3320f169c0eaSGlenn Lagasse 	/* Read stdout first, as it usually outputs more than stderr. */
3321f169c0eaSGlenn Lagasse 	oneline[BUFSIZ-1] = '\0';
3322f169c0eaSGlenn Lagasse 	while (fgets(oneline, BUFSIZ-1, stdout_str) != NULL) {
3323f169c0eaSGlenn Lagasse 		if (stdout_str != NULL) {
3324f169c0eaSGlenn Lagasse 			(void) strlcat(stdout_buf, oneline, stdout_bufsize);
3325f169c0eaSGlenn Lagasse 		}
3326f169c0eaSGlenn Lagasse 	}
3327f169c0eaSGlenn Lagasse 
3328f169c0eaSGlenn Lagasse 	while (fgets(oneline, BUFSIZ-1, stderr_str) != NULL) {
3329f169c0eaSGlenn Lagasse 		(void) strlcat(stderr_buf, oneline, stderr_bufsize);
3330f169c0eaSGlenn Lagasse 	}
3331f169c0eaSGlenn Lagasse 
3332f169c0eaSGlenn Lagasse 	/* Close pipe, get exit status. */
3333f169c0eaSGlenn Lagasse 	if ((exit_status = pclose(stdout_str)) == -1) {
3334f169c0eaSGlenn Lagasse 		(void) be_print_err(gettext("be_run_cmd: pclose: %s\n"),
3335f169c0eaSGlenn Lagasse 		    strerror(errno));
3336f169c0eaSGlenn Lagasse 		rval = BE_ERR_EXTCMD;
3337f169c0eaSGlenn Lagasse 	} else if (WIFEXITED(exit_status)) {
3338f169c0eaSGlenn Lagasse 		exit_status = (int)((char)WEXITSTATUS(exit_status));
3339a63c99a2SToomas Soome 		/*
3340a63c99a2SToomas Soome 		 * error code BC_NOUPDT means more recent version
3341a63c99a2SToomas Soome 		 * is installed
3342a63c99a2SToomas Soome 		 */
3343a63c99a2SToomas Soome 		if (exit_status != BC_SUCCESS && exit_status != BC_NOUPDT) {
3344f169c0eaSGlenn Lagasse 			(void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: "
3345f169c0eaSGlenn Lagasse 			    "command terminated with error status: %d\n"),
3346f169c0eaSGlenn Lagasse 			    exit_status);
3347f169c0eaSGlenn Lagasse 			(void) strlcat(stderr_buf, oneline, stderr_bufsize);
3348f169c0eaSGlenn Lagasse 			rval = BE_ERR_EXTCMD;
3349f169c0eaSGlenn Lagasse 		}
3350f169c0eaSGlenn Lagasse 	} else {
3351f169c0eaSGlenn Lagasse 		(void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: command "
3352f169c0eaSGlenn Lagasse 		    "terminated on signal: %s\n"),
3353f169c0eaSGlenn Lagasse 		    strsignal(WTERMSIG(exit_status)));
3354f169c0eaSGlenn Lagasse 		(void) strlcat(stderr_buf, oneline, stderr_bufsize);
3355f169c0eaSGlenn Lagasse 		rval = BE_ERR_EXTCMD;
3356f169c0eaSGlenn Lagasse 	}
3357f169c0eaSGlenn Lagasse 
3358f169c0eaSGlenn Lagasse cleanup:
3359f169c0eaSGlenn Lagasse 	(void) unlink(temp_filename);
3360f169c0eaSGlenn Lagasse 	(void) free(temp_filename);
3361f169c0eaSGlenn Lagasse 
3362f169c0eaSGlenn Lagasse 	return (rval);
3363f169c0eaSGlenn Lagasse }
3364f169c0eaSGlenn Lagasse 
3365f169c0eaSGlenn Lagasse /* ********************************************************************	*/
3366f169c0eaSGlenn Lagasse /*			Private Functions				*/
3367f169c0eaSGlenn Lagasse /* ******************************************************************** */
3368f169c0eaSGlenn Lagasse 
3369f169c0eaSGlenn Lagasse /*
3370f169c0eaSGlenn Lagasse  * Function:	update_dataset
3371f169c0eaSGlenn Lagasse  * Description:	This function takes a dataset name and replaces the zpool
3372f169c0eaSGlenn Lagasse  *		and be_name components of the dataset with the new be_name
3373f169c0eaSGlenn Lagasse  *		zpool passed in.
3374f169c0eaSGlenn Lagasse  * Parameters:
3375f169c0eaSGlenn Lagasse  *		dataset - name of dataset
3376f169c0eaSGlenn Lagasse  *		dataset_len - lenth of buffer in which dataset is passed in.
3377f169c0eaSGlenn Lagasse  *		be_name - name of new BE name to update to.
3378f169c0eaSGlenn Lagasse  *		old_rc_loc - dataset under which the root container dataset
3379f169c0eaSGlenn Lagasse  *			for the old BE lives.
3380f169c0eaSGlenn Lagasse  *		new_rc_loc - dataset under which the root container dataset
3381f169c0eaSGlenn Lagasse  *			for the new BE lives.
3382f169c0eaSGlenn Lagasse  * Returns:
3383f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
3384f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
3385f169c0eaSGlenn Lagasse  * Scope:
3386f169c0eaSGlenn Lagasse  *		Private
3387f169c0eaSGlenn Lagasse  */
3388f169c0eaSGlenn Lagasse static int
3389f169c0eaSGlenn Lagasse update_dataset(char *dataset, int dataset_len, char *be_name,
3390f169c0eaSGlenn Lagasse     char *old_rc_loc, char *new_rc_loc)
3391f169c0eaSGlenn Lagasse {
3392f169c0eaSGlenn Lagasse 	char	*ds = NULL;
3393f169c0eaSGlenn Lagasse 	char	*sub_ds = NULL;
3394f169c0eaSGlenn Lagasse 
3395f169c0eaSGlenn Lagasse 	/* Tear off the BE container dataset */
3396f169c0eaSGlenn Lagasse 	if ((ds = be_make_name_from_ds(dataset, old_rc_loc)) == NULL) {
3397f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
3398f169c0eaSGlenn Lagasse 	}
3399f169c0eaSGlenn Lagasse 
3400f169c0eaSGlenn Lagasse 	/* Get dataset name relative to BE root, if there is one */
3401f169c0eaSGlenn Lagasse 	sub_ds = strchr(ds, '/');
3402f169c0eaSGlenn Lagasse 
3403f169c0eaSGlenn Lagasse 	/* Generate the BE root dataset name */
3404f169c0eaSGlenn Lagasse 	be_make_root_ds(new_rc_loc, be_name, dataset, dataset_len);
3405f169c0eaSGlenn Lagasse 
3406f169c0eaSGlenn Lagasse 	/* If a subordinate dataset name was found, append it */
3407f169c0eaSGlenn Lagasse 	if (sub_ds != NULL)
3408f169c0eaSGlenn Lagasse 		(void) strlcat(dataset, sub_ds, dataset_len);
3409f169c0eaSGlenn Lagasse 
3410f169c0eaSGlenn Lagasse 	free(ds);
3411f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
3412f169c0eaSGlenn Lagasse }
3413f169c0eaSGlenn Lagasse 
3414f169c0eaSGlenn Lagasse /*
3415f169c0eaSGlenn Lagasse  * Function:	_update_vfstab
3416f169c0eaSGlenn Lagasse  * Description:	This function updates a vfstab file to reflect the new
3417f169c0eaSGlenn Lagasse  *		root container dataset location and be_name for all
3418f169c0eaSGlenn Lagasse  *		entries listed in the be_fs_list_data_t structure passed in.
3419f169c0eaSGlenn Lagasse  * Parameters:
3420f169c0eaSGlenn Lagasse  *		vfstab - vfstab file to modify
3421f169c0eaSGlenn Lagasse  *		be_name - name of BE to update.
3422f169c0eaSGlenn Lagasse  *		old_rc_loc - dataset under which the root container dataset
3423f169c0eaSGlenn Lagasse  *			of the old BE resides in.
3424f169c0eaSGlenn Lagasse  *		new_rc_loc - dataset under which the root container dataset
3425f169c0eaSGlenn Lagasse  *			of the new BE resides in.
3426f169c0eaSGlenn Lagasse  *		fld - be_fs_list_data_t pointer providing the list of
3427f169c0eaSGlenn Lagasse  *			file systems to look for in vfstab.
3428f169c0eaSGlenn Lagasse  * Returns:
3429f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
3430f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
3431f169c0eaSGlenn Lagasse  * Scope:
3432f169c0eaSGlenn Lagasse  *		Private
3433f169c0eaSGlenn Lagasse  */
3434f169c0eaSGlenn Lagasse static int
3435f169c0eaSGlenn Lagasse _update_vfstab(char *vfstab, char *be_name, char *old_rc_loc,
3436f169c0eaSGlenn Lagasse     char *new_rc_loc, be_fs_list_data_t *fld)
3437f169c0eaSGlenn Lagasse {
3438f169c0eaSGlenn Lagasse 	struct vfstab	vp;
3439f169c0eaSGlenn Lagasse 	char		*tmp_vfstab = NULL;
3440f169c0eaSGlenn Lagasse 	char		comments_buf[BUFSIZ];
3441f169c0eaSGlenn Lagasse 	FILE		*comments = NULL;
3442f169c0eaSGlenn Lagasse 	FILE		*vfs_ents = NULL;
3443f169c0eaSGlenn Lagasse 	FILE		*tfile = NULL;
3444f169c0eaSGlenn Lagasse 	struct stat	sb;
3445f169c0eaSGlenn Lagasse 	char		dev[MAXPATHLEN];
3446f169c0eaSGlenn Lagasse 	char		*c;
3447f169c0eaSGlenn Lagasse 	int		fd;
3448f169c0eaSGlenn Lagasse 	int		ret = BE_SUCCESS, err = 0;
3449f169c0eaSGlenn Lagasse 	int		i;
3450f169c0eaSGlenn Lagasse 	int		tmp_vfstab_len = 0;
3451f169c0eaSGlenn Lagasse 
3452f169c0eaSGlenn Lagasse 	errno = 0;
3453f169c0eaSGlenn Lagasse 
3454f169c0eaSGlenn Lagasse 	/*
3455f169c0eaSGlenn Lagasse 	 * Open vfstab for reading twice.  First is for comments,
3456f169c0eaSGlenn Lagasse 	 * second is for actual entries.
3457f169c0eaSGlenn Lagasse 	 */
3458f169c0eaSGlenn Lagasse 	if ((comments = fopen(vfstab, "r")) == NULL ||
3459f169c0eaSGlenn Lagasse 	    (vfs_ents = fopen(vfstab, "r")) == NULL) {
3460f169c0eaSGlenn Lagasse 		err = errno;
3461f169c0eaSGlenn Lagasse 		be_print_err(gettext("_update_vfstab: "
3462f169c0eaSGlenn Lagasse 		    "failed to open vfstab (%s): %s\n"), vfstab,
3463f169c0eaSGlenn Lagasse 		    strerror(err));
3464f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
3465f169c0eaSGlenn Lagasse 		goto cleanup;
3466f169c0eaSGlenn Lagasse 	}
3467f169c0eaSGlenn Lagasse 
3468f169c0eaSGlenn Lagasse 	/* Grab the stats of the original vfstab file */
3469f169c0eaSGlenn Lagasse 	if (stat(vfstab, &sb) != 0) {
3470f169c0eaSGlenn Lagasse 		err = errno;
3471f169c0eaSGlenn Lagasse 		be_print_err(gettext("_update_vfstab: "
3472f169c0eaSGlenn Lagasse 		    "failed to stat file %s: %s\n"), vfstab,
3473f169c0eaSGlenn Lagasse 		    strerror(err));
3474f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
3475f169c0eaSGlenn Lagasse 		goto cleanup;
3476f169c0eaSGlenn Lagasse 	}
3477f169c0eaSGlenn Lagasse 
3478f169c0eaSGlenn Lagasse 	/* Create tmp file for modified vfstab */
3479f169c0eaSGlenn Lagasse 	if ((tmp_vfstab = (char *)malloc(strlen(vfstab) + 7))
3480f169c0eaSGlenn Lagasse 	    == NULL) {
3481f169c0eaSGlenn Lagasse 		be_print_err(gettext("_update_vfstab: "
3482f169c0eaSGlenn Lagasse 		    "malloc failed\n"));
3483f169c0eaSGlenn Lagasse 		ret = BE_ERR_NOMEM;
3484f169c0eaSGlenn Lagasse 		goto cleanup;
3485f169c0eaSGlenn Lagasse 	}
3486f169c0eaSGlenn Lagasse 	tmp_vfstab_len = strlen(vfstab) + 7;
3487f169c0eaSGlenn Lagasse 	(void) memset(tmp_vfstab, 0, tmp_vfstab_len);
3488f169c0eaSGlenn Lagasse 	(void) strlcpy(tmp_vfstab, vfstab, tmp_vfstab_len);
3489f169c0eaSGlenn Lagasse 	(void) strlcat(tmp_vfstab, "XXXXXX", tmp_vfstab_len);
3490f169c0eaSGlenn Lagasse 	if ((fd = mkstemp(tmp_vfstab)) == -1) {
3491f169c0eaSGlenn Lagasse 		err = errno;
3492f169c0eaSGlenn Lagasse 		be_print_err(gettext("_update_vfstab: "
3493f169c0eaSGlenn Lagasse 		    "mkstemp failed: %s\n"), strerror(err));
3494f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
3495f169c0eaSGlenn Lagasse 		goto cleanup;
3496f169c0eaSGlenn Lagasse 	}
3497f169c0eaSGlenn Lagasse 	if ((tfile = fdopen(fd, "w")) == NULL) {
3498f169c0eaSGlenn Lagasse 		err = errno;
3499f169c0eaSGlenn Lagasse 		be_print_err(gettext("_update_vfstab: "
3500f169c0eaSGlenn Lagasse 		    "could not open file for write\n"));
3501f169c0eaSGlenn Lagasse 		(void) close(fd);
3502f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
3503f169c0eaSGlenn Lagasse 		goto cleanup;
3504f169c0eaSGlenn Lagasse 	}
3505f169c0eaSGlenn Lagasse 
3506f169c0eaSGlenn Lagasse 	while (fgets(comments_buf, BUFSIZ, comments)) {
3507f169c0eaSGlenn Lagasse 		for (c = comments_buf; *c != '\0' && isspace(*c); c++)
3508f169c0eaSGlenn Lagasse 			;
3509f169c0eaSGlenn Lagasse 		if (*c == '\0') {
3510f169c0eaSGlenn Lagasse 			continue;
3511f169c0eaSGlenn Lagasse 		} else if (*c == '#') {
3512f169c0eaSGlenn Lagasse 			/*
3513f169c0eaSGlenn Lagasse 			 * If line is a comment line, just put
3514f169c0eaSGlenn Lagasse 			 * it through to the tmp vfstab.
3515f169c0eaSGlenn Lagasse 			 */
3516f169c0eaSGlenn Lagasse 			(void) fputs(comments_buf, tfile);
3517f169c0eaSGlenn Lagasse 		} else {
3518f169c0eaSGlenn Lagasse 			/*
3519f169c0eaSGlenn Lagasse 			 * Else line is a vfstab entry, grab it
3520f169c0eaSGlenn Lagasse 			 * into a vfstab struct.
3521f169c0eaSGlenn Lagasse 			 */
3522f169c0eaSGlenn Lagasse 			if (getvfsent(vfs_ents, &vp) != 0) {
3523f169c0eaSGlenn Lagasse 				err = errno;
3524f169c0eaSGlenn Lagasse 				be_print_err(gettext("_update_vfstab: "
3525f169c0eaSGlenn Lagasse 				    "getvfsent failed: %s\n"), strerror(err));
3526f169c0eaSGlenn Lagasse 				ret = errno_to_be_err(err);
3527f169c0eaSGlenn Lagasse 				goto cleanup;
3528f169c0eaSGlenn Lagasse 			}
3529f169c0eaSGlenn Lagasse 
3530f169c0eaSGlenn Lagasse 			if (vp.vfs_special == NULL || vp.vfs_mountp == NULL) {
3531f169c0eaSGlenn Lagasse 				(void) putvfsent(tfile, &vp);
3532f169c0eaSGlenn Lagasse 				continue;
3533f169c0eaSGlenn Lagasse 			}
3534f169c0eaSGlenn Lagasse 
3535f169c0eaSGlenn Lagasse 			/*
3536f169c0eaSGlenn Lagasse 			 * If the entry is one of the entries in the list
3537f169c0eaSGlenn Lagasse 			 * of file systems to update, modify it's device
3538f169c0eaSGlenn Lagasse 			 * field to be correct for this BE.
3539f169c0eaSGlenn Lagasse 			 */
3540f169c0eaSGlenn Lagasse 			for (i = 0; i < fld->fs_num; i++) {
3541f169c0eaSGlenn Lagasse 				if (strcmp(vp.vfs_special, fld->fs_list[i])
3542f169c0eaSGlenn Lagasse 				    == 0) {
3543f169c0eaSGlenn Lagasse 					/*
3544f169c0eaSGlenn Lagasse 					 * Found entry that needs an update.
3545f169c0eaSGlenn Lagasse 					 * Replace the root container dataset
3546f169c0eaSGlenn Lagasse 					 * location and be_name in the
3547f169c0eaSGlenn Lagasse 					 * entry's device.
3548f169c0eaSGlenn Lagasse 					 */
3549f169c0eaSGlenn Lagasse 					(void) strlcpy(dev, vp.vfs_special,
3550f169c0eaSGlenn Lagasse 					    sizeof (dev));
3551f169c0eaSGlenn Lagasse 
3552f169c0eaSGlenn Lagasse 					if ((ret = update_dataset(dev,
3553f169c0eaSGlenn Lagasse 					    sizeof (dev), be_name, old_rc_loc,
3554f169c0eaSGlenn Lagasse 					    new_rc_loc)) != 0) {
3555f169c0eaSGlenn Lagasse 						be_print_err(
3556f169c0eaSGlenn Lagasse 						    gettext("_update_vfstab: "
3557f169c0eaSGlenn Lagasse 						    "Failed to update device "
3558f169c0eaSGlenn Lagasse 						    "field for vfstab entry "
3559f169c0eaSGlenn Lagasse 						    "%s\n"), fld->fs_list[i]);
3560f169c0eaSGlenn Lagasse 						goto cleanup;
3561f169c0eaSGlenn Lagasse 					}
3562f169c0eaSGlenn Lagasse 
3563f169c0eaSGlenn Lagasse 					vp.vfs_special = dev;
3564f169c0eaSGlenn Lagasse 					break;
3565f169c0eaSGlenn Lagasse 				}
3566f169c0eaSGlenn Lagasse 			}
3567f169c0eaSGlenn Lagasse 
3568f169c0eaSGlenn Lagasse 			/* Put entry through to tmp vfstab */
3569f169c0eaSGlenn Lagasse 			(void) putvfsent(tfile, &vp);
3570f169c0eaSGlenn Lagasse 		}
3571f169c0eaSGlenn Lagasse 	}
3572f169c0eaSGlenn Lagasse 
3573f169c0eaSGlenn Lagasse 	(void) fclose(comments);
3574f169c0eaSGlenn Lagasse 	comments = NULL;
3575f169c0eaSGlenn Lagasse 	(void) fclose(vfs_ents);
3576f169c0eaSGlenn Lagasse 	vfs_ents = NULL;
3577f169c0eaSGlenn Lagasse 	(void) fclose(tfile);
3578f169c0eaSGlenn Lagasse 	tfile = NULL;
3579f169c0eaSGlenn Lagasse 
3580f169c0eaSGlenn Lagasse 	/* Copy tmp vfstab into place */
3581f169c0eaSGlenn Lagasse 	if (rename(tmp_vfstab, vfstab) != 0) {
3582f169c0eaSGlenn Lagasse 		err = errno;
3583f169c0eaSGlenn Lagasse 		be_print_err(gettext("_update_vfstab: "
3584f169c0eaSGlenn Lagasse 		    "failed to rename file %s to %s: %s\n"), tmp_vfstab,
3585f169c0eaSGlenn Lagasse 		    vfstab, strerror(err));
3586f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
3587f169c0eaSGlenn Lagasse 		goto cleanup;
3588f169c0eaSGlenn Lagasse 	}
3589f169c0eaSGlenn Lagasse 
3590f169c0eaSGlenn Lagasse 	/* Set the perms and ownership of the updated file */
3591f169c0eaSGlenn Lagasse 	if (chmod(vfstab, sb.st_mode) != 0) {
3592f169c0eaSGlenn Lagasse 		err = errno;
3593f169c0eaSGlenn Lagasse 		be_print_err(gettext("_update_vfstab: "
3594f169c0eaSGlenn Lagasse 		    "failed to chmod %s: %s\n"), vfstab, strerror(err));
3595f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
3596f169c0eaSGlenn Lagasse 		goto cleanup;
3597f169c0eaSGlenn Lagasse 	}
3598f169c0eaSGlenn Lagasse 	if (chown(vfstab, sb.st_uid, sb.st_gid) != 0) {
3599f169c0eaSGlenn Lagasse 		err = errno;
3600f169c0eaSGlenn Lagasse 		be_print_err(gettext("_update_vfstab: "
3601f169c0eaSGlenn Lagasse 		    "failed to chown %s: %s\n"), vfstab, strerror(err));
3602f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
3603f169c0eaSGlenn Lagasse 		goto cleanup;
3604f169c0eaSGlenn Lagasse 	}
3605f169c0eaSGlenn Lagasse 
3606f169c0eaSGlenn Lagasse cleanup:
3607f169c0eaSGlenn Lagasse 	if (comments != NULL)
3608f169c0eaSGlenn Lagasse 		(void) fclose(comments);
3609f169c0eaSGlenn Lagasse 	if (vfs_ents != NULL)
3610f169c0eaSGlenn Lagasse 		(void) fclose(vfs_ents);
3611f169c0eaSGlenn Lagasse 	(void) unlink(tmp_vfstab);
3612f169c0eaSGlenn Lagasse 	(void) free(tmp_vfstab);
3613f169c0eaSGlenn Lagasse 	if (tfile != NULL)
3614f169c0eaSGlenn Lagasse 		(void) fclose(tfile);
3615f169c0eaSGlenn Lagasse 
3616f169c0eaSGlenn Lagasse 	return (ret);
3617f169c0eaSGlenn Lagasse }
3618f169c0eaSGlenn Lagasse 
3619f169c0eaSGlenn Lagasse 
3620f169c0eaSGlenn Lagasse /*
3621f169c0eaSGlenn Lagasse  * Function:	be_get_auto_name
3622f169c0eaSGlenn Lagasse  * Description:	Generate an auto name constructed based on the BE name
3623f169c0eaSGlenn Lagasse  *		of the original BE or zone BE being cloned.
3624f169c0eaSGlenn Lagasse  * Parameters:
3625f169c0eaSGlenn Lagasse  *		obe_name - name of the original BE or zone BE being cloned.
3626f169c0eaSGlenn Lagasse  *              container_ds - container dataset for the zone.
3627f169c0eaSGlenn Lagasse  *                             Note: if zone_be is false this should be
3628f169c0eaSGlenn Lagasse  *                                  NULL.
3629f169c0eaSGlenn Lagasse  *		zone_be - flag that indicates if we are operating on a zone BE.
3630f169c0eaSGlenn Lagasse  * Returns:
3631f169c0eaSGlenn Lagasse  *		Success - pointer to auto generated BE name.  The name
3632f169c0eaSGlenn Lagasse  *			is allocated in heap storage so the caller is
3633f169c0eaSGlenn Lagasse  *			responsible for free'ing the name.
3634f169c0eaSGlenn Lagasse  *		Failure - NULL
3635f169c0eaSGlenn Lagasse  * Scope:
3636f169c0eaSGlenn Lagasse  *		Private
3637f169c0eaSGlenn Lagasse  */
3638f169c0eaSGlenn Lagasse static char *
3639f169c0eaSGlenn Lagasse be_get_auto_name(char *obe_name, char *be_container_ds, boolean_t zone_be)
3640f169c0eaSGlenn Lagasse {
3641f169c0eaSGlenn Lagasse 	be_node_list_t	*be_nodes = NULL;
3642f169c0eaSGlenn Lagasse 	be_node_list_t	*cur_be = NULL;
3643f169c0eaSGlenn Lagasse 	char		auto_be_name[MAXPATHLEN];
3644f169c0eaSGlenn Lagasse 	char		base_be_name[MAXPATHLEN];
3645f169c0eaSGlenn Lagasse 	char		cur_be_name[MAXPATHLEN];
3646f169c0eaSGlenn Lagasse 	char		*num_str = NULL;
3647f169c0eaSGlenn Lagasse 	char		*c = NULL;
3648f169c0eaSGlenn Lagasse 	int		num = 0;
3649f169c0eaSGlenn Lagasse 	int		cur_num = 0;
3650f169c0eaSGlenn Lagasse 
3651f169c0eaSGlenn Lagasse 	errno = 0;
3652f169c0eaSGlenn Lagasse 
3653f169c0eaSGlenn Lagasse 	/*
3654f169c0eaSGlenn Lagasse 	 * Check if obe_name is already in an auto BE name format.
3655f169c0eaSGlenn Lagasse 	 * If it is, then strip off the increment number to get the
3656f169c0eaSGlenn Lagasse 	 * base name.
3657f169c0eaSGlenn Lagasse 	 */
3658f169c0eaSGlenn Lagasse 	(void) strlcpy(base_be_name, obe_name, sizeof (base_be_name));
3659f169c0eaSGlenn Lagasse 
3660f169c0eaSGlenn Lagasse 	if ((num_str = strrchr(base_be_name, BE_AUTO_NAME_DELIM))
3661f169c0eaSGlenn Lagasse 	    != NULL) {
3662f169c0eaSGlenn Lagasse 		/* Make sure remaining string is all digits */
3663f169c0eaSGlenn Lagasse 		c = num_str + 1;
3664f169c0eaSGlenn Lagasse 		while (c[0] != '\0' && isdigit(c[0]))
3665f169c0eaSGlenn Lagasse 			c++;
3666f169c0eaSGlenn Lagasse 		/*
3667f169c0eaSGlenn Lagasse 		 * If we're now at the end of the string strip off the
3668f169c0eaSGlenn Lagasse 		 * increment number.
3669f169c0eaSGlenn Lagasse 		 */
3670f169c0eaSGlenn Lagasse 		if (c[0] == '\0')
3671f169c0eaSGlenn Lagasse 			num_str[0] = '\0';
3672f169c0eaSGlenn Lagasse 	}
3673f169c0eaSGlenn Lagasse 
3674f169c0eaSGlenn Lagasse 	if (zone_be) {
3675f169c0eaSGlenn Lagasse 		if (be_container_ds == NULL)
3676f169c0eaSGlenn Lagasse 			return (NULL);
3677f169c0eaSGlenn Lagasse 		if (be_get_zone_be_list(obe_name, be_container_ds,
3678f169c0eaSGlenn Lagasse 		    &be_nodes) != BE_SUCCESS) {
3679f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_auto_name: "
3680f169c0eaSGlenn Lagasse 			    "be_get_zone_be_list failed\n"));
3681f169c0eaSGlenn Lagasse 			return (NULL);
3682f169c0eaSGlenn Lagasse 		}
3683*a897f28bSAndy Fiddaman 	} else if (_be_list(NULL, &be_nodes, BE_LIST_DEFAULT) != BE_SUCCESS) {
3684f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_auto_name: be_list failed\n"));
3685f169c0eaSGlenn Lagasse 		return (NULL);
3686f169c0eaSGlenn Lagasse 	}
3687f169c0eaSGlenn Lagasse 
3688f169c0eaSGlenn Lagasse 	for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
3689f169c0eaSGlenn Lagasse 		(void) strlcpy(cur_be_name, cur_be->be_node_name,
3690f169c0eaSGlenn Lagasse 		    sizeof (cur_be_name));
3691f169c0eaSGlenn Lagasse 
3692f169c0eaSGlenn Lagasse 		/* If cur_be_name doesn't match at least base be name, skip. */
3693f169c0eaSGlenn Lagasse 		if (strncmp(cur_be_name, base_be_name, strlen(base_be_name))
3694f169c0eaSGlenn Lagasse 		    != 0)
3695f169c0eaSGlenn Lagasse 			continue;
3696f169c0eaSGlenn Lagasse 
3697f169c0eaSGlenn Lagasse 		/* Get the string following the base be name */
3698f169c0eaSGlenn Lagasse 		num_str = cur_be_name + strlen(base_be_name);
3699f169c0eaSGlenn Lagasse 
3700f169c0eaSGlenn Lagasse 		/*
3701f169c0eaSGlenn Lagasse 		 * If nothing follows the base be name, this cur_be_name
3702f169c0eaSGlenn Lagasse 		 * is the BE named with the base be name, skip.
3703f169c0eaSGlenn Lagasse 		 */
3704f169c0eaSGlenn Lagasse 		if (num_str == NULL || num_str[0] == '\0')
3705f169c0eaSGlenn Lagasse 			continue;
3706f169c0eaSGlenn Lagasse 
3707f169c0eaSGlenn Lagasse 		/*
3708f169c0eaSGlenn Lagasse 		 * Remove the name delimiter.  If its not there,
3709f169c0eaSGlenn Lagasse 		 * cur_be_name isn't part of this BE name stream, skip.
3710f169c0eaSGlenn Lagasse 		 */
3711f169c0eaSGlenn Lagasse 		if (num_str[0] == BE_AUTO_NAME_DELIM)
3712f169c0eaSGlenn Lagasse 			num_str++;
3713f169c0eaSGlenn Lagasse 		else
3714f169c0eaSGlenn Lagasse 			continue;
3715f169c0eaSGlenn Lagasse 
3716f169c0eaSGlenn Lagasse 		/* Make sure remaining string is all digits */
3717f169c0eaSGlenn Lagasse 		c = num_str;
3718f169c0eaSGlenn Lagasse 		while (c[0] != '\0' && isdigit(c[0]))
3719f169c0eaSGlenn Lagasse 			c++;
3720f169c0eaSGlenn Lagasse 		if (c[0] != '\0')
3721f169c0eaSGlenn Lagasse 			continue;
3722f169c0eaSGlenn Lagasse 
3723f169c0eaSGlenn Lagasse 		/* Convert the number string to an int */
3724f169c0eaSGlenn Lagasse 		cur_num = atoi(num_str);
3725f169c0eaSGlenn Lagasse 
3726f169c0eaSGlenn Lagasse 		/*
3727f169c0eaSGlenn Lagasse 		 * If failed to convert the string, skip it.  If its too
3728f169c0eaSGlenn Lagasse 		 * long to be converted to an int, we wouldn't auto generate
3729f169c0eaSGlenn Lagasse 		 * this number anyway so there couldn't be a conflict.
3730f169c0eaSGlenn Lagasse 		 * We treat it as a manually created BE name.
3731f169c0eaSGlenn Lagasse 		 */
3732f169c0eaSGlenn Lagasse 		if (cur_num == 0 && errno == EINVAL)
3733f169c0eaSGlenn Lagasse 			continue;
3734f169c0eaSGlenn Lagasse 
3735f169c0eaSGlenn Lagasse 		/*
3736f169c0eaSGlenn Lagasse 		 * Compare current number to current max number,
3737f169c0eaSGlenn Lagasse 		 * take higher of the two.
3738f169c0eaSGlenn Lagasse 		 */
3739f169c0eaSGlenn Lagasse 		if (cur_num > num)
3740f169c0eaSGlenn Lagasse 			num = cur_num;
3741f169c0eaSGlenn Lagasse 	}
3742f169c0eaSGlenn Lagasse 
3743f169c0eaSGlenn Lagasse 	/*
3744f169c0eaSGlenn Lagasse 	 * Store off a copy of 'num' incase we need it later.  If incrementing
3745f169c0eaSGlenn Lagasse 	 * 'num' causes it to roll over, this means 'num' is the largest
3746f169c0eaSGlenn Lagasse 	 * positive int possible; we'll need it later in the loop to determine
3747f169c0eaSGlenn Lagasse 	 * if we've exhausted all possible increment numbers.  We store it in
3748f169c0eaSGlenn Lagasse 	 * 'cur_num'.
3749f169c0eaSGlenn Lagasse 	 */
3750f169c0eaSGlenn Lagasse 	cur_num = num;
3751f169c0eaSGlenn Lagasse 
3752f169c0eaSGlenn Lagasse 	/* Increment 'num' to get new auto BE name number */
3753f169c0eaSGlenn Lagasse 	if (++num <= 0) {
3754f169c0eaSGlenn Lagasse 		int ret = 0;
3755f169c0eaSGlenn Lagasse 
3756f169c0eaSGlenn Lagasse 		/*
3757f169c0eaSGlenn Lagasse 		 * Since incrementing 'num' caused it to rollover, start
3758f169c0eaSGlenn Lagasse 		 * over at 0 and find the first available number.
3759f169c0eaSGlenn Lagasse 		 */
3760f169c0eaSGlenn Lagasse 		for (num = 0; num < cur_num; num++) {
3761f169c0eaSGlenn Lagasse 
3762f169c0eaSGlenn Lagasse 			(void) snprintf(cur_be_name, sizeof (cur_be_name),
3763f169c0eaSGlenn Lagasse 			    "%s%c%d", base_be_name, BE_AUTO_NAME_DELIM, num);
3764f169c0eaSGlenn Lagasse 
3765f169c0eaSGlenn Lagasse 			ret = zpool_iter(g_zfs, be_exists_callback,
3766f169c0eaSGlenn Lagasse 			    cur_be_name);
3767f169c0eaSGlenn Lagasse 
3768f169c0eaSGlenn Lagasse 			if (ret == 0) {
3769f169c0eaSGlenn Lagasse 				/*
3770f169c0eaSGlenn Lagasse 				 * BE name doesn't exist, break out
3771f169c0eaSGlenn Lagasse 				 * to use 'num'.
3772f169c0eaSGlenn Lagasse 				 */
3773f169c0eaSGlenn Lagasse 				break;
3774f169c0eaSGlenn Lagasse 			} else if (ret == 1) {
3775f169c0eaSGlenn Lagasse 				/* BE name exists, continue looking */
3776f169c0eaSGlenn Lagasse 				continue;
3777f169c0eaSGlenn Lagasse 			} else {
3778f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_get_auto_name: "
3779f169c0eaSGlenn Lagasse 				    "zpool_iter failed: %s\n"),
3780f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
3781f169c0eaSGlenn Lagasse 				be_free_list(be_nodes);
3782f169c0eaSGlenn Lagasse 				return (NULL);
3783f169c0eaSGlenn Lagasse 			}
3784f169c0eaSGlenn Lagasse 		}
3785f169c0eaSGlenn Lagasse 
3786f169c0eaSGlenn Lagasse 		/*
3787f169c0eaSGlenn Lagasse 		 * If 'num' equals 'cur_num', we've exhausted all possible
3788f169c0eaSGlenn Lagasse 		 * auto BE names for this base BE name.
3789f169c0eaSGlenn Lagasse 		 */
3790f169c0eaSGlenn Lagasse 		if (num == cur_num) {
3791f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_auto_name: "
3792f169c0eaSGlenn Lagasse 			    "No more available auto BE names for base "
3793f169c0eaSGlenn Lagasse 			    "BE name %s\n"), base_be_name);
3794f169c0eaSGlenn Lagasse 			be_free_list(be_nodes);
3795f169c0eaSGlenn Lagasse 			return (NULL);
3796f169c0eaSGlenn Lagasse 		}
3797f169c0eaSGlenn Lagasse 	}
3798f169c0eaSGlenn Lagasse 
3799f169c0eaSGlenn Lagasse 	be_free_list(be_nodes);
3800f169c0eaSGlenn Lagasse 
3801f169c0eaSGlenn Lagasse 	/*
3802f169c0eaSGlenn Lagasse 	 * Generate string for auto BE name.
3803f169c0eaSGlenn Lagasse 	 */
3804f169c0eaSGlenn Lagasse 	(void) snprintf(auto_be_name, sizeof (auto_be_name), "%s%c%d",
3805f169c0eaSGlenn Lagasse 	    base_be_name, BE_AUTO_NAME_DELIM, num);
3806f169c0eaSGlenn Lagasse 
3807f169c0eaSGlenn Lagasse 	if ((c = strdup(auto_be_name)) == NULL) {
3808f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_auto_name: "
3809f169c0eaSGlenn Lagasse 		    "memory allocation failed\n"));
3810f169c0eaSGlenn Lagasse 		return (NULL);
3811f169c0eaSGlenn Lagasse 	}
3812f169c0eaSGlenn Lagasse 
3813f169c0eaSGlenn Lagasse 	return (c);
3814f169c0eaSGlenn Lagasse }
3815f169c0eaSGlenn Lagasse 
38166b1d07a4SAlexander Eremin /*
38176b1d07a4SAlexander Eremin  * Function:	be_get_console_prop
38186b1d07a4SAlexander Eremin  * Description:	Determine console device.
38196b1d07a4SAlexander Eremin  * Returns:
38206b1d07a4SAlexander Eremin  *		Success - pointer to console setting.
38216b1d07a4SAlexander Eremin  *		Failure - NULL
38226b1d07a4SAlexander Eremin  * Scope:
38236b1d07a4SAlexander Eremin  *		Private
38246b1d07a4SAlexander Eremin  */
38256b1d07a4SAlexander Eremin static char *
38266b1d07a4SAlexander Eremin be_get_console_prop(void)
38276b1d07a4SAlexander Eremin {
38286b1d07a4SAlexander Eremin 	di_node_t	dn;
38296b1d07a4SAlexander Eremin 	char *console = NULL;
38306b1d07a4SAlexander Eremin 
38316b1d07a4SAlexander Eremin 	if ((dn = di_init("/", DINFOPROP)) == DI_NODE_NIL) {
38326b1d07a4SAlexander Eremin 		be_print_err(gettext("be_get_console_prop: "
38336b1d07a4SAlexander Eremin 		    "di_init() failed\n"));
38346b1d07a4SAlexander Eremin 		return (NULL);
38356b1d07a4SAlexander Eremin 	}
38366b1d07a4SAlexander Eremin 
38376b1d07a4SAlexander Eremin 	if (di_prop_lookup_strings(DDI_DEV_T_ANY, dn,
38386b1d07a4SAlexander Eremin 	    "console", &console) != -1) {
38396b1d07a4SAlexander Eremin 		di_fini(dn);
38406b1d07a4SAlexander Eremin 		return (console);
38416b1d07a4SAlexander Eremin 	}
38426b1d07a4SAlexander Eremin 
38436b1d07a4SAlexander Eremin 	if (console == NULL) {
38446b1d07a4SAlexander Eremin 		if (di_prop_lookup_strings(DDI_DEV_T_ANY, dn,
38456b1d07a4SAlexander Eremin 		    "output-device", &console) != -1) {
38466b1d07a4SAlexander Eremin 			di_fini(dn);
38476b1d07a4SAlexander Eremin 			if (strncmp(console, "screen", strlen("screen")) == 0)
38486b1d07a4SAlexander Eremin 				console = BE_DEFAULT_CONSOLE;
38496b1d07a4SAlexander Eremin 		}
38506b1d07a4SAlexander Eremin 	}
38516b1d07a4SAlexander Eremin 
38526b1d07a4SAlexander Eremin 	/*
38536b1d07a4SAlexander Eremin 	 * Default console to text
38546b1d07a4SAlexander Eremin 	 */
38556b1d07a4SAlexander Eremin 	if (console == NULL) {
38566b1d07a4SAlexander Eremin 		console = BE_DEFAULT_CONSOLE;
38576b1d07a4SAlexander Eremin 	}
38586b1d07a4SAlexander Eremin 
38596b1d07a4SAlexander Eremin 	return (console);
38606b1d07a4SAlexander Eremin }
38616b1d07a4SAlexander Eremin 
3862f169c0eaSGlenn Lagasse /*
3863f169c0eaSGlenn Lagasse  * Function:	be_create_menu
3864f169c0eaSGlenn Lagasse  * Description:
3865f169c0eaSGlenn Lagasse  *		This function is used if no menu.lst file exists. In
3866f169c0eaSGlenn Lagasse  *		this case a new file is created and if needed default
3867f169c0eaSGlenn Lagasse  *		lines are added to the file.
3868f169c0eaSGlenn Lagasse  * Parameters:
3869f169c0eaSGlenn Lagasse  *		pool - The name of the pool the menu.lst file is on
3870f169c0eaSGlenn Lagasse  *		menu_file - The name of the file we're creating.
3871f169c0eaSGlenn Lagasse  *		menu_fp - A pointer to the file pointer of the file we
3872f169c0eaSGlenn Lagasse  *			  created. This is also used to pass back the file
3873f169c0eaSGlenn Lagasse  *			  pointer to the newly created file.
3874f169c0eaSGlenn Lagasse  *		mode - the original mode used for the failed attempt to
3875f169c0eaSGlenn Lagasse  *		       non-existent file.
3876f169c0eaSGlenn Lagasse  * Returns:
3877f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
3878f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
3879f169c0eaSGlenn Lagasse  * Scope:
3880f169c0eaSGlenn Lagasse  *		Private
3881f169c0eaSGlenn Lagasse  */
3882f169c0eaSGlenn Lagasse static int
3883f169c0eaSGlenn Lagasse be_create_menu(
3884f169c0eaSGlenn Lagasse 	char *pool,
3885f169c0eaSGlenn Lagasse 	char *menu_file,
3886f169c0eaSGlenn Lagasse 	FILE **menu_fp,
3887f169c0eaSGlenn Lagasse 	char *mode)
3888f169c0eaSGlenn Lagasse {
3889f169c0eaSGlenn Lagasse 	be_node_list_t	*be_nodes = NULL;
3890f169c0eaSGlenn Lagasse 	char *menu_path = NULL;
3891f169c0eaSGlenn Lagasse 	char *be_rpool = NULL;
3892f169c0eaSGlenn Lagasse 	char *be_name = NULL;
38936b1d07a4SAlexander Eremin 	char *console = NULL;
3894f169c0eaSGlenn Lagasse 	errno = 0;
3895f169c0eaSGlenn Lagasse 
3896f169c0eaSGlenn Lagasse 	if (menu_file == NULL || menu_fp == NULL || mode == NULL)
3897f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
3898f169c0eaSGlenn Lagasse 
3899f169c0eaSGlenn Lagasse 	menu_path = strdup(menu_file);
3900f169c0eaSGlenn Lagasse 	if (menu_path == NULL)
3901f169c0eaSGlenn Lagasse 		return (BE_ERR_NOMEM);
3902f169c0eaSGlenn Lagasse 
3903f169c0eaSGlenn Lagasse 	(void) dirname(menu_path);
3904f169c0eaSGlenn Lagasse 	if (*menu_path == '.') {
3905f169c0eaSGlenn Lagasse 		free(menu_path);
3906f169c0eaSGlenn Lagasse 		return (BE_ERR_BAD_MENU_PATH);
3907f169c0eaSGlenn Lagasse 	}
3908f169c0eaSGlenn Lagasse 	if (mkdirp(menu_path,
3909f169c0eaSGlenn Lagasse 	    S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
3910f169c0eaSGlenn Lagasse 	    errno != EEXIST) {
3911f169c0eaSGlenn Lagasse 		free(menu_path);
3912f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_create_menu: Failed to create the %s "
3913f169c0eaSGlenn Lagasse 		    "directory: %s\n"), menu_path, strerror(errno));
3914f169c0eaSGlenn Lagasse 		return (errno_to_be_err(errno));
3915f169c0eaSGlenn Lagasse 	}
3916f169c0eaSGlenn Lagasse 	free(menu_path);
3917f169c0eaSGlenn Lagasse 
3918f169c0eaSGlenn Lagasse 	/*
3919f169c0eaSGlenn Lagasse 	 * Check to see if this system supports grub
3920f169c0eaSGlenn Lagasse 	 */
3921f169c0eaSGlenn Lagasse 	if (be_has_grub()) {
3922f169c0eaSGlenn Lagasse 		/*
3923f169c0eaSGlenn Lagasse 		 * The grub menu is missing so we need to create it
3924f169c0eaSGlenn Lagasse 		 * and fill in the first few lines.
3925f169c0eaSGlenn Lagasse 		 */
39266b1d07a4SAlexander Eremin 		FILE *temp_fp = fopen(menu_file, "a+");
39276b1d07a4SAlexander Eremin 		if (temp_fp == NULL) {
39286b1d07a4SAlexander Eremin 			*menu_fp = NULL;
39296b1d07a4SAlexander Eremin 			return (errno_to_be_err(errno));
3930f169c0eaSGlenn Lagasse 		}
39316b1d07a4SAlexander Eremin 
39326b1d07a4SAlexander Eremin 		if ((console = be_get_console_prop()) != NULL) {
39336b1d07a4SAlexander Eremin 
39346b1d07a4SAlexander Eremin 			/*
39356b1d07a4SAlexander Eremin 			 * If console is redirected to serial line,
39366b1d07a4SAlexander Eremin 			 * GRUB splash screen will not be enabled.
39376b1d07a4SAlexander Eremin 			 */
39386b1d07a4SAlexander Eremin 			if (strncmp(console, "text", strlen("text")) == 0 ||
39396b1d07a4SAlexander Eremin 			    strncmp(console, "graphics",
39406b1d07a4SAlexander Eremin 			    strlen("graphics")) == 0) {
39416b1d07a4SAlexander Eremin 
39426b1d07a4SAlexander Eremin 				(void) fprintf(temp_fp, "%s\n", BE_GRUB_SPLASH);
39436b1d07a4SAlexander Eremin 				(void) fprintf(temp_fp, "%s\n",
39446b1d07a4SAlexander Eremin 				    BE_GRUB_FOREGROUND);
39456b1d07a4SAlexander Eremin 				(void) fprintf(temp_fp, "%s\n",
39466b1d07a4SAlexander Eremin 				    BE_GRUB_BACKGROUND);
39476b1d07a4SAlexander Eremin 				(void) fprintf(temp_fp, "%s\n",
39486b1d07a4SAlexander Eremin 				    BE_GRUB_DEFAULT);
39496b1d07a4SAlexander Eremin 			} else {
39506b1d07a4SAlexander Eremin 				be_print_err(gettext("be_create_menu: "
39516b1d07a4SAlexander Eremin 				    "console on serial line, "
39526b1d07a4SAlexander Eremin 				    "GRUB splash image will be disabled\n"));
39536b1d07a4SAlexander Eremin 			}
39546b1d07a4SAlexander Eremin 		}
39556b1d07a4SAlexander Eremin 
39566b1d07a4SAlexander Eremin 		(void) fprintf(temp_fp,	"timeout 30\n");
39576b1d07a4SAlexander Eremin 		(void) fclose(temp_fp);
39586b1d07a4SAlexander Eremin 
3959f169c0eaSGlenn Lagasse 	} else {
3960f169c0eaSGlenn Lagasse 		/*
3961f169c0eaSGlenn Lagasse 		 * The menu file doesn't exist so we need to create a
3962f169c0eaSGlenn Lagasse 		 * blank file.
3963f169c0eaSGlenn Lagasse 		 */
3964f169c0eaSGlenn Lagasse 		FILE *temp_fp = fopen(menu_file, "w+");
3965f169c0eaSGlenn Lagasse 		if (temp_fp == NULL) {
3966f169c0eaSGlenn Lagasse 			*menu_fp = NULL;
3967f169c0eaSGlenn Lagasse 			return (errno_to_be_err(errno));
3968f169c0eaSGlenn Lagasse 		}
3969f169c0eaSGlenn Lagasse 		(void) fclose(temp_fp);
3970f169c0eaSGlenn Lagasse 	}
3971f169c0eaSGlenn Lagasse 
3972f169c0eaSGlenn Lagasse 	/*
3973f169c0eaSGlenn Lagasse 	 * Now we need to add all the BE's back into the the file.
3974f169c0eaSGlenn Lagasse 	 */
3975*a897f28bSAndy Fiddaman 	if (_be_list(NULL, &be_nodes, BE_LIST_DEFAULT) == BE_SUCCESS) {
3976f169c0eaSGlenn Lagasse 		while (be_nodes != NULL) {
3977f169c0eaSGlenn Lagasse 			if (strcmp(pool, be_nodes->be_rpool) == 0) {
3978f169c0eaSGlenn Lagasse 				(void) be_append_menu(be_nodes->be_node_name,
3979f169c0eaSGlenn Lagasse 				    be_nodes->be_rpool, NULL, NULL, NULL);
3980f169c0eaSGlenn Lagasse 			}
3981f169c0eaSGlenn Lagasse 			if (be_nodes->be_active_on_boot) {
3982f169c0eaSGlenn Lagasse 				be_rpool = strdup(be_nodes->be_rpool);
3983f169c0eaSGlenn Lagasse 				be_name = strdup(be_nodes->be_node_name);
3984f169c0eaSGlenn Lagasse 			}
3985f169c0eaSGlenn Lagasse 
3986f169c0eaSGlenn Lagasse 			be_nodes = be_nodes->be_next_node;
3987f169c0eaSGlenn Lagasse 		}
3988f169c0eaSGlenn Lagasse 	}
3989f169c0eaSGlenn Lagasse 	be_free_list(be_nodes);
3990f169c0eaSGlenn Lagasse 
3991f169c0eaSGlenn Lagasse 	/*
3992f169c0eaSGlenn Lagasse 	 * Check to see if this system supports grub
3993f169c0eaSGlenn Lagasse 	 */
3994f169c0eaSGlenn Lagasse 	if (be_has_grub()) {
3995f169c0eaSGlenn Lagasse 		int err = be_change_grub_default(be_name, be_rpool);
3996f169c0eaSGlenn Lagasse 		if (err != BE_SUCCESS)
3997f169c0eaSGlenn Lagasse 			return (err);
3998f169c0eaSGlenn Lagasse 	}
3999f169c0eaSGlenn Lagasse 	*menu_fp = fopen(menu_file, mode);
4000f169c0eaSGlenn Lagasse 	if (*menu_fp == NULL)
4001f169c0eaSGlenn Lagasse 		return (errno_to_be_err(errno));
4002f169c0eaSGlenn Lagasse 
4003f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
4004f169c0eaSGlenn Lagasse }
4005f169c0eaSGlenn Lagasse 
4006f169c0eaSGlenn Lagasse /*
4007f169c0eaSGlenn Lagasse  * Function:	be_open_menu
4008f169c0eaSGlenn Lagasse  * Description:
4009f169c0eaSGlenn Lagasse  *		This function is used it open the menu.lst file. If this
4010f169c0eaSGlenn Lagasse  *              file does not exist be_create_menu is called to create it
4011f169c0eaSGlenn Lagasse  *              and the open file pointer is returned. If the file does
4012f169c0eaSGlenn Lagasse  *              exist it is simply opened using the mode passed in.
4013f169c0eaSGlenn Lagasse  * Parameters:
4014f169c0eaSGlenn Lagasse  *		pool - The name of the pool the menu.lst file is on
4015f169c0eaSGlenn Lagasse  *		menu_file - The name of the file we're opening.
4016f169c0eaSGlenn Lagasse  *		menu_fp - A pointer to the file pointer of the file we're
4017f169c0eaSGlenn Lagasse  *			  opening. This is also used to pass back the file
4018f169c0eaSGlenn Lagasse  *			  pointer.
4019f169c0eaSGlenn Lagasse  *		mode - the original mode to be used for opening the menu.lst
4020f169c0eaSGlenn Lagasse  *                     file.
4021f169c0eaSGlenn Lagasse  *              create_menu - If this is true and the menu.lst file does not
4022f169c0eaSGlenn Lagasse  *                            exist we will attempt to re-create it. However
4023f169c0eaSGlenn Lagasse  *                            if it's false the error returned from the fopen
4024f169c0eaSGlenn Lagasse  *                            will be returned.
4025f169c0eaSGlenn Lagasse  * Returns:
4026f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
4027f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
4028f169c0eaSGlenn Lagasse  * Scope:
4029f169c0eaSGlenn Lagasse  *		Private
4030f169c0eaSGlenn Lagasse  */
4031f169c0eaSGlenn Lagasse static int
4032f169c0eaSGlenn Lagasse be_open_menu(
4033f169c0eaSGlenn Lagasse 	char *pool,
4034f169c0eaSGlenn Lagasse 	char *menu_file,
4035f169c0eaSGlenn Lagasse 	FILE **menu_fp,
4036f169c0eaSGlenn Lagasse 	char *mode,
4037f169c0eaSGlenn Lagasse 	boolean_t create_menu)
4038f169c0eaSGlenn Lagasse {
4039f169c0eaSGlenn Lagasse 	int	err = 0;
4040f169c0eaSGlenn Lagasse 	boolean_t	set_print = B_FALSE;
4041f169c0eaSGlenn Lagasse 
4042f169c0eaSGlenn Lagasse 	*menu_fp = fopen(menu_file, mode);
4043f169c0eaSGlenn Lagasse 	err = errno;
4044f169c0eaSGlenn Lagasse 	if (*menu_fp == NULL) {
4045f169c0eaSGlenn Lagasse 		if (err == ENOENT && create_menu) {
4046f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_open_menu: menu.lst "
4047f169c0eaSGlenn Lagasse 			    "file %s does not exist,\n"), menu_file);
4048f169c0eaSGlenn Lagasse 			if (!do_print) {
4049f169c0eaSGlenn Lagasse 				set_print = B_TRUE;
4050f169c0eaSGlenn Lagasse 				do_print = B_TRUE;
4051f169c0eaSGlenn Lagasse 			}
4052f169c0eaSGlenn Lagasse 			be_print_err(gettext("WARNING: menu.lst "
4053f169c0eaSGlenn Lagasse 			    "file %s does not exist,\n         generating "
4054f169c0eaSGlenn Lagasse 			    "a new menu.lst file\n"), menu_file);
4055f169c0eaSGlenn Lagasse 			if (set_print)
4056f169c0eaSGlenn Lagasse 				do_print = B_FALSE;
4057f169c0eaSGlenn Lagasse 			err = 0;
4058de1ab35cSAlexander Eremin 			if ((err = be_create_menu(pool, menu_file,
4059f169c0eaSGlenn Lagasse 			    menu_fp, mode)) == ENOENT)
4060f169c0eaSGlenn Lagasse 				return (BE_ERR_NO_MENU);
4061f169c0eaSGlenn Lagasse 			else if (err != BE_SUCCESS)
4062f169c0eaSGlenn Lagasse 				return (err);
4063f169c0eaSGlenn Lagasse 			else if (*menu_fp == NULL)
4064f169c0eaSGlenn Lagasse 				return (BE_ERR_NO_MENU);
4065f169c0eaSGlenn Lagasse 		} else {
4066f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_open_menu: failed "
4067f169c0eaSGlenn Lagasse 			    "to open menu.lst file %s\n"), menu_file);
4068f169c0eaSGlenn Lagasse 			if (err == ENOENT)
4069f169c0eaSGlenn Lagasse 				return (BE_ERR_NO_MENU);
4070f169c0eaSGlenn Lagasse 			else
4071f169c0eaSGlenn Lagasse 				return (errno_to_be_err(err));
4072f169c0eaSGlenn Lagasse 		}
4073f169c0eaSGlenn Lagasse 	}
4074f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
4075f169c0eaSGlenn Lagasse }
4076