xref: /illumos-gate/usr/src/lib/libbe/common/be_utils.c (revision bb771288)
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.
2702123a49SAndy Fiddaman  * Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
28ce829a51SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
296b1d07a4SAlexander Eremin  */
306b1d07a4SAlexander Eremin 
316b1d07a4SAlexander Eremin 
32f169c0eaSGlenn Lagasse /*
33f169c0eaSGlenn Lagasse  * System includes
34f169c0eaSGlenn Lagasse  */
35f169c0eaSGlenn Lagasse #include <assert.h>
36f169c0eaSGlenn Lagasse #include <errno.h>
37f169c0eaSGlenn Lagasse #include <libgen.h>
38f169c0eaSGlenn Lagasse #include <libintl.h>
39f169c0eaSGlenn Lagasse #include <libnvpair.h>
40f169c0eaSGlenn Lagasse #include <libzfs.h>
41f169c0eaSGlenn Lagasse #include <libgen.h>
42f169c0eaSGlenn Lagasse #include <stdio.h>
43f169c0eaSGlenn Lagasse #include <stdlib.h>
44f169c0eaSGlenn Lagasse #include <string.h>
45f169c0eaSGlenn Lagasse #include <sys/stat.h>
46f169c0eaSGlenn Lagasse #include <sys/types.h>
47f169c0eaSGlenn Lagasse #include <sys/vfstab.h>
48f169c0eaSGlenn Lagasse #include <sys/param.h>
49f169c0eaSGlenn Lagasse #include <sys/systeminfo.h>
50f169c0eaSGlenn Lagasse #include <ctype.h>
51f169c0eaSGlenn Lagasse #include <time.h>
52f169c0eaSGlenn Lagasse #include <unistd.h>
53f169c0eaSGlenn Lagasse #include <fcntl.h>
54de1ab35cSAlexander Eremin #include <deflt.h>
55f169c0eaSGlenn Lagasse #include <wait.h>
566b1d07a4SAlexander Eremin #include <libdevinfo.h>
577e0e2549SAlexander Eremin #include <libgen.h>
58f169c0eaSGlenn Lagasse 
59f169c0eaSGlenn Lagasse #include <libbe.h>
60f169c0eaSGlenn Lagasse #include <libbe_priv.h>
61a63c99a2SToomas Soome #include <boot_utils.h>
62f5e5a2c4SToomas Soome #include <ficl.h>
63f5e5a2c4SToomas Soome #include <ficlplatform/emu.h>
64f169c0eaSGlenn Lagasse 
65f169c0eaSGlenn Lagasse /* Private function prototypes */
66f169c0eaSGlenn Lagasse static int update_dataset(char *, int, char *, char *, char *);
67f169c0eaSGlenn Lagasse static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *);
68de1ab35cSAlexander Eremin static int be_open_menu(char *, char *, FILE **, char *, boolean_t);
69de1ab35cSAlexander Eremin static int be_create_menu(char *, char *, FILE **, char *);
70f169c0eaSGlenn Lagasse static char *be_get_auto_name(char *, char *, boolean_t);
71f169c0eaSGlenn Lagasse 
72f169c0eaSGlenn Lagasse /*
73f169c0eaSGlenn Lagasse  * Global error printing
74f169c0eaSGlenn Lagasse  */
75f169c0eaSGlenn Lagasse boolean_t do_print = B_FALSE;
76f169c0eaSGlenn Lagasse 
77f169c0eaSGlenn Lagasse /*
78f169c0eaSGlenn Lagasse  * Private datatypes
79f169c0eaSGlenn Lagasse  */
80f169c0eaSGlenn Lagasse typedef struct zone_be_name_cb_data {
81f169c0eaSGlenn Lagasse 	char *base_be_name;
82f169c0eaSGlenn Lagasse 	int num;
83f169c0eaSGlenn Lagasse } zone_be_name_cb_data_t;
84f169c0eaSGlenn Lagasse 
85f169c0eaSGlenn Lagasse /* ********************************************************************	*/
86f169c0eaSGlenn Lagasse /*			Public Functions				*/
87f169c0eaSGlenn Lagasse /* ******************************************************************** */
88f169c0eaSGlenn Lagasse 
89f5e5a2c4SToomas Soome /*
90f5e5a2c4SToomas Soome  * Callback for ficl to suppress all output from ficl, as we do not
91f5e5a2c4SToomas Soome  * want to confuse user with messages from ficl, and we are only
92f5e5a2c4SToomas Soome  * checking results from function calls.
93f5e5a2c4SToomas Soome  */
94f5e5a2c4SToomas Soome /*ARGSUSED*/
95f5e5a2c4SToomas Soome static void
ficlSuppressTextOutput(ficlCallback * cb,char * text)96f5e5a2c4SToomas Soome ficlSuppressTextOutput(ficlCallback *cb, char *text)
97f5e5a2c4SToomas Soome {
98f5e5a2c4SToomas Soome 	/* This function is intentionally doing nothing. */
99f5e5a2c4SToomas Soome }
100f5e5a2c4SToomas Soome 
101f5e5a2c4SToomas Soome /*
102f5e5a2c4SToomas Soome  * Function:	be_get_boot_args
103f5e5a2c4SToomas Soome  * Description:	Returns the fast boot argument string for enumerated BE.
104f5e5a2c4SToomas Soome  * Parameters:
105f5e5a2c4SToomas Soome  *		fbarg - pointer to argument string.
106f5e5a2c4SToomas Soome  *		entry - index of BE.
107f5e5a2c4SToomas Soome  * Returns:
108f5e5a2c4SToomas Soome  *		fast boot argument string.
109f5e5a2c4SToomas Soome  * Scope:
110f5e5a2c4SToomas Soome  *		Public
111f5e5a2c4SToomas Soome  */
112f5e5a2c4SToomas Soome int
be_get_boot_args(char ** fbarg,int entry)113f5e5a2c4SToomas Soome be_get_boot_args(char **fbarg, int entry)
114f5e5a2c4SToomas Soome {
115f5e5a2c4SToomas Soome 	be_node_list_t *node, *be_nodes = NULL;
116f5e5a2c4SToomas Soome 	be_transaction_data_t bt = {0};
117f5e5a2c4SToomas Soome 	char *mountpoint = NULL;
118f5e5a2c4SToomas Soome 	boolean_t be_mounted = B_FALSE;
119f5e5a2c4SToomas Soome 	int ret = BE_SUCCESS;
120f5e5a2c4SToomas Soome 	int index;
121f5e5a2c4SToomas Soome 	ficlVm *vm;
122f5e5a2c4SToomas Soome 
123f5e5a2c4SToomas Soome 	*fbarg = NULL;
124f5e5a2c4SToomas Soome 	if (!be_zfs_init())
125f5e5a2c4SToomas Soome 		return (BE_ERR_INIT);
126f5e5a2c4SToomas Soome 
127f5e5a2c4SToomas Soome 	/*
128f5e5a2c4SToomas Soome 	 * need pool name, menu.lst has entries from our pool only
129f5e5a2c4SToomas Soome 	 */
130f5e5a2c4SToomas Soome 	ret = be_find_current_be(&bt);
131f5e5a2c4SToomas Soome 	if (ret != BE_SUCCESS) {
132f5e5a2c4SToomas Soome 		be_zfs_fini();
133f5e5a2c4SToomas Soome 		return (ret);
134f5e5a2c4SToomas Soome 	}
135f5e5a2c4SToomas Soome 
136f5e5a2c4SToomas Soome 	/*
137f5e5a2c4SToomas Soome 	 * be_get_boot_args() is for loader, fail with grub will trigger
138f5e5a2c4SToomas Soome 	 * normal boot.
139f5e5a2c4SToomas Soome 	 */
140f5e5a2c4SToomas Soome 	if (be_has_grub()) {
141f5e5a2c4SToomas Soome 		ret = BE_ERR_INIT;
142f5e5a2c4SToomas Soome 		goto done;
143f5e5a2c4SToomas Soome 	}
144f5e5a2c4SToomas Soome 
145a897f28bSAndy Fiddaman 	ret = _be_list(NULL, &be_nodes, BE_LIST_DEFAULT);
146f5e5a2c4SToomas Soome 	if (ret != BE_SUCCESS)
147f5e5a2c4SToomas Soome 		goto done;
148f5e5a2c4SToomas Soome 
149f5e5a2c4SToomas Soome 	/*
150f5e5a2c4SToomas Soome 	 * iterate through be_nodes,
151f5e5a2c4SToomas Soome 	 * if entry == -1, stop if be_active_on_boot,
152f5e5a2c4SToomas Soome 	 * else stop if index == entry.
153f5e5a2c4SToomas Soome 	 */
154f5e5a2c4SToomas Soome 	index = 0;
155f5e5a2c4SToomas Soome 	for (node = be_nodes; node != NULL; node = node->be_next_node) {
156f5e5a2c4SToomas Soome 		if (strcmp(node->be_rpool, bt.obe_zpool) != 0)
157f5e5a2c4SToomas Soome 			continue;
158f5e5a2c4SToomas Soome 		if (entry == BE_ENTRY_DEFAULT &&
159f5e5a2c4SToomas Soome 		    node->be_active_on_boot == B_TRUE)
160f5e5a2c4SToomas Soome 			break;
161f5e5a2c4SToomas Soome 		if (index == entry)
162f5e5a2c4SToomas Soome 			break;
163f5e5a2c4SToomas Soome 		index++;
164f5e5a2c4SToomas Soome 	}
165f5e5a2c4SToomas Soome 	if (node == NULL) {
166f5e5a2c4SToomas Soome 		be_free_list(be_nodes);
167f5e5a2c4SToomas Soome 		ret = BE_ERR_NOENT;
168f5e5a2c4SToomas Soome 		goto done;
169f5e5a2c4SToomas Soome 	}
170f5e5a2c4SToomas Soome 
171f5e5a2c4SToomas Soome 	/* try to mount inactive be */
172f5e5a2c4SToomas Soome 	if (node->be_active == B_FALSE) {
173f5e5a2c4SToomas Soome 		ret = _be_mount(node->be_node_name, &mountpoint,
174f5e5a2c4SToomas Soome 		    BE_MOUNT_FLAG_NO_ZONES);
175f5e5a2c4SToomas Soome 		if (ret != BE_SUCCESS && ret != BE_ERR_MOUNTED) {
176f5e5a2c4SToomas Soome 			be_free_list(be_nodes);
177f5e5a2c4SToomas Soome 			goto done;
178f5e5a2c4SToomas Soome 		} else
179f5e5a2c4SToomas Soome 			be_mounted = B_TRUE;
180f5e5a2c4SToomas Soome 	}
181f5e5a2c4SToomas Soome 
182f5e5a2c4SToomas Soome 	vm = bf_init("", ficlSuppressTextOutput);
183f5e5a2c4SToomas Soome 	if (vm != NULL) {
184f5e5a2c4SToomas Soome 		/*
185f5e5a2c4SToomas Soome 		 * zfs MAXNAMELEN is 256, so we need to pick buf large enough
186f5e5a2c4SToomas Soome 		 * to contain such names.
187f5e5a2c4SToomas Soome 		 */
188f5e5a2c4SToomas Soome 		char buf[MAXNAMELEN * 2];
189f5e5a2c4SToomas Soome 		char *kernel_options = NULL;
190f5e5a2c4SToomas Soome 		char *kernel = NULL;
191f5e5a2c4SToomas Soome 		char *tmp;
192f5e5a2c4SToomas Soome 		zpool_handle_t *zph;
193f5e5a2c4SToomas Soome 
194f5e5a2c4SToomas Soome 		/*
195f5e5a2c4SToomas Soome 		 * just try to interpret following words. on error
196f5e5a2c4SToomas Soome 		 * we will be missing kernelname, and will get out.
197f5e5a2c4SToomas Soome 		 */
198f5e5a2c4SToomas Soome 		(void) snprintf(buf, sizeof (buf), "set currdev=zfs:%s:",
199f5e5a2c4SToomas Soome 		    node->be_root_ds);
200f5e5a2c4SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
201f5e5a2c4SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
202f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: error "
203f5e5a2c4SToomas Soome 			    "interpreting boot config: %d\n"), ret);
204f5e5a2c4SToomas Soome 			bf_fini();
205f5e5a2c4SToomas Soome 			ret = BE_ERR_NO_MENU;
206f5e5a2c4SToomas Soome 			goto cleanup;
207f5e5a2c4SToomas Soome 		}
208f5e5a2c4SToomas Soome 		(void) snprintf(buf, sizeof (buf),
209f5e5a2c4SToomas Soome 		    "include /boot/forth/loader.4th");
210f5e5a2c4SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
211f5e5a2c4SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
212f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: error "
213f5e5a2c4SToomas Soome 			    "interpreting boot config: %d\n"), ret);
214f5e5a2c4SToomas Soome 			bf_fini();
215f5e5a2c4SToomas Soome 			ret = BE_ERR_NO_MENU;
216f5e5a2c4SToomas Soome 			goto cleanup;
217f5e5a2c4SToomas Soome 		}
218f5e5a2c4SToomas Soome 		(void) snprintf(buf, sizeof (buf), "start");
219f5e5a2c4SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
220f5e5a2c4SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
221f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: error "
222f5e5a2c4SToomas Soome 			    "interpreting boot config: %d\n"), ret);
223f5e5a2c4SToomas Soome 			bf_fini();
224f5e5a2c4SToomas Soome 			ret = BE_ERR_NO_MENU;
225f5e5a2c4SToomas Soome 			goto cleanup;
226f5e5a2c4SToomas Soome 		}
227f5e5a2c4SToomas Soome 		(void) snprintf(buf, sizeof (buf), "boot");
228f5e5a2c4SToomas Soome 		ret = ficlVmEvaluate(vm, buf);
229f5e5a2c4SToomas Soome 		bf_fini();
230f5e5a2c4SToomas Soome 		if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
231f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: error "
232f5e5a2c4SToomas Soome 			    "interpreting boot config: %d\n"), ret);
233f5e5a2c4SToomas Soome 			ret = BE_ERR_NO_MENU;
234f5e5a2c4SToomas Soome 			goto cleanup;
235f5e5a2c4SToomas Soome 		}
236f5e5a2c4SToomas Soome 
237f5e5a2c4SToomas Soome 		kernel_options = getenv("boot-args");
238f5e5a2c4SToomas Soome 		kernel = getenv("kernelname");
239f5e5a2c4SToomas Soome 
240f5e5a2c4SToomas Soome 		if (kernel == NULL) {
241f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: no kernel\n"));
242f5e5a2c4SToomas Soome 			ret = BE_ERR_NOENT;
243f5e5a2c4SToomas Soome 			goto cleanup;
244f5e5a2c4SToomas Soome 		}
245f5e5a2c4SToomas Soome 
246f5e5a2c4SToomas Soome 		if ((zph = zpool_open(g_zfs, node->be_rpool)) == NULL) {
247f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: failed to "
248f5e5a2c4SToomas Soome 			    "open root pool (%s): %s\n"), node->be_rpool,
249f5e5a2c4SToomas Soome 			    libzfs_error_description(g_zfs));
250f5e5a2c4SToomas Soome 			ret = zfs_err_to_be_err(g_zfs);
251f5e5a2c4SToomas Soome 			goto cleanup;
252f5e5a2c4SToomas Soome 		}
253f5e5a2c4SToomas Soome 		ret = zpool_get_physpath(zph, buf, sizeof (buf));
254f5e5a2c4SToomas Soome 		zpool_close(zph);
255f5e5a2c4SToomas Soome 		if (ret != 0) {
256f5e5a2c4SToomas Soome 			be_print_err(gettext("be_get_boot_args: failed to "
257f5e5a2c4SToomas Soome 			    "get physpath\n"));
258f5e5a2c4SToomas Soome 			goto cleanup;
259f5e5a2c4SToomas Soome 		}
260f5e5a2c4SToomas Soome 
261f5e5a2c4SToomas Soome 		/* zpool_get_physpath() can return space separated list */
262f5e5a2c4SToomas Soome 		tmp = buf;
263f5e5a2c4SToomas Soome 		tmp = strsep(&tmp, " ");
264f5e5a2c4SToomas Soome 
265f5e5a2c4SToomas Soome 		if (kernel_options == NULL || *kernel_options == '\0')
266f5e5a2c4SToomas Soome 			(void) asprintf(fbarg, "/ %s "
267f5e5a2c4SToomas Soome 			    "-B zfs-bootfs=%s,bootpath=\"%s\"\n", kernel,
268f5e5a2c4SToomas Soome 			    node->be_root_ds, tmp);
269f5e5a2c4SToomas Soome 		else
270f5e5a2c4SToomas Soome 			(void) asprintf(fbarg, "/ %s %s "
271f5e5a2c4SToomas Soome 			    "-B zfs-bootfs=%s,bootpath=\"%s\"\n", kernel,
272f5e5a2c4SToomas Soome 			    kernel_options, node->be_root_ds, tmp);
273f5e5a2c4SToomas Soome 
274ce829a51SJohn Levon 		if (*fbarg == NULL)
275f5e5a2c4SToomas Soome 			ret = BE_ERR_NOMEM;
276f5e5a2c4SToomas Soome 		else
277f5e5a2c4SToomas Soome 			ret = 0;
278f5e5a2c4SToomas Soome 	} else
279f5e5a2c4SToomas Soome 		ret = BE_ERR_NOMEM;
280f5e5a2c4SToomas Soome cleanup:
281f5e5a2c4SToomas Soome 	if (be_mounted == B_TRUE)
282f5e5a2c4SToomas Soome 		(void) _be_unmount(node->be_node_name, BE_UNMOUNT_FLAG_FORCE);
283f5e5a2c4SToomas Soome 	be_free_list(be_nodes);
284f5e5a2c4SToomas Soome done:
285f5e5a2c4SToomas Soome 	free(mountpoint);
286f5e5a2c4SToomas Soome 	free(bt.obe_name);
287f5e5a2c4SToomas Soome 	free(bt.obe_root_ds);
288f5e5a2c4SToomas Soome 	free(bt.obe_zpool);
289f5e5a2c4SToomas Soome 	free(bt.obe_snap_name);
290f5e5a2c4SToomas Soome 	free(bt.obe_altroot);
291f5e5a2c4SToomas Soome 	be_zfs_fini();
292f5e5a2c4SToomas Soome 	return (ret);
293f5e5a2c4SToomas Soome }
294f5e5a2c4SToomas Soome 
295f169c0eaSGlenn Lagasse /*
296f169c0eaSGlenn Lagasse  * Function:	be_max_avail
297f169c0eaSGlenn Lagasse  * Description:	Returns the available size for the zfs dataset passed in.
298f169c0eaSGlenn Lagasse  * Parameters:
299f169c0eaSGlenn Lagasse  *		dataset - The dataset we want to get the available space for.
300f169c0eaSGlenn Lagasse  *		ret - The available size will be returned in this.
301f169c0eaSGlenn Lagasse  * Returns:
302f169c0eaSGlenn Lagasse  *		The error returned by the zfs get property function.
303f169c0eaSGlenn Lagasse  * Scope:
304f169c0eaSGlenn Lagasse  *		Public
305f169c0eaSGlenn Lagasse  */
306f169c0eaSGlenn Lagasse int
be_max_avail(char * dataset,uint64_t * ret)307f169c0eaSGlenn Lagasse be_max_avail(char *dataset, uint64_t *ret)
308f169c0eaSGlenn Lagasse {
309f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp;
310f169c0eaSGlenn Lagasse 	int err = 0;
311f169c0eaSGlenn Lagasse 
312f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
313f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
314f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
315f169c0eaSGlenn Lagasse 
316f169c0eaSGlenn Lagasse 	zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET);
317f169c0eaSGlenn Lagasse 	if (zhp == NULL) {
318f169c0eaSGlenn Lagasse 		/*
319f169c0eaSGlenn Lagasse 		 * The zfs_open failed return an error
320f169c0eaSGlenn Lagasse 		 */
321f169c0eaSGlenn Lagasse 		err = zfs_err_to_be_err(g_zfs);
322f169c0eaSGlenn Lagasse 	} else {
323f169c0eaSGlenn Lagasse 		err = be_maxsize_avail(zhp, ret);
324f169c0eaSGlenn Lagasse 	}
325f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
326f169c0eaSGlenn Lagasse 	be_zfs_fini();
327f169c0eaSGlenn Lagasse 	return (err);
328f169c0eaSGlenn Lagasse }
329f169c0eaSGlenn Lagasse 
330f169c0eaSGlenn Lagasse /*
331f169c0eaSGlenn Lagasse  * Function:	libbe_print_errors
332f169c0eaSGlenn Lagasse  * Description:	Turns on/off error output for the library.
333f169c0eaSGlenn Lagasse  * Parameter:
334f169c0eaSGlenn Lagasse  *		set_do_print - Boolean that turns library error
335f169c0eaSGlenn Lagasse  *			       printing on or off.
336f169c0eaSGlenn Lagasse  * Returns:
337f169c0eaSGlenn Lagasse  *		None
338f169c0eaSGlenn Lagasse  * Scope:
339f169c0eaSGlenn Lagasse  *		Public;
340f169c0eaSGlenn Lagasse  */
341f169c0eaSGlenn Lagasse void
libbe_print_errors(boolean_t set_do_print)342f169c0eaSGlenn Lagasse libbe_print_errors(boolean_t set_do_print)
343f169c0eaSGlenn Lagasse {
344f169c0eaSGlenn Lagasse 	do_print = set_do_print;
345f169c0eaSGlenn Lagasse }
346f169c0eaSGlenn Lagasse 
347f169c0eaSGlenn Lagasse /* ********************************************************************	*/
348f169c0eaSGlenn Lagasse /*			Semi-Private Functions				*/
349f169c0eaSGlenn Lagasse /* ******************************************************************** */
350f169c0eaSGlenn Lagasse 
351f169c0eaSGlenn Lagasse /*
352f169c0eaSGlenn Lagasse  * Function:	be_zfs_init
353f169c0eaSGlenn Lagasse  * Description:	Initializes the libary global libzfs handle.
354f169c0eaSGlenn Lagasse  * Parameters:
355f169c0eaSGlenn Lagasse  *		None
356f169c0eaSGlenn Lagasse  * Returns:
357f169c0eaSGlenn Lagasse  *		B_TRUE - Success
358f169c0eaSGlenn Lagasse  *		B_FALSE - Failure
359f169c0eaSGlenn Lagasse  * Scope:
360f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
361f169c0eaSGlenn Lagasse  */
362f169c0eaSGlenn Lagasse boolean_t
be_zfs_init(void)363f169c0eaSGlenn Lagasse be_zfs_init(void)
364f169c0eaSGlenn Lagasse {
365f169c0eaSGlenn Lagasse 	be_zfs_fini();
366f169c0eaSGlenn Lagasse 
367f169c0eaSGlenn Lagasse 	if ((g_zfs = libzfs_init()) == NULL) {
368f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
369f169c0eaSGlenn Lagasse 		    "library\n"));
370f169c0eaSGlenn Lagasse 		return (B_FALSE);
371f169c0eaSGlenn Lagasse 	}
372f169c0eaSGlenn Lagasse 
373f169c0eaSGlenn Lagasse 	return (B_TRUE);
374f169c0eaSGlenn Lagasse }
375f169c0eaSGlenn Lagasse 
376f169c0eaSGlenn Lagasse /*
377f169c0eaSGlenn Lagasse  * Function:	be_zfs_fini
378f169c0eaSGlenn Lagasse  * Description:	Closes the library global libzfs handle if it currently open.
379f169c0eaSGlenn Lagasse  * Parameter:
380f169c0eaSGlenn Lagasse  *		None
381f169c0eaSGlenn Lagasse  * Returns:
382f169c0eaSGlenn Lagasse  *		None
383f169c0eaSGlenn Lagasse  * Scope:
384f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
385f169c0eaSGlenn Lagasse  */
386f169c0eaSGlenn Lagasse void
be_zfs_fini(void)387f169c0eaSGlenn Lagasse be_zfs_fini(void)
388f169c0eaSGlenn Lagasse {
389f169c0eaSGlenn Lagasse 	if (g_zfs)
390f169c0eaSGlenn Lagasse 		libzfs_fini(g_zfs);
391f169c0eaSGlenn Lagasse 
392f169c0eaSGlenn Lagasse 	g_zfs = NULL;
393f169c0eaSGlenn Lagasse }
394f169c0eaSGlenn Lagasse 
395de1ab35cSAlexander Eremin /*
396de1ab35cSAlexander Eremin  * Function:	be_get_defaults
397de1ab35cSAlexander Eremin  * Description:	Open defaults and gets be default paramets
398de1ab35cSAlexander Eremin  * Parameters:
399de1ab35cSAlexander Eremin  *		defaults - be defaults struct
400de1ab35cSAlexander Eremin  * Returns:
401de1ab35cSAlexander Eremin  *		None
402de1ab35cSAlexander Eremin  * Scope:
403de1ab35cSAlexander Eremin  *		Semi-private (library wide use only)
404de1ab35cSAlexander Eremin  */
405de1ab35cSAlexander Eremin void
be_get_defaults(struct be_defaults * defaults)406de1ab35cSAlexander Eremin be_get_defaults(struct be_defaults *defaults)
407de1ab35cSAlexander Eremin {
408de1ab35cSAlexander Eremin 	void	*defp;
409de1ab35cSAlexander Eremin 
410fa0c327aSToomas Soome 	defaults->be_deflt_grub = B_FALSE;
411de1ab35cSAlexander Eremin 	defaults->be_deflt_rpool_container = B_FALSE;
412de1ab35cSAlexander Eremin 	defaults->be_deflt_bename_starts_with[0] = '\0';
413de1ab35cSAlexander Eremin 
414de1ab35cSAlexander Eremin 	if ((defp = defopen_r(BE_DEFAULTS)) != NULL) {
415de1ab35cSAlexander Eremin 		const char *res = defread_r(BE_DFLT_BENAME_STARTS, defp);
416fa0c327aSToomas Soome 		if (res != NULL && res[0] != '\0') {
417de1ab35cSAlexander Eremin 			(void) strlcpy(defaults->be_deflt_bename_starts_with,
4189adfa60dSMatthew Ahrens 			    res, ZFS_MAX_DATASET_NAME_LEN);
419de1ab35cSAlexander Eremin 			defaults->be_deflt_rpool_container = B_TRUE;
420de1ab35cSAlexander Eremin 		}
421fa0c327aSToomas Soome 		if (be_is_isa("i386")) {
422fa0c327aSToomas Soome 			res = defread_r(BE_DFLT_BE_HAS_GRUB, defp);
423fa0c327aSToomas Soome 			if (res != NULL && res[0] != '\0') {
424fa0c327aSToomas Soome 				if (strcasecmp(res, "true") == 0)
425fa0c327aSToomas Soome 					defaults->be_deflt_grub = B_TRUE;
426fa0c327aSToomas Soome 			}
427fa0c327aSToomas Soome 		}
428de1ab35cSAlexander Eremin 		defclose_r(defp);
429de1ab35cSAlexander Eremin 	}
430de1ab35cSAlexander Eremin }
431de1ab35cSAlexander Eremin 
432f169c0eaSGlenn Lagasse /*
433f169c0eaSGlenn Lagasse  * Function:	be_make_root_ds
434f169c0eaSGlenn Lagasse  * Description:	Generate string for BE's root dataset given the pool
435f169c0eaSGlenn Lagasse  *		it lives in and the BE name.
436f169c0eaSGlenn Lagasse  * Parameters:
437f169c0eaSGlenn Lagasse  *		zpool - pointer zpool name.
438f169c0eaSGlenn Lagasse  *		be_name - pointer to BE name.
439f169c0eaSGlenn Lagasse  *		be_root_ds - pointer to buffer to return BE root dataset in.
440f169c0eaSGlenn Lagasse  *		be_root_ds_size - size of be_root_ds
441f169c0eaSGlenn Lagasse  * Returns:
442f169c0eaSGlenn Lagasse  *		None
443f169c0eaSGlenn Lagasse  * Scope:
444f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
445f169c0eaSGlenn Lagasse  */
446f169c0eaSGlenn Lagasse void
be_make_root_ds(const char * zpool,const char * be_name,char * be_root_ds,int be_root_ds_size)447f169c0eaSGlenn Lagasse be_make_root_ds(const char *zpool, const char *be_name, char *be_root_ds,
448f169c0eaSGlenn Lagasse     int be_root_ds_size)
449f169c0eaSGlenn Lagasse {
450de1ab35cSAlexander Eremin 	struct be_defaults be_defaults;
451de1ab35cSAlexander Eremin 	be_get_defaults(&be_defaults);
4527e0e2549SAlexander Eremin 	char	*root_ds = NULL;
453de1ab35cSAlexander Eremin 
4547e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
4557e0e2549SAlexander Eremin 		if (be_defaults.be_deflt_rpool_container) {
4567e0e2549SAlexander Eremin 			(void) snprintf(be_root_ds, be_root_ds_size,
4577e0e2549SAlexander Eremin 			    "%s/%s", zpool, be_name);
4587e0e2549SAlexander Eremin 		} else {
4597e0e2549SAlexander Eremin 			(void) snprintf(be_root_ds, be_root_ds_size,
4607e0e2549SAlexander Eremin 			    "%s/%s/%s", zpool, BE_CONTAINER_DS_NAME, be_name);
4617e0e2549SAlexander Eremin 		}
4627e0e2549SAlexander Eremin 	} else {
4637e0e2549SAlexander Eremin 		/*
4647e0e2549SAlexander Eremin 		 * In non-global zone we can use path from mounted root dataset
4657e0e2549SAlexander Eremin 		 * to generate BE's root dataset string.
4667e0e2549SAlexander Eremin 		 */
4677e0e2549SAlexander Eremin 		if ((root_ds = be_get_ds_from_dir("/")) != NULL) {
4687e0e2549SAlexander Eremin 			(void) snprintf(be_root_ds, be_root_ds_size, "%s/%s",
4697e0e2549SAlexander Eremin 			    dirname(root_ds), be_name);
4707e0e2549SAlexander Eremin 		} else {
4717e0e2549SAlexander Eremin 			be_print_err(gettext("be_make_root_ds: zone root "
4727e0e2549SAlexander Eremin 			    "dataset is not mounted\n"));
4737e0e2549SAlexander Eremin 			return;
4747e0e2549SAlexander Eremin 		}
4757e0e2549SAlexander Eremin 	}
476f169c0eaSGlenn Lagasse }
477f169c0eaSGlenn Lagasse 
478f169c0eaSGlenn Lagasse /*
479f169c0eaSGlenn Lagasse  * Function:	be_make_container_ds
480f169c0eaSGlenn Lagasse  * Description:	Generate string for the BE container dataset given a pool name.
481f169c0eaSGlenn Lagasse  * Parameters:
482f169c0eaSGlenn Lagasse  *		zpool - pointer zpool name.
483f169c0eaSGlenn Lagasse  *		container_ds - pointer to buffer to return BE container
484f169c0eaSGlenn Lagasse  *			dataset in.
485f169c0eaSGlenn Lagasse  *		container_ds_size - size of container_ds
486f169c0eaSGlenn Lagasse  * Returns:
487f169c0eaSGlenn Lagasse  *		None
488f169c0eaSGlenn Lagasse  * Scope:
489f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
490f169c0eaSGlenn Lagasse  */
491f169c0eaSGlenn Lagasse void
be_make_container_ds(const char * zpool,char * container_ds,int container_ds_size)492f169c0eaSGlenn Lagasse be_make_container_ds(const char *zpool,  char *container_ds,
493f169c0eaSGlenn Lagasse     int container_ds_size)
494f169c0eaSGlenn Lagasse {
495de1ab35cSAlexander Eremin 	struct be_defaults be_defaults;
496de1ab35cSAlexander Eremin 	be_get_defaults(&be_defaults);
4977e0e2549SAlexander Eremin 	char	*root_ds = NULL;
498de1ab35cSAlexander Eremin 
4997e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
5007e0e2549SAlexander Eremin 		if (be_defaults.be_deflt_rpool_container) {
5017e0e2549SAlexander Eremin 			(void) snprintf(container_ds, container_ds_size,
5027e0e2549SAlexander Eremin 			    "%s", zpool);
5037e0e2549SAlexander Eremin 		} else {
5047e0e2549SAlexander Eremin 			(void) snprintf(container_ds, container_ds_size,
5057e0e2549SAlexander Eremin 			    "%s/%s", zpool, BE_CONTAINER_DS_NAME);
5067e0e2549SAlexander Eremin 		}
5077e0e2549SAlexander Eremin 	} else {
5087e0e2549SAlexander Eremin 		if ((root_ds = be_get_ds_from_dir("/")) != NULL) {
5097e0e2549SAlexander Eremin 			(void) strlcpy(container_ds, dirname(root_ds),
5107e0e2549SAlexander Eremin 			    container_ds_size);
5117e0e2549SAlexander Eremin 		} else {
5127e0e2549SAlexander Eremin 			be_print_err(gettext("be_make_container_ds: zone root "
5137e0e2549SAlexander Eremin 			    "dataset is not mounted\n"));
5147e0e2549SAlexander Eremin 			return;
5157e0e2549SAlexander Eremin 		}
5167e0e2549SAlexander Eremin 	}
517f169c0eaSGlenn Lagasse }
518f169c0eaSGlenn Lagasse 
51902123a49SAndy Fiddaman /*
52002123a49SAndy Fiddaman  * Function:	be_make_root_container_ds
52102123a49SAndy Fiddaman  * Description:	Generate string for the BE root container dataset given a pool
52202123a49SAndy Fiddaman  *              name.
52302123a49SAndy Fiddaman  * Parameters:
52402123a49SAndy Fiddaman  *		zpool - pointer zpool name.
52502123a49SAndy Fiddaman  *		container_ds - pointer to buffer in which to return result
52602123a49SAndy Fiddaman  *		container_ds_size - size of container_ds
52702123a49SAndy Fiddaman  * Returns:
52802123a49SAndy Fiddaman  *		None
52902123a49SAndy Fiddaman  * Scope:
53002123a49SAndy Fiddaman  *		Semi-private (library wide use only)
53102123a49SAndy Fiddaman  */
53202123a49SAndy Fiddaman void
be_make_root_container_ds(const char * zpool,char * container_ds,int container_ds_size)53302123a49SAndy Fiddaman be_make_root_container_ds(const char *zpool, char *container_ds,
53402123a49SAndy Fiddaman     int container_ds_size)
53502123a49SAndy Fiddaman {
53602123a49SAndy Fiddaman 	char *root;
53702123a49SAndy Fiddaman 
53802123a49SAndy Fiddaman 	be_make_container_ds(zpool, container_ds, container_ds_size);
53902123a49SAndy Fiddaman 
54002123a49SAndy Fiddaman 	/* If the container DS ends with /ROOT, remove it.  */
54102123a49SAndy Fiddaman 
54202123a49SAndy Fiddaman 	if ((root = strrchr(container_ds, '/')) != NULL &&
54302123a49SAndy Fiddaman 	    strcmp(root + 1, BE_CONTAINER_DS_NAME) == 0) {
54402123a49SAndy Fiddaman 		*root = '\0';
54502123a49SAndy Fiddaman 	}
54602123a49SAndy Fiddaman }
54702123a49SAndy Fiddaman 
548f169c0eaSGlenn Lagasse /*
549f169c0eaSGlenn Lagasse  * Function:	be_make_name_from_ds
550f169c0eaSGlenn Lagasse  * Description:	This function takes a dataset name and strips off the
551f169c0eaSGlenn Lagasse  *		BE container dataset portion from the beginning.  The
552f169c0eaSGlenn Lagasse  *		returned name is allocated in heap storage, so the caller
553f169c0eaSGlenn Lagasse  *		is responsible for freeing it.
554f169c0eaSGlenn Lagasse  * Parameters:
555f169c0eaSGlenn Lagasse  *		dataset - dataset to get name from.
556f169c0eaSGlenn Lagasse  *		rc_loc - dataset underwhich the root container dataset lives.
557f169c0eaSGlenn Lagasse  * Returns:
558f169c0eaSGlenn Lagasse  *		name of dataset relative to BE container dataset.
559f169c0eaSGlenn Lagasse  *		NULL if dataset is not under a BE root dataset.
560f169c0eaSGlenn Lagasse  * Scope:
561f169c0eaSGlenn Lagasse  *		Semi-primate (library wide use only)
562f169c0eaSGlenn Lagasse  */
563f169c0eaSGlenn Lagasse char *
be_make_name_from_ds(const char * dataset,char * rc_loc)564f169c0eaSGlenn Lagasse be_make_name_from_ds(const char *dataset, char *rc_loc)
565f169c0eaSGlenn Lagasse {
5669adfa60dSMatthew Ahrens 	char	ds[ZFS_MAX_DATASET_NAME_LEN];
567f169c0eaSGlenn Lagasse 	char	*tok = NULL;
568f169c0eaSGlenn Lagasse 	char	*name = NULL;
569de1ab35cSAlexander Eremin 	struct be_defaults be_defaults;
570de1ab35cSAlexander Eremin 	int	rlen = strlen(rc_loc);
571de1ab35cSAlexander Eremin 
572de1ab35cSAlexander Eremin 	be_get_defaults(&be_defaults);
573f169c0eaSGlenn Lagasse 
574f169c0eaSGlenn Lagasse 	/*
575f169c0eaSGlenn Lagasse 	 * First token is the location of where the root container dataset
576f169c0eaSGlenn Lagasse 	 * lives; it must match rc_loc.
577f169c0eaSGlenn Lagasse 	 */
578de1ab35cSAlexander Eremin 	if (strncmp(dataset, rc_loc, rlen) == 0 && dataset[rlen] == '/')
579de1ab35cSAlexander Eremin 		(void) strlcpy(ds, dataset + rlen + 1, sizeof (ds));
580de1ab35cSAlexander Eremin 	else
581f169c0eaSGlenn Lagasse 		return (NULL);
582f169c0eaSGlenn Lagasse 
583de1ab35cSAlexander Eremin 	if (be_defaults.be_deflt_rpool_container) {
584de1ab35cSAlexander Eremin 		if ((name = strdup(ds)) == NULL) {
585de1ab35cSAlexander Eremin 			be_print_err(gettext("be_make_name_from_ds: "
586de1ab35cSAlexander Eremin 			    "memory allocation failed\n"));
587de1ab35cSAlexander Eremin 			return (NULL);
588de1ab35cSAlexander Eremin 		}
589de1ab35cSAlexander Eremin 	} else {
590de1ab35cSAlexander Eremin 		/* Second token must be BE container dataset name */
591de1ab35cSAlexander Eremin 		if ((tok = strtok(ds, "/")) == NULL ||
592de1ab35cSAlexander Eremin 		    strcmp(tok, BE_CONTAINER_DS_NAME) != 0)
593de1ab35cSAlexander Eremin 			return (NULL);
594f169c0eaSGlenn Lagasse 
595de1ab35cSAlexander Eremin 		/* Return the remaining token if one exists */
596de1ab35cSAlexander Eremin 		if ((tok = strtok(NULL, "")) == NULL)
597de1ab35cSAlexander Eremin 			return (NULL);
598f169c0eaSGlenn Lagasse 
599de1ab35cSAlexander Eremin 		if ((name = strdup(tok)) == NULL) {
600de1ab35cSAlexander Eremin 			be_print_err(gettext("be_make_name_from_ds: "
601de1ab35cSAlexander Eremin 			    "memory allocation failed\n"));
602de1ab35cSAlexander Eremin 			return (NULL);
603de1ab35cSAlexander Eremin 		}
604f169c0eaSGlenn Lagasse 	}
605f169c0eaSGlenn Lagasse 
606f169c0eaSGlenn Lagasse 	return (name);
607f169c0eaSGlenn Lagasse }
608f169c0eaSGlenn Lagasse 
609f169c0eaSGlenn Lagasse /*
610f169c0eaSGlenn Lagasse  * Function:	be_maxsize_avail
611f169c0eaSGlenn Lagasse  * Description:	Returns the available size for the zfs handle passed in.
612f169c0eaSGlenn Lagasse  * Parameters:
613f169c0eaSGlenn Lagasse  *		zhp - A pointer to the open zfs handle.
614f169c0eaSGlenn Lagasse  *		ret - The available size will be returned in this.
615f169c0eaSGlenn Lagasse  * Returns:
616f169c0eaSGlenn Lagasse  *		The error returned by the zfs get property function.
617f169c0eaSGlenn Lagasse  * Scope:
618f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
619f169c0eaSGlenn Lagasse  */
620f169c0eaSGlenn Lagasse int
be_maxsize_avail(zfs_handle_t * zhp,uint64_t * ret)621f169c0eaSGlenn Lagasse be_maxsize_avail(zfs_handle_t *zhp, uint64_t *ret)
622f169c0eaSGlenn Lagasse {
623f169c0eaSGlenn Lagasse 	return ((*ret = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE)));
624f169c0eaSGlenn Lagasse }
625f169c0eaSGlenn Lagasse 
626f169c0eaSGlenn Lagasse /*
627f169c0eaSGlenn Lagasse  * Function:	be_append_menu
628f169c0eaSGlenn Lagasse  * Description:	Appends an entry for a BE into the menu.lst.
629f169c0eaSGlenn Lagasse  * Parameters:
630f169c0eaSGlenn Lagasse  *		be_name - pointer to name of BE to add boot menu entry for.
631f169c0eaSGlenn Lagasse  *		be_root_pool - pointer to name of pool BE lives in.
632f169c0eaSGlenn Lagasse  *		boot_pool - Used if the pool containing the grub menu is
633f169c0eaSGlenn Lagasse  *			    different than the one contaiing the BE. This
634f169c0eaSGlenn Lagasse  *			    will normally be NULL.
635f169c0eaSGlenn Lagasse  *		be_orig_root_ds - The root dataset for the BE. This is
636f169c0eaSGlenn Lagasse  *			used to check to see if an entry already exists
637f169c0eaSGlenn Lagasse  *			for this BE.
638f169c0eaSGlenn Lagasse  *		description - pointer to description of BE to be added in
639f169c0eaSGlenn Lagasse  *			the title line for this BEs entry.
640f169c0eaSGlenn Lagasse  * Returns:
641f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
642f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
643f169c0eaSGlenn Lagasse  * Scope:
644f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
645f169c0eaSGlenn Lagasse  */
646f169c0eaSGlenn Lagasse int
be_append_menu(char * be_name,char * be_root_pool,char * boot_pool,char * be_orig_root_ds,char * description)647f169c0eaSGlenn Lagasse be_append_menu(char *be_name, char *be_root_pool, char *boot_pool,
648f169c0eaSGlenn Lagasse     char *be_orig_root_ds, char *description)
649f169c0eaSGlenn Lagasse {
650f169c0eaSGlenn Lagasse 	zfs_handle_t *zhp = NULL;
651f169c0eaSGlenn Lagasse 	char menu_file[MAXPATHLEN];
652f169c0eaSGlenn Lagasse 	char be_root_ds[MAXPATHLEN];
653f169c0eaSGlenn Lagasse 	char line[BUFSIZ];
654f169c0eaSGlenn Lagasse 	char temp_line[BUFSIZ];
655f169c0eaSGlenn Lagasse 	char title[MAXPATHLEN];
656f169c0eaSGlenn Lagasse 	char *entries[BUFSIZ];
657f169c0eaSGlenn Lagasse 	char *tmp_entries[BUFSIZ];
658f169c0eaSGlenn Lagasse 	char *pool_mntpnt = NULL;
659f169c0eaSGlenn Lagasse 	char *ptmp_mntpnt = NULL;
660f169c0eaSGlenn Lagasse 	char *orig_mntpnt = NULL;
661f169c0eaSGlenn Lagasse 	boolean_t found_be = B_FALSE;
662f169c0eaSGlenn Lagasse 	boolean_t found_orig_be = B_FALSE;
663f169c0eaSGlenn Lagasse 	boolean_t found_title = B_FALSE;
664f169c0eaSGlenn Lagasse 	boolean_t pool_mounted = B_FALSE;
665f169c0eaSGlenn Lagasse 	boolean_t collect_lines = B_FALSE;
666f169c0eaSGlenn Lagasse 	FILE *menu_fp = NULL;
667f169c0eaSGlenn Lagasse 	int err = 0, ret = BE_SUCCESS;
668f169c0eaSGlenn Lagasse 	int i, num_tmp_lines = 0, num_lines = 0;
669f169c0eaSGlenn Lagasse 
670f169c0eaSGlenn Lagasse 	if (be_name == NULL || be_root_pool == NULL)
671f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
672f169c0eaSGlenn Lagasse 
673f169c0eaSGlenn Lagasse 	if (boot_pool == NULL)
674f169c0eaSGlenn Lagasse 		boot_pool = be_root_pool;
675f169c0eaSGlenn Lagasse 
676f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
677f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_append_menu: failed to open "
678f169c0eaSGlenn Lagasse 		    "pool dataset for %s: %s\n"), be_root_pool,
679f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
680f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
681f169c0eaSGlenn Lagasse 	}
682f169c0eaSGlenn Lagasse 
683f169c0eaSGlenn Lagasse 	/*
684f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
685f169c0eaSGlenn Lagasse 	 * attempt to mount it.
686f169c0eaSGlenn Lagasse 	 */
687f169c0eaSGlenn Lagasse 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
688f169c0eaSGlenn Lagasse 	    &pool_mounted)) != BE_SUCCESS) {
689f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_append_menu: pool dataset "
690f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), be_root_pool);
691f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
692f169c0eaSGlenn Lagasse 		return (ret);
693f169c0eaSGlenn Lagasse 	}
694f169c0eaSGlenn Lagasse 
695f169c0eaSGlenn Lagasse 	/*
696f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
697f169c0eaSGlenn Lagasse 	 */
698f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
699f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_append_menu: pool "