xref: /titanic_44/usr/src/lib/libbe/common/be_activate.c (revision 1a902ef8628b0dffd6df5442354ab59bb8530962)
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.
24f169c0eaSGlenn Lagasse  */
25f169c0eaSGlenn Lagasse 
267e0e2549SAlexander Eremin /*
27*1a902ef8SHans Rosenfeld  * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
287e0e2549SAlexander Eremin  */
297e0e2549SAlexander Eremin 
30f169c0eaSGlenn Lagasse #include <assert.h>
31f169c0eaSGlenn Lagasse #include <libintl.h>
32f169c0eaSGlenn Lagasse #include <libnvpair.h>
33f169c0eaSGlenn Lagasse #include <libzfs.h>
34f169c0eaSGlenn Lagasse #include <stdio.h>
35f169c0eaSGlenn Lagasse #include <stdlib.h>
36f169c0eaSGlenn Lagasse #include <string.h>
37*1a902ef8SHans Rosenfeld #include <strings.h>
38f169c0eaSGlenn Lagasse #include <errno.h>
39f169c0eaSGlenn Lagasse #include <sys/mnttab.h>
40f169c0eaSGlenn Lagasse #include <sys/types.h>
41f169c0eaSGlenn Lagasse #include <sys/stat.h>
42*1a902ef8SHans Rosenfeld #include <fcntl.h>
43f169c0eaSGlenn Lagasse #include <unistd.h>
44*1a902ef8SHans Rosenfeld #include <sys/efi_partition.h>
45f169c0eaSGlenn Lagasse 
46f169c0eaSGlenn Lagasse #include <libbe.h>
47f169c0eaSGlenn Lagasse #include <libbe_priv.h>
48f169c0eaSGlenn Lagasse 
49f169c0eaSGlenn Lagasse char	*mnttab = MNTTAB;
50f169c0eaSGlenn Lagasse 
51f169c0eaSGlenn Lagasse /*
52f169c0eaSGlenn Lagasse  * Private function prototypes
53f169c0eaSGlenn Lagasse  */
54f169c0eaSGlenn Lagasse static int set_bootfs(char *boot_rpool, char *be_root_ds);
55f169c0eaSGlenn Lagasse static int set_canmount(be_node_list_t *, char *);
56*1a902ef8SHans Rosenfeld static boolean_t be_do_installgrub_mbr(char *, nvlist_t *);
57*1a902ef8SHans Rosenfeld static int be_do_installgrub_helper(zpool_handle_t *, nvlist_t *, char *,
58*1a902ef8SHans Rosenfeld     char *);
59f169c0eaSGlenn Lagasse static int be_do_installgrub(be_transaction_data_t *);
60f169c0eaSGlenn Lagasse static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
61f169c0eaSGlenn Lagasse static int get_ver_from_capfile(char *, char **);
62f169c0eaSGlenn Lagasse static int be_promote_zone_ds(char *, char *);
63f169c0eaSGlenn Lagasse static int be_promote_ds_callback(zfs_handle_t *, void *);
64f169c0eaSGlenn Lagasse 
65f169c0eaSGlenn Lagasse /* ******************************************************************** */
66f169c0eaSGlenn Lagasse /*			Public Functions				*/
67f169c0eaSGlenn Lagasse /* ******************************************************************** */
68f169c0eaSGlenn Lagasse 
69f169c0eaSGlenn Lagasse /*
70f169c0eaSGlenn Lagasse  * Function:	be_activate
71f169c0eaSGlenn Lagasse  * Description:	Calls _be_activate which activates the BE named in the
72f169c0eaSGlenn Lagasse  *		attributes passed in through be_attrs. The process of
73f169c0eaSGlenn Lagasse  *		activation sets the bootfs property of the root pool, resets
74f169c0eaSGlenn Lagasse  *		the canmount property to noauto, and sets the default in the
75f169c0eaSGlenn Lagasse  *		grub menu to the entry corresponding to the entry for the named
76f169c0eaSGlenn Lagasse  *		BE.
77f169c0eaSGlenn Lagasse  * Parameters:
78f169c0eaSGlenn Lagasse  *		be_attrs - pointer to nvlist_t of attributes being passed in.
79f169c0eaSGlenn Lagasse  *			The follow attribute values are used by this function:
80f169c0eaSGlenn Lagasse  *
81f169c0eaSGlenn Lagasse  *			BE_ATTR_ORIG_BE_NAME		*required
82f169c0eaSGlenn Lagasse  * Return:
83f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
84f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
85f169c0eaSGlenn Lagasse  * Scope:
86f169c0eaSGlenn Lagasse  *		Public
87f169c0eaSGlenn Lagasse  */
88f169c0eaSGlenn Lagasse int
be_activate(nvlist_t * be_attrs)89f169c0eaSGlenn Lagasse be_activate(nvlist_t *be_attrs)
90f169c0eaSGlenn Lagasse {
91f169c0eaSGlenn Lagasse 	int	ret = BE_SUCCESS;
92f169c0eaSGlenn Lagasse 	char	*be_name = NULL;
93f169c0eaSGlenn Lagasse 
94f169c0eaSGlenn Lagasse 	/* Initialize libzfs handle */
95f169c0eaSGlenn Lagasse 	if (!be_zfs_init())
96f169c0eaSGlenn Lagasse 		return (BE_ERR_INIT);
97f169c0eaSGlenn Lagasse 
98f169c0eaSGlenn Lagasse 	/* Get the BE name to activate */
99f169c0eaSGlenn Lagasse 	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
100f169c0eaSGlenn Lagasse 	    != 0) {
101f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_activate: failed to "
102f169c0eaSGlenn Lagasse 		    "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
103f169c0eaSGlenn Lagasse 		be_zfs_fini();
104f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
105f169c0eaSGlenn Lagasse 	}
106f169c0eaSGlenn Lagasse 
107f169c0eaSGlenn Lagasse 	/* Validate BE name */
108f169c0eaSGlenn Lagasse 	if (!be_valid_be_name(be_name)) {
109f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_activate: invalid BE name %s\n"),
110f169c0eaSGlenn Lagasse 		    be_name);
111f169c0eaSGlenn Lagasse 		be_zfs_fini();
112f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
113f169c0eaSGlenn Lagasse 	}
114f169c0eaSGlenn Lagasse 
115f169c0eaSGlenn Lagasse 	ret = _be_activate(be_name);
116f169c0eaSGlenn Lagasse 
117f169c0eaSGlenn Lagasse 	be_zfs_fini();
118f169c0eaSGlenn Lagasse 
119f169c0eaSGlenn Lagasse 	return (ret);
120f169c0eaSGlenn Lagasse }
121f169c0eaSGlenn Lagasse 
122f169c0eaSGlenn Lagasse /* ******************************************************************** */
123f169c0eaSGlenn Lagasse /*			Semi Private Functions				*/
124f169c0eaSGlenn Lagasse /* ******************************************************************** */
125f169c0eaSGlenn Lagasse 
126f169c0eaSGlenn Lagasse /*
127f169c0eaSGlenn Lagasse  * Function:	_be_activate
128f169c0eaSGlenn Lagasse  * Description:	This does the actual work described in be_activate.
129f169c0eaSGlenn Lagasse  * Parameters:
130f169c0eaSGlenn Lagasse  *		be_name - pointer to the name of BE to activate.
131f169c0eaSGlenn Lagasse  *
132f169c0eaSGlenn Lagasse  * Return:
133f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
134f169c0eaSGlenn Lagasse  *		be_errnot_t - Failure
135f169c0eaSGlenn Lagasse  * Scope:
136f169c0eaSGlenn Lagasse  *		Public
137f169c0eaSGlenn Lagasse  */
138f169c0eaSGlenn Lagasse int
_be_activate(char * be_name)139f169c0eaSGlenn Lagasse _be_activate(char *be_name)
140f169c0eaSGlenn Lagasse {
141f169c0eaSGlenn Lagasse 	be_transaction_data_t cb = { 0 };
142f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
143f169c0eaSGlenn Lagasse 	char		root_ds[MAXPATHLEN];
1447e0e2549SAlexander Eremin 	char		active_ds[MAXPATHLEN];
145f169c0eaSGlenn Lagasse 	char		*cur_vers = NULL, *new_vers = NULL;
146f169c0eaSGlenn Lagasse 	be_node_list_t	*be_nodes = NULL;
147f169c0eaSGlenn Lagasse 	uuid_t		uu = {0};
148f169c0eaSGlenn Lagasse 	int		entry, ret = BE_SUCCESS;
149f169c0eaSGlenn Lagasse 	int		zret = 0;
150f169c0eaSGlenn Lagasse 
151f169c0eaSGlenn Lagasse 	/*
152f169c0eaSGlenn Lagasse 	 * TODO: The BE needs to be validated to make sure that it is actually
153f169c0eaSGlenn Lagasse 	 * a bootable BE.
154f169c0eaSGlenn Lagasse 	 */
155f169c0eaSGlenn Lagasse 
156f169c0eaSGlenn Lagasse 	if (be_name == NULL)
157f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
158f169c0eaSGlenn Lagasse 
159f169c0eaSGlenn Lagasse 	/* Set obe_name to be_name in the cb structure */
160f169c0eaSGlenn Lagasse 	cb.obe_name = be_name;
161f169c0eaSGlenn Lagasse 
162f169c0eaSGlenn Lagasse 	/* find which zpool the be is in */
163f169c0eaSGlenn Lagasse 	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
164f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_activate: failed to "
165f169c0eaSGlenn Lagasse 		    "find zpool for BE (%s)\n"), cb.obe_name);
166f169c0eaSGlenn Lagasse 		return (BE_ERR_BE_NOENT);
167f169c0eaSGlenn Lagasse 	} else if (zret < 0) {
168f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_activate: "
169f169c0eaSGlenn Lagasse 		    "zpool_iter failed: %s\n"),
170f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
171f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
172f169c0eaSGlenn Lagasse 		return (ret);
173f169c0eaSGlenn Lagasse 	}
174f169c0eaSGlenn Lagasse 
175f169c0eaSGlenn Lagasse 	be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
176f169c0eaSGlenn Lagasse 	cb.obe_root_ds = strdup(root_ds);
177f169c0eaSGlenn Lagasse 
178f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID) {
179f169c0eaSGlenn Lagasse 		if (be_has_grub() && (ret = be_get_grub_vers(&cb, &cur_vers,
180f169c0eaSGlenn Lagasse 		    &new_vers)) != BE_SUCCESS) {
181f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_activate: failed to get grub "
182f169c0eaSGlenn Lagasse 			    "versions from capability files.\n"));
183f169c0eaSGlenn Lagasse 			return (ret);
184f169c0eaSGlenn Lagasse 		}
185f169c0eaSGlenn Lagasse 		if (cur_vers != NULL) {
186f169c0eaSGlenn Lagasse 			/*
187f169c0eaSGlenn Lagasse 			 * We need to check to see if the version number from
188f169c0eaSGlenn Lagasse 			 * the BE being activated is greater than the current
189f169c0eaSGlenn Lagasse 			 * one.
190f169c0eaSGlenn Lagasse 			 */
191f169c0eaSGlenn Lagasse 			if (new_vers != NULL &&
192f169c0eaSGlenn Lagasse 			    atof(cur_vers) < atof(new_vers)) {
193f169c0eaSGlenn Lagasse 				if ((ret = be_do_installgrub(&cb))
194f169c0eaSGlenn Lagasse 				    != BE_SUCCESS) {
195f169c0eaSGlenn Lagasse 					free(new_vers);
196f169c0eaSGlenn Lagasse 					free(cur_vers);
197f169c0eaSGlenn Lagasse 					return (ret);
198f169c0eaSGlenn Lagasse 				}
199f169c0eaSGlenn Lagasse 				free(new_vers);
200f169c0eaSGlenn Lagasse 			}
201f169c0eaSGlenn Lagasse 			free(cur_vers);
202f169c0eaSGlenn Lagasse 		} else if (new_vers != NULL) {
203f169c0eaSGlenn Lagasse 			if ((ret = be_do_installgrub(&cb)) != BE_SUCCESS) {
204f169c0eaSGlenn Lagasse 				free(new_vers);
205f169c0eaSGlenn Lagasse 				return (ret);
206f169c0eaSGlenn Lagasse 			}
207f169c0eaSGlenn Lagasse 			free(new_vers);
208f169c0eaSGlenn Lagasse 		}
209f169c0eaSGlenn Lagasse 		if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
210f169c0eaSGlenn Lagasse 			if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
211f169c0eaSGlenn Lagasse 			    NULL, NULL, NULL)) != BE_SUCCESS) {
212f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_activate: Failed to "
213f169c0eaSGlenn Lagasse 				    "add BE (%s) to the GRUB menu\n"),
214f169c0eaSGlenn Lagasse 				    cb.obe_name);
215f169c0eaSGlenn Lagasse 				goto done;
216f169c0eaSGlenn Lagasse 			}
217f169c0eaSGlenn Lagasse 		}
218f169c0eaSGlenn Lagasse 		if (be_has_grub()) {
219f169c0eaSGlenn Lagasse 			if ((ret = be_change_grub_default(cb.obe_name,
220f169c0eaSGlenn Lagasse 			    cb.obe_zpool)) != BE_SUCCESS) {
221f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_activate: failed to "
222f169c0eaSGlenn Lagasse 				    "change the default entry in menu.lst\n"));
223f169c0eaSGlenn Lagasse 				goto done;
224f169c0eaSGlenn Lagasse 			}
225f169c0eaSGlenn Lagasse 		}
226f169c0eaSGlenn Lagasse 	}
227f169c0eaSGlenn Lagasse 
228f169c0eaSGlenn Lagasse 	if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
229f169c0eaSGlenn Lagasse 		return (ret);
230f169c0eaSGlenn Lagasse 	}
231f169c0eaSGlenn Lagasse 
232f169c0eaSGlenn Lagasse 	if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
233f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_activate: failed to set "
234f169c0eaSGlenn Lagasse 		    "canmount dataset property\n"));
235f169c0eaSGlenn Lagasse 		goto done;
236f169c0eaSGlenn Lagasse 	}
237f169c0eaSGlenn Lagasse 
2387e0e2549SAlexander Eremin 	if (getzoneid() == GLOBAL_ZONEID) {
2397e0e2549SAlexander Eremin 		if ((ret = set_bootfs(be_nodes->be_rpool,
2407e0e2549SAlexander Eremin 		    root_ds)) != BE_SUCCESS) {
241f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_activate: failed to set "
242f169c0eaSGlenn Lagasse 			    "bootfs pool property for %s\n"), root_ds);
243f169c0eaSGlenn Lagasse 			goto done;
244f169c0eaSGlenn Lagasse 		}
2457e0e2549SAlexander Eremin 	}
246f169c0eaSGlenn Lagasse 
247f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
248f169c0eaSGlenn Lagasse 		/*
249f169c0eaSGlenn Lagasse 		 * We don't need to close the zfs handle at this
250f169c0eaSGlenn Lagasse 		 * point because The callback funtion
251f169c0eaSGlenn Lagasse 		 * be_promote_ds_callback() will close it for us.
252f169c0eaSGlenn Lagasse 		 */
253f169c0eaSGlenn Lagasse 		if (be_promote_ds_callback(zhp, NULL) != 0) {
254f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_activate: "
255f169c0eaSGlenn Lagasse 			    "failed to activate the "
256f169c0eaSGlenn Lagasse 			    "datasets for %s: %s\n"),
257f169c0eaSGlenn Lagasse 			    root_ds,
258f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
259f169c0eaSGlenn Lagasse 			ret = BE_ERR_PROMOTE;
260f169c0eaSGlenn Lagasse 			goto done;
261f169c0eaSGlenn Lagasse 		}
262f169c0eaSGlenn Lagasse 	} else {
2637e0e2549SAlexander Eremin 		be_print_err(gettext("be_activate: failed to open "
264f169c0eaSGlenn Lagasse 		    "dataset (%s): %s\n"), root_ds,
265f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
266f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
267f169c0eaSGlenn Lagasse 		goto done;
268f169c0eaSGlenn Lagasse 	}
269f169c0eaSGlenn Lagasse 
270f169c0eaSGlenn Lagasse 	if (getzoneid() == GLOBAL_ZONEID &&
271f169c0eaSGlenn Lagasse 	    be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
272f169c0eaSGlenn Lagasse 	    (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
273f169c0eaSGlenn Lagasse 	    != BE_SUCCESS) {
274f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_activate: failed to promote "
275f169c0eaSGlenn Lagasse 		    "the active zonepath datasets for zones in BE %s\n"),
276f169c0eaSGlenn Lagasse 		    cb.obe_name);
277f169c0eaSGlenn Lagasse 	}
278f169c0eaSGlenn Lagasse 
2797e0e2549SAlexander Eremin 	if (getzoneid() != GLOBAL_ZONEID) {
2807e0e2549SAlexander Eremin 		if (!be_zone_compare_uuids(root_ds)) {
2817e0e2549SAlexander Eremin 			be_print_err(gettext("be_activate: activating zone "
2827e0e2549SAlexander Eremin 			    "root dataset from non-active global BE is not "
2837e0e2549SAlexander Eremin 			    "supported\n"));
2847e0e2549SAlexander Eremin 			ret = BE_ERR_NOTSUP;
2857e0e2549SAlexander Eremin 			goto done;
2867e0e2549SAlexander Eremin 		}
2877e0e2549SAlexander Eremin 		if ((zhp = zfs_open(g_zfs, root_ds,
2887e0e2549SAlexander Eremin 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
2897e0e2549SAlexander Eremin 			be_print_err(gettext("be_activate: failed to open "
2907e0e2549SAlexander Eremin 			    "dataset (%s): %s\n"), root_ds,
2917e0e2549SAlexander Eremin 			    libzfs_error_description(g_zfs));
2927e0e2549SAlexander Eremin 			ret = zfs_err_to_be_err(g_zfs);
2937e0e2549SAlexander Eremin 			goto done;
2947e0e2549SAlexander Eremin 		}
2957e0e2549SAlexander Eremin 		/* Find current active zone root dataset */
2967e0e2549SAlexander Eremin 		if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
2977e0e2549SAlexander Eremin 		    active_ds, sizeof (active_ds))) != BE_SUCCESS) {
2987e0e2549SAlexander Eremin 			be_print_err(gettext("be_activate: failed to find "
2997e0e2549SAlexander Eremin 			    "active zone root dataset\n"));
3007e0e2549SAlexander Eremin 			ZFS_CLOSE(zhp);
3017e0e2549SAlexander Eremin 			goto done;
3027e0e2549SAlexander Eremin 		}
3037e0e2549SAlexander Eremin 		/* Do nothing if requested BE is already active */
3047e0e2549SAlexander Eremin 		if (strcmp(root_ds, active_ds) == 0) {
3057e0e2549SAlexander Eremin 			ret = BE_SUCCESS;
3067e0e2549SAlexander Eremin 			ZFS_CLOSE(zhp);
3077e0e2549SAlexander Eremin 			goto done;
3087e0e2549SAlexander Eremin 		}
3097e0e2549SAlexander Eremin 
3107e0e2549SAlexander Eremin 		/* Set active property for BE */
3117e0e2549SAlexander Eremin 		if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
3127e0e2549SAlexander Eremin 			be_print_err(gettext("be_activate: failed to set "
3137e0e2549SAlexander Eremin 			    "active property (%s): %s\n"), root_ds,
3147e0e2549SAlexander Eremin 			    libzfs_error_description(g_zfs));
3157e0e2549SAlexander Eremin 			ret = zfs_err_to_be_err(g_zfs);
3167e0e2549SAlexander Eremin 			ZFS_CLOSE(zhp);
3177e0e2549SAlexander Eremin 			goto done;
3187e0e2549SAlexander Eremin 		}
3197e0e2549SAlexander Eremin 		ZFS_CLOSE(zhp);
3207e0e2549SAlexander Eremin 
3217e0e2549SAlexander Eremin 		/* Unset active property for old active root dataset */
3227e0e2549SAlexander Eremin 		if ((zhp = zfs_open(g_zfs, active_ds,
3237e0e2549SAlexander Eremin 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
3247e0e2549SAlexander Eremin 			be_print_err(gettext("be_activate: failed to open "
3257e0e2549SAlexander Eremin 			    "dataset (%s): %s\n"), active_ds,
3267e0e2549SAlexander Eremin 			    libzfs_error_description(g_zfs));
3277e0e2549SAlexander Eremin 			ret = zfs_err_to_be_err(g_zfs);
3287e0e2549SAlexander Eremin 			goto done;
3297e0e2549SAlexander Eremin 		}
3307e0e2549SAlexander Eremin 		if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
3317e0e2549SAlexander Eremin 			be_print_err(gettext("be_activate: failed to unset "
3327e0e2549SAlexander Eremin 			    "active property (%s): %s\n"), active_ds,
3337e0e2549SAlexander Eremin 			    libzfs_error_description(g_zfs));
3347e0e2549SAlexander Eremin 			ret = zfs_err_to_be_err(g_zfs);
3357e0e2549SAlexander Eremin 			ZFS_CLOSE(zhp);
3367e0e2549SAlexander Eremin 			goto done;
3377e0e2549SAlexander Eremin 		}
3387e0e2549SAlexander Eremin 		ZFS_CLOSE(zhp);
3397e0e2549SAlexander Eremin 	}
340f169c0eaSGlenn Lagasse done:
341f169c0eaSGlenn Lagasse 	be_free_list(be_nodes);
342f169c0eaSGlenn Lagasse 	return (ret);
343f169c0eaSGlenn Lagasse }
344f169c0eaSGlenn Lagasse 
345f169c0eaSGlenn Lagasse /*
346f169c0eaSGlenn Lagasse  * Function:	be_activate_current_be
347f169c0eaSGlenn Lagasse  * Description:	Set the currently "active" BE to be "active on boot"
348f169c0eaSGlenn Lagasse  * Paramters:
349f169c0eaSGlenn Lagasse  *		none
350f169c0eaSGlenn Lagasse  * Returns:
351f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
352f169c0eaSGlenn Lagasse  *		be_errnot_t - Failure
353f169c0eaSGlenn Lagasse  * Scope:
354f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
355f169c0eaSGlenn Lagasse  */
356f169c0eaSGlenn Lagasse int
be_activate_current_be(void)357f169c0eaSGlenn Lagasse be_activate_current_be(void)
358f169c0eaSGlenn Lagasse {
359f169c0eaSGlenn Lagasse 	int ret = BE_SUCCESS;
360f169c0eaSGlenn Lagasse 	be_transaction_data_t bt = { 0 };
361f169c0eaSGlenn Lagasse 
362f169c0eaSGlenn Lagasse 	if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
363f169c0eaSGlenn Lagasse 		return (ret);
364f169c0eaSGlenn Lagasse 	}
365f169c0eaSGlenn Lagasse 
366f169c0eaSGlenn Lagasse 	if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
367f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_activate_current_be: failed to "
368f169c0eaSGlenn Lagasse 		    "activate %s\n"), bt.obe_name);
369f169c0eaSGlenn Lagasse 		return (ret);
370f169c0eaSGlenn Lagasse 	}
371f169c0eaSGlenn Lagasse 
372f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
373f169c0eaSGlenn Lagasse }
374f169c0eaSGlenn Lagasse 
375f169c0eaSGlenn Lagasse /*
376f169c0eaSGlenn Lagasse  * Function:	be_is_active_on_boot
377f169c0eaSGlenn Lagasse  * Description:	Checks if the BE name passed in has the "active on boot"
378f169c0eaSGlenn Lagasse  *		property set to B_TRUE.
379f169c0eaSGlenn Lagasse  * Paramters:
380f169c0eaSGlenn Lagasse  *		be_name - the name of the BE to check
381f169c0eaSGlenn Lagasse  * Returns:
382f169c0eaSGlenn Lagasse  *		B_TRUE - if active on boot.
383f169c0eaSGlenn Lagasse  *		B_FALSE - if not active on boot.
384f169c0eaSGlenn Lagasse  * Scope:
385f169c0eaSGlenn Lagasse  *		Semi-private (library wide use only)
386f169c0eaSGlenn Lagasse  */
387f169c0eaSGlenn Lagasse boolean_t
be_is_active_on_boot(char * be_name)388f169c0eaSGlenn Lagasse be_is_active_on_boot(char *be_name)
389f169c0eaSGlenn Lagasse {
390f169c0eaSGlenn Lagasse 	be_node_list_t *be_node = NULL;
391f169c0eaSGlenn Lagasse 
392f169c0eaSGlenn Lagasse 	if (be_name == NULL) {
393f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_is_active_on_boot: "
394f169c0eaSGlenn Lagasse 		    "be_name must not be NULL\n"));
395f169c0eaSGlenn Lagasse 		return (B_FALSE);
396f169c0eaSGlenn Lagasse 	}
397f169c0eaSGlenn Lagasse 
398f169c0eaSGlenn Lagasse 	if (_be_list(be_name, &be_node) != BE_SUCCESS) {
399f169c0eaSGlenn Lagasse 		return (B_FALSE);
400f169c0eaSGlenn Lagasse 	}
401f169c0eaSGlenn Lagasse 
402f169c0eaSGlenn Lagasse 	if (be_node == NULL) {
403f169c0eaSGlenn Lagasse 		return (B_FALSE);
404f169c0eaSGlenn Lagasse 	}
405f169c0eaSGlenn Lagasse 
406f169c0eaSGlenn Lagasse 	if (be_node->be_active_on_boot) {
407f169c0eaSGlenn Lagasse 		be_free_list(be_node);
408f169c0eaSGlenn Lagasse 		return (B_TRUE);
409f169c0eaSGlenn Lagasse 	} else {
410f169c0eaSGlenn Lagasse 		be_free_list(be_node);
411f169c0eaSGlenn Lagasse 		return (B_FALSE);
412f169c0eaSGlenn Lagasse 	}
413f169c0eaSGlenn Lagasse }
414f169c0eaSGlenn Lagasse 
415f169c0eaSGlenn Lagasse /* ******************************************************************** */
416f169c0eaSGlenn Lagasse /*			Private Functions				*/
417f169c0eaSGlenn Lagasse /* ******************************************************************** */
418f169c0eaSGlenn Lagasse 
419f169c0eaSGlenn Lagasse /*
420f169c0eaSGlenn Lagasse  * Function:	set_bootfs
421f169c0eaSGlenn Lagasse  * Description:	Sets the bootfs property on the boot pool to be the
422f169c0eaSGlenn Lagasse  *		root dataset of the activated BE.
423f169c0eaSGlenn Lagasse  * Parameters:
424f169c0eaSGlenn Lagasse  *		boot_pool - The pool we're setting bootfs in.
425f169c0eaSGlenn Lagasse  *		be_root_ds - The main dataset for the BE.
426f169c0eaSGlenn Lagasse  * Return:
427f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
428f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
429f169c0eaSGlenn Lagasse  * Scope:
430f169c0eaSGlenn Lagasse  *		Private
431f169c0eaSGlenn Lagasse  */
432f169c0eaSGlenn Lagasse static int
set_bootfs(char * boot_rpool,char * be_root_ds)433f169c0eaSGlenn Lagasse set_bootfs(char *boot_rpool, char *be_root_ds)
434f169c0eaSGlenn Lagasse {
435f169c0eaSGlenn Lagasse 	zpool_handle_t *zhp;
436f169c0eaSGlenn Lagasse 	int err = BE_SUCCESS;
437f169c0eaSGlenn Lagasse 
438f169c0eaSGlenn Lagasse 	if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
439f169c0eaSGlenn Lagasse 		be_print_err(gettext("set_bootfs: failed to open pool "
440f169c0eaSGlenn Lagasse 		    "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
441f169c0eaSGlenn Lagasse 		err = zfs_err_to_be_err(g_zfs);
442f169c0eaSGlenn Lagasse 		return (err);
443f169c0eaSGlenn Lagasse 	}
444f169c0eaSGlenn Lagasse 
445f169c0eaSGlenn Lagasse 	err = zpool_set_prop(zhp, "bootfs", be_root_ds);
446f169c0eaSGlenn Lagasse 	if (err) {
447f169c0eaSGlenn Lagasse 		be_print_err(gettext("set_bootfs: failed to set "
448f169c0eaSGlenn Lagasse 		    "bootfs property for pool %s: %s\n"), boot_rpool,
449f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
450f169c0eaSGlenn Lagasse 		err = zfs_err_to_be_err(g_zfs);
451f169c0eaSGlenn Lagasse 		zpool_close(zhp);
452f169c0eaSGlenn Lagasse 		return (err);
453f169c0eaSGlenn Lagasse 	}
454f169c0eaSGlenn Lagasse 
455f169c0eaSGlenn Lagasse 	zpool_close(zhp);
456f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
457f169c0eaSGlenn Lagasse }
458f169c0eaSGlenn Lagasse 
459f169c0eaSGlenn Lagasse /*
460f169c0eaSGlenn Lagasse  * Function:	set_canmount
461f169c0eaSGlenn Lagasse  * Description:	Sets the canmount property on the datasets of the
462f169c0eaSGlenn Lagasse  *		activated BE.
463f169c0eaSGlenn Lagasse  * Parameters:
464f169c0eaSGlenn Lagasse  *		be_nodes - The be_node_t returned from be_list
465f169c0eaSGlenn Lagasse  *		value - The value of canmount we setting, on|off|noauto.
466f169c0eaSGlenn Lagasse  * Return:
467f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
468f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
469f169c0eaSGlenn Lagasse  * Scope:
470f169c0eaSGlenn Lagasse  *		Private
471f169c0eaSGlenn Lagasse  */
472f169c0eaSGlenn Lagasse static int
set_canmount(be_node_list_t * be_nodes,char * value)473f169c0eaSGlenn Lagasse set_canmount(be_node_list_t *be_nodes, char *value)
474f169c0eaSGlenn Lagasse {
475f169c0eaSGlenn Lagasse 	char		ds_path[MAXPATHLEN];
476f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
477f169c0eaSGlenn Lagasse 	be_node_list_t	*list = be_nodes;
478f169c0eaSGlenn Lagasse 	int		err = BE_SUCCESS;
479f169c0eaSGlenn Lagasse 
480f169c0eaSGlenn Lagasse 	while (list != NULL) {
481f169c0eaSGlenn Lagasse 		be_dataset_list_t *datasets = list->be_node_datasets;
482f169c0eaSGlenn Lagasse 
483f169c0eaSGlenn Lagasse 		be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
484f169c0eaSGlenn Lagasse 		    sizeof (ds_path));
485f169c0eaSGlenn Lagasse 
486f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
487f169c0eaSGlenn Lagasse 		    NULL) {
488f169c0eaSGlenn Lagasse 			be_print_err(gettext("set_canmount: failed to open "
489f169c0eaSGlenn Lagasse 			    "dataset (%s): %s\n"), ds_path,
490f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
491f169c0eaSGlenn Lagasse 			err = zfs_err_to_be_err(g_zfs);
492f169c0eaSGlenn Lagasse 			return (err);
493f169c0eaSGlenn Lagasse 		}
494f169c0eaSGlenn Lagasse 		if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
495f169c0eaSGlenn Lagasse 			/*
496f169c0eaSGlenn Lagasse 			 * it's already mounted so we can't change the
497f169c0eaSGlenn Lagasse 			 * canmount property anyway.
498f169c0eaSGlenn Lagasse 			 */
499f169c0eaSGlenn Lagasse 			err = BE_SUCCESS;
500f169c0eaSGlenn Lagasse 		} else {
501f169c0eaSGlenn Lagasse 			err = zfs_prop_set(zhp,
502f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
503f169c0eaSGlenn Lagasse 			if (err) {
504f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
505f169c0eaSGlenn Lagasse 				be_print_err(gettext("set_canmount: failed to "
506f169c0eaSGlenn Lagasse 				    "set dataset property (%s): %s\n"),
507f169c0eaSGlenn Lagasse 				    ds_path, libzfs_error_description(g_zfs));
508f169c0eaSGlenn Lagasse 				err = zfs_err_to_be_err(g_zfs);
509f169c0eaSGlenn Lagasse 				return (err);
510f169c0eaSGlenn Lagasse 			}
511f169c0eaSGlenn Lagasse 		}
512f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
513f169c0eaSGlenn Lagasse 
514f169c0eaSGlenn Lagasse 		while (datasets != NULL) {
515f169c0eaSGlenn Lagasse 			be_make_root_ds(list->be_rpool,
516f169c0eaSGlenn Lagasse 			    datasets->be_dataset_name, ds_path,
517f169c0eaSGlenn Lagasse 			    sizeof (ds_path));
518f169c0eaSGlenn Lagasse 
519f169c0eaSGlenn Lagasse 			if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
520f169c0eaSGlenn Lagasse 			    == NULL) {
521f169c0eaSGlenn Lagasse 				be_print_err(gettext("set_canmount: failed to "
522f169c0eaSGlenn Lagasse 				    "open dataset %s: %s\n"), ds_path,
523f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
524f169c0eaSGlenn Lagasse 				err = zfs_err_to_be_err(g_zfs);
525f169c0eaSGlenn Lagasse 				return (err);
526f169c0eaSGlenn Lagasse 			}
527f169c0eaSGlenn Lagasse 			if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
528f169c0eaSGlenn Lagasse 				/*
529f169c0eaSGlenn Lagasse 				 * it's already mounted so we can't change the
530f169c0eaSGlenn Lagasse 				 * canmount property anyway.
531f169c0eaSGlenn Lagasse 				 */
532f169c0eaSGlenn Lagasse 				err = BE_SUCCESS;
533f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
534f169c0eaSGlenn Lagasse 				break;
535f169c0eaSGlenn Lagasse 			}
536f169c0eaSGlenn Lagasse 			err = zfs_prop_set(zhp,
537f169c0eaSGlenn Lagasse 			    zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
538f169c0eaSGlenn Lagasse 			if (err) {
539f169c0eaSGlenn Lagasse 				ZFS_CLOSE(zhp);
540f169c0eaSGlenn Lagasse 				be_print_err(gettext("set_canmount: "
541f169c0eaSGlenn Lagasse 				    "Failed to set property value %s "
542f169c0eaSGlenn Lagasse 				    "for dataset %s: %s\n"), value, ds_path,
543f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
544f169c0eaSGlenn Lagasse 				err = zfs_err_to_be_err(g_zfs);
545f169c0eaSGlenn Lagasse 				return (err);
546f169c0eaSGlenn Lagasse 			}
547f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
548f169c0eaSGlenn Lagasse 			datasets = datasets->be_next_dataset;
549f169c0eaSGlenn Lagasse 		}
550f169c0eaSGlenn Lagasse 		list = list->be_next_node;
551f169c0eaSGlenn Lagasse 	}
552f169c0eaSGlenn Lagasse 	return (err);
553f169c0eaSGlenn Lagasse }
554f169c0eaSGlenn Lagasse 
555f169c0eaSGlenn Lagasse /*
556f169c0eaSGlenn Lagasse  * Function:	be_get_grub_vers
557f169c0eaSGlenn Lagasse  * Description:	Gets the grub version number from /boot/grub/capability. If
558f169c0eaSGlenn Lagasse  *              capability file doesn't exist NULL is returned.
559f169c0eaSGlenn Lagasse  * Parameters:
560f169c0eaSGlenn Lagasse  *              bt - The transaction data for the BE we're getting the grub
561f169c0eaSGlenn Lagasse  *                   version for.
562f169c0eaSGlenn Lagasse  *              cur_vers - used to return the current version of grub from
563f169c0eaSGlenn Lagasse  *                         the root pool.
564f169c0eaSGlenn Lagasse  *              new_vers - used to return the grub version of the BE we're
565f169c0eaSGlenn Lagasse  *                         activating.
566f169c0eaSGlenn Lagasse  * Return:
567f169c0eaSGlenn Lagasse  *              BE_SUCCESS - Success
568f169c0eaSGlenn Lagasse  *              be_errno_t - Failed to find version
569f169c0eaSGlenn Lagasse  * Scope:
570f169c0eaSGlenn Lagasse  *		Private
571f169c0eaSGlenn Lagasse  */
572f169c0eaSGlenn Lagasse static int
be_get_grub_vers(be_transaction_data_t * bt,char ** cur_vers,char ** new_vers)573f169c0eaSGlenn Lagasse be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
574f169c0eaSGlenn Lagasse {
575f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
576f169c0eaSGlenn Lagasse 	zfs_handle_t	*pool_zhp = NULL;
577f169c0eaSGlenn Lagasse 	int ret = BE_SUCCESS;
578f169c0eaSGlenn Lagasse 	char cap_file[MAXPATHLEN];
579f169c0eaSGlenn Lagasse 	char *temp_mntpnt = NULL;
580f169c0eaSGlenn Lagasse 	char *zpool_mntpt = NULL;
581f169c0eaSGlenn Lagasse 	char *ptmp_mntpnt = NULL;
582f169c0eaSGlenn Lagasse 	char *orig_mntpnt = NULL;
583f169c0eaSGlenn Lagasse 	boolean_t be_mounted = B_FALSE;
584f169c0eaSGlenn Lagasse 	boolean_t pool_mounted = B_FALSE;
585f169c0eaSGlenn Lagasse 
586f169c0eaSGlenn Lagasse 	if (!be_has_grub()) {
587f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_grub_vers: Not supported on "
588f169c0eaSGlenn Lagasse 		    "this architecture\n"));
589f169c0eaSGlenn Lagasse 		return (BE_ERR_NOTSUP);
590f169c0eaSGlenn Lagasse 	}
591f169c0eaSGlenn Lagasse 
592f169c0eaSGlenn Lagasse 	if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
593f169c0eaSGlenn Lagasse 	    bt->obe_root_ds == NULL) {
594f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
595f169c0eaSGlenn Lagasse 		return (BE_ERR_INVAL);
596f169c0eaSGlenn Lagasse 	}
597f169c0eaSGlenn Lagasse 
598f169c0eaSGlenn Lagasse 	if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
599f169c0eaSGlenn Lagasse 	    NULL) {
600f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
601f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
602f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
603f169c0eaSGlenn Lagasse 	}
604f169c0eaSGlenn Lagasse 
605f169c0eaSGlenn Lagasse 	/*
606f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
607f169c0eaSGlenn Lagasse 	 * attempt to mount it.
608f169c0eaSGlenn Lagasse 	 */
609f169c0eaSGlenn Lagasse 	if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
610f169c0eaSGlenn Lagasse 	    &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
611f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_grub_vers: pool dataset "
612f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), bt->obe_zpool);
613f169c0eaSGlenn Lagasse 		ZFS_CLOSE(pool_zhp);
614f169c0eaSGlenn Lagasse 		return (ret);
615f169c0eaSGlenn Lagasse 	}
616f169c0eaSGlenn Lagasse 
617f169c0eaSGlenn Lagasse 	/*
618f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
619f169c0eaSGlenn Lagasse 	 */
620f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
621f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_grub_vers: pool "
622f169c0eaSGlenn Lagasse 		    "dataset (%s) is not mounted. Can't set the "
623f169c0eaSGlenn Lagasse 		    "default BE in the grub menu.\n"), bt->obe_zpool);
624f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
625f169c0eaSGlenn Lagasse 		goto cleanup;
626f169c0eaSGlenn Lagasse 	}
627f169c0eaSGlenn Lagasse 
628f169c0eaSGlenn Lagasse 	/*
629f169c0eaSGlenn Lagasse 	 * get the version of the most recent grub update.
630f169c0eaSGlenn Lagasse 	 */
631f169c0eaSGlenn Lagasse 	(void) snprintf(cap_file, sizeof (cap_file), "%s%s",
632f169c0eaSGlenn Lagasse 	    zpool_mntpt, BE_CAP_FILE);
633f169c0eaSGlenn Lagasse 	free(zpool_mntpt);
634f169c0eaSGlenn Lagasse 	zpool_mntpt = NULL;
635f169c0eaSGlenn Lagasse 
636f169c0eaSGlenn Lagasse 	if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
637f169c0eaSGlenn Lagasse 		goto cleanup;
638f169c0eaSGlenn Lagasse 
639f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
640f169c0eaSGlenn Lagasse 	    NULL) {
641f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_get_grub_vers: failed to "
642f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
643f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
644f169c0eaSGlenn Lagasse 		free(cur_vers);
645f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
646f169c0eaSGlenn Lagasse 		goto cleanup;
647f169c0eaSGlenn Lagasse 	}
648f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
649f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
650f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
651f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_get_grub_vers: failed to "
652f169c0eaSGlenn Lagasse 			    "mount BE (%s)\n"), bt->obe_name);
653f169c0eaSGlenn Lagasse 			free(*cur_vers);
654f169c0eaSGlenn Lagasse 			*cur_vers = NULL;
655f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
656f169c0eaSGlenn Lagasse 			goto cleanup;
657f169c0eaSGlenn Lagasse 		}
658f169c0eaSGlenn Lagasse 		be_mounted = B_TRUE;
659f169c0eaSGlenn Lagasse 	}
660f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
661f169c0eaSGlenn Lagasse 
662f169c0eaSGlenn Lagasse 	/*
663f169c0eaSGlenn Lagasse 	 * Now get the grub version for the BE being activated.
664f169c0eaSGlenn Lagasse 	 */
665f169c0eaSGlenn Lagasse 	(void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
666f169c0eaSGlenn Lagasse 	    BE_CAP_FILE);
667f169c0eaSGlenn Lagasse 	ret = get_ver_from_capfile(cap_file, new_vers);
668f169c0eaSGlenn Lagasse 	if (ret != BE_SUCCESS) {
669f169c0eaSGlenn Lagasse 		free(*cur_vers);
670f169c0eaSGlenn Lagasse 		*cur_vers = NULL;
671f169c0eaSGlenn Lagasse 	}
672f169c0eaSGlenn Lagasse 	if (be_mounted)
673f169c0eaSGlenn Lagasse 		(void) _be_unmount(bt->obe_name, 0);
674f169c0eaSGlenn Lagasse 
675f169c0eaSGlenn Lagasse cleanup:
676f169c0eaSGlenn Lagasse 	if (pool_mounted) {
677f169c0eaSGlenn Lagasse 		int iret = BE_SUCCESS;
678f169c0eaSGlenn Lagasse 		iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
679f169c0eaSGlenn Lagasse 		if (ret == BE_SUCCESS)
680f169c0eaSGlenn Lagasse 			ret = iret;
681f169c0eaSGlenn Lagasse 		free(orig_mntpnt);
682f169c0eaSGlenn Lagasse 		free(ptmp_mntpnt);
683f169c0eaSGlenn Lagasse 	}
684f169c0eaSGlenn Lagasse 	ZFS_CLOSE(pool_zhp);
685f169c0eaSGlenn Lagasse 
686f169c0eaSGlenn Lagasse 	free(temp_mntpnt);
687f169c0eaSGlenn Lagasse 	return (ret);
688f169c0eaSGlenn Lagasse }
689f169c0eaSGlenn Lagasse 
690f169c0eaSGlenn Lagasse /*
691f169c0eaSGlenn Lagasse  * Function:	get_ver_from_capfile
692f169c0eaSGlenn Lagasse  * Description: Parses the capability file passed in looking for the VERSION
693f169c0eaSGlenn Lagasse  *              line. If found the version is returned in vers, if not then
694f169c0eaSGlenn Lagasse  *              NULL is returned in vers.
695f169c0eaSGlenn Lagasse  *
696f169c0eaSGlenn Lagasse  * Parameters:
697f169c0eaSGlenn Lagasse  *              file - the path to the capability file we want to parse.
698f169c0eaSGlenn Lagasse  *              vers - the version string that will be passed back.
699f169c0eaSGlenn Lagasse  * Return:
700f169c0eaSGlenn Lagasse  *              BE_SUCCESS - Success
701f169c0eaSGlenn Lagasse  *              be_errno_t - Failed to find version
702f169c0eaSGlenn Lagasse  * Scope:
703f169c0eaSGlenn Lagasse  *		Private
704f169c0eaSGlenn Lagasse  */
705f169c0eaSGlenn Lagasse static int
get_ver_from_capfile(char * file,char ** vers)706f169c0eaSGlenn Lagasse get_ver_from_capfile(char *file, char **vers)
707f169c0eaSGlenn Lagasse {
708f169c0eaSGlenn Lagasse 	FILE *fp = NULL;
709f169c0eaSGlenn Lagasse 	char line[BUFSIZ];
710f169c0eaSGlenn Lagasse 	char *last = NULL;
711f169c0eaSGlenn Lagasse 	int err = BE_SUCCESS;
712f169c0eaSGlenn Lagasse 	errno = 0;
713f169c0eaSGlenn Lagasse 
714f169c0eaSGlenn Lagasse 	if (!be_has_grub()) {
715f169c0eaSGlenn Lagasse 		be_print_err(gettext("get_ver_from_capfile: Not supported "
716f169c0eaSGlenn Lagasse 		    "on this architecture\n"));
717f169c0eaSGlenn Lagasse 		return (BE_ERR_NOTSUP);
718f169c0eaSGlenn Lagasse 	}
719f169c0eaSGlenn Lagasse 
720f169c0eaSGlenn Lagasse 	/*
721f169c0eaSGlenn Lagasse 	 * Set version string to NULL; the only case this shouldn't be set
722f169c0eaSGlenn Lagasse 	 * to be NULL is when we've actually found a version in the capability
723f169c0eaSGlenn Lagasse 	 * file, which is set below.
724f169c0eaSGlenn Lagasse 	 */
725f169c0eaSGlenn Lagasse 	*vers = NULL;
726f169c0eaSGlenn Lagasse 
727f169c0eaSGlenn Lagasse 	/*
728f169c0eaSGlenn Lagasse 	 * If the capability file doesn't exist, we're returning success
729f169c0eaSGlenn Lagasse 	 * because on older releases, the capability file did not exist
730f169c0eaSGlenn Lagasse 	 * so this is a valid scenario.
731f169c0eaSGlenn Lagasse 	 */
732f169c0eaSGlenn Lagasse 	if (access(file, F_OK) == 0) {
733f169c0eaSGlenn Lagasse 		if ((fp = fopen(file, "r")) == NULL) {
734f169c0eaSGlenn Lagasse 			err = errno;
735f169c0eaSGlenn Lagasse 			be_print_err(gettext("get_ver_from_capfile: failed to "
736f169c0eaSGlenn Lagasse 			    "open file %s with error %s\n"), file,
737f169c0eaSGlenn Lagasse 			    strerror(err));
738f169c0eaSGlenn Lagasse 			err = errno_to_be_err(err);
739f169c0eaSGlenn Lagasse 			return (err);
740f169c0eaSGlenn Lagasse 		}
741f169c0eaSGlenn Lagasse 
742f169c0eaSGlenn Lagasse 		while (fgets(line, BUFSIZ, fp)) {
743f169c0eaSGlenn Lagasse 			char *tok = strtok_r(line, "=", &last);
744f169c0eaSGlenn Lagasse 
745f169c0eaSGlenn Lagasse 			if (tok == NULL || tok[0] == '#') {
746f169c0eaSGlenn Lagasse 				continue;
747f169c0eaSGlenn Lagasse 			} else if (strcmp(tok, "VERSION") == 0) {
748f169c0eaSGlenn Lagasse 				*vers = strdup(last);
749f169c0eaSGlenn Lagasse 				break;
750f169c0eaSGlenn Lagasse 			}
751f169c0eaSGlenn Lagasse 		}
752f169c0eaSGlenn Lagasse 		(void) fclose(fp);
753f169c0eaSGlenn Lagasse 	}
754f169c0eaSGlenn Lagasse 
755f169c0eaSGlenn Lagasse 	return (BE_SUCCESS);
756f169c0eaSGlenn Lagasse }
757f169c0eaSGlenn Lagasse 
758f169c0eaSGlenn Lagasse /*
759*1a902ef8SHans Rosenfeld  * To be able to boot EFI labeled disks, GRUB stage1 needs to be written
760*1a902ef8SHans Rosenfeld  * into the MBR. We do not do this if we're on disks with a traditional
761*1a902ef8SHans Rosenfeld  * fdisk partition table only, or if any foreign EFI partitions exist.
762*1a902ef8SHans Rosenfeld  * In the trivial case of a whole-disk vdev we always write stage1 into
763*1a902ef8SHans Rosenfeld  * the MBR.
764*1a902ef8SHans Rosenfeld  */
765*1a902ef8SHans Rosenfeld static boolean_t
be_do_installgrub_mbr(char * diskname,nvlist_t * child)766*1a902ef8SHans Rosenfeld be_do_installgrub_mbr(char *diskname, nvlist_t *child)
767*1a902ef8SHans Rosenfeld {
768*1a902ef8SHans Rosenfeld 	struct uuid allowed_uuids[] = {
769*1a902ef8SHans Rosenfeld 		EFI_UNUSED,
770*1a902ef8SHans Rosenfeld 		EFI_RESV1,
771*1a902ef8SHans Rosenfeld 		EFI_BOOT,
772*1a902ef8SHans Rosenfeld 		EFI_ROOT,
773*1a902ef8SHans Rosenfeld 		EFI_SWAP,
774*1a902ef8SHans Rosenfeld 		EFI_USR,
775*1a902ef8SHans Rosenfeld 		EFI_BACKUP,
776*1a902ef8SHans Rosenfeld 		EFI_RESV2,
777*1a902ef8SHans Rosenfeld 		EFI_VAR,
778*1a902ef8SHans Rosenfeld 		EFI_HOME,
779*1a902ef8SHans Rosenfeld 		EFI_ALTSCTR,
780*1a902ef8SHans Rosenfeld 		EFI_RESERVED,
781*1a902ef8SHans Rosenfeld 		EFI_SYSTEM,
782*1a902ef8SHans Rosenfeld 		EFI_BIOS_BOOT,
783*1a902ef8SHans Rosenfeld 		EFI_SYMC_PUB,
784*1a902ef8SHans Rosenfeld 		EFI_SYMC_CDS
785*1a902ef8SHans Rosenfeld 	};
786*1a902ef8SHans Rosenfeld 
787*1a902ef8SHans Rosenfeld 	uint64_t whole;
788*1a902ef8SHans Rosenfeld 	struct dk_gpt *gpt;
789*1a902ef8SHans Rosenfeld 	struct uuid *u;
790*1a902ef8SHans Rosenfeld 	int fd, npart, i, j;
791*1a902ef8SHans Rosenfeld 
792*1a902ef8SHans Rosenfeld 	(void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
793*1a902ef8SHans Rosenfeld 	    &whole);
794*1a902ef8SHans Rosenfeld 
795*1a902ef8SHans Rosenfeld 	if (whole)
796*1a902ef8SHans Rosenfeld 		return (B_TRUE);
797*1a902ef8SHans Rosenfeld 
798*1a902ef8SHans Rosenfeld 	if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
799*1a902ef8SHans Rosenfeld 		return (B_FALSE);
800*1a902ef8SHans Rosenfeld 
801*1a902ef8SHans Rosenfeld 	if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
802*1a902ef8SHans Rosenfeld 		return (B_FALSE);
803*1a902ef8SHans Rosenfeld 
804*1a902ef8SHans Rosenfeld 	for (i = 0; i != npart; i++) {
805*1a902ef8SHans Rosenfeld 		int match = 0;
806*1a902ef8SHans Rosenfeld 
807*1a902ef8SHans Rosenfeld 		u = &gpt->efi_parts[i].p_guid;
808*1a902ef8SHans Rosenfeld 
809*1a902ef8SHans Rosenfeld 		for (j = 0;
810*1a902ef8SHans Rosenfeld 		    j != sizeof (allowed_uuids) / sizeof (struct uuid);
811*1a902ef8SHans Rosenfeld 		    j++)
812*1a902ef8SHans Rosenfeld 			if (bcmp(u, &allowed_uuids[j],
813*1a902ef8SHans Rosenfeld 			    sizeof (struct uuid)) == 0)
814*1a902ef8SHans Rosenfeld 				match++;
815*1a902ef8SHans Rosenfeld 
816*1a902ef8SHans Rosenfeld 		if (match == 0)
817*1a902ef8SHans Rosenfeld 			return (B_FALSE);
818*1a902ef8SHans Rosenfeld 	}
819*1a902ef8SHans Rosenfeld 
820*1a902ef8SHans Rosenfeld 	return (B_TRUE);
821*1a902ef8SHans Rosenfeld }
822*1a902ef8SHans Rosenfeld 
823*1a902ef8SHans Rosenfeld static int
be_do_installgrub_helper(zpool_handle_t * zphp,nvlist_t * child,char * stage1,char * stage2)824*1a902ef8SHans Rosenfeld be_do_installgrub_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
825*1a902ef8SHans Rosenfeld     char *stage2)
826*1a902ef8SHans Rosenfeld {
827*1a902ef8SHans Rosenfeld 	char installgrub_cmd[MAXPATHLEN];
828*1a902ef8SHans Rosenfeld 	char be_run_cmd_errbuf[BUFSIZ];
829*1a902ef8SHans Rosenfeld 	char diskname[MAXPATHLEN];
830*1a902ef8SHans Rosenfeld 	char *vname;
831*1a902ef8SHans Rosenfeld 	char *path, *dsk_ptr;
832*1a902ef8SHans Rosenfeld 	char *m_flag = "";
833*1a902ef8SHans Rosenfeld 
834*1a902ef8SHans Rosenfeld 	if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
835*1a902ef8SHans Rosenfeld 		be_print_err(gettext("be_do_installgrub: "
836*1a902ef8SHans Rosenfeld 		    "failed to get device path\n"));
837*1a902ef8SHans Rosenfeld 		return (BE_ERR_NODEV);
838*1a902ef8SHans Rosenfeld 	}
839*1a902ef8SHans Rosenfeld 
840*1a902ef8SHans Rosenfeld 	/*
841*1a902ef8SHans Rosenfeld 	 * Modify the vdev path to point to the raw disk.
842*1a902ef8SHans Rosenfeld 	 */
843*1a902ef8SHans Rosenfeld 	path = strdup(path);
844*1a902ef8SHans Rosenfeld 	if (path == NULL)
845*1a902ef8SHans Rosenfeld 		return (BE_ERR_NOMEM);
846*1a902ef8SHans Rosenfeld 
847*1a902ef8SHans Rosenfeld 	dsk_ptr = strstr(path, "/dsk/");
848*1a902ef8SHans Rosenfeld 	if (dsk_ptr != NULL) {
849*1a902ef8SHans Rosenfeld 		*dsk_ptr = '\0';
850*1a902ef8SHans Rosenfeld 		dsk_ptr++;
851*1a902ef8SHans Rosenfeld 	} else {
852*1a902ef8SHans Rosenfeld 		dsk_ptr = "";
853*1a902ef8SHans Rosenfeld 	}
854*1a902ef8SHans Rosenfeld 
855*1a902ef8SHans Rosenfeld 	(void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
856*1a902ef8SHans Rosenfeld 	free(path);
857*1a902ef8SHans Rosenfeld 
858*1a902ef8SHans Rosenfeld 	if (be_do_installgrub_mbr(diskname, child))
859*1a902ef8SHans Rosenfeld 		m_flag = "-m -f";
860*1a902ef8SHans Rosenfeld 
861*1a902ef8SHans Rosenfeld 	vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
862*1a902ef8SHans Rosenfeld 	if (vname == NULL) {
863*1a902ef8SHans Rosenfeld 		be_print_err(gettext("be_do_installgrub: "
864*1a902ef8SHans Rosenfeld 		    "failed to get device name: %s\n"),
865*1a902ef8SHans Rosenfeld 		    libzfs_error_description(g_zfs));
866*1a902ef8SHans Rosenfeld 		return (zfs_err_to_be_err(g_zfs));
867*1a902ef8SHans Rosenfeld 	}
868*1a902ef8SHans Rosenfeld 
869*1a902ef8SHans Rosenfeld 	(void) snprintf(installgrub_cmd, sizeof (installgrub_cmd),
870*1a902ef8SHans Rosenfeld 	    "%s %s %s %s %s", BE_INSTALL_GRUB, m_flag, stage1, stage2,
871*1a902ef8SHans Rosenfeld 	    diskname);
872*1a902ef8SHans Rosenfeld 	if (be_run_cmd(installgrub_cmd, be_run_cmd_errbuf, BUFSIZ, NULL, 0)
873*1a902ef8SHans Rosenfeld 	    != BE_SUCCESS) {
874*1a902ef8SHans Rosenfeld 		be_print_err(gettext("be_do_installgrub: installgrub "
875*1a902ef8SHans Rosenfeld 		    "failed for device %s.\n"), vname);
876*1a902ef8SHans Rosenfeld 		/* Assume localized cmd err output. */
877*1a902ef8SHans Rosenfeld 		be_print_err(gettext("  Command: \"%s\"\n"),
878*1a902ef8SHans Rosenfeld 		    installgrub_cmd);
879*1a902ef8SHans Rosenfeld 		be_print_err("%s", be_run_cmd_errbuf);
880*1a902ef8SHans Rosenfeld 		free(vname);
881*1a902ef8SHans Rosenfeld 		return (BE_ERR_BOOTFILE_INST);
882*1a902ef8SHans Rosenfeld 	}
883*1a902ef8SHans Rosenfeld 	free(vname);
884*1a902ef8SHans Rosenfeld 
885*1a902ef8SHans Rosenfeld 	return (BE_SUCCESS);
886*1a902ef8SHans Rosenfeld }
887*1a902ef8SHans Rosenfeld 
888*1a902ef8SHans Rosenfeld /*
889f169c0eaSGlenn Lagasse  * Function:	be_do_installgrub
890f169c0eaSGlenn Lagasse  * Description:	This function runs installgrub using the grub loader files
891f169c0eaSGlenn Lagasse  *              from the BE we're activating and installing them on the
892f169c0eaSGlenn Lagasse  *              pool the BE lives in.
893f169c0eaSGlenn Lagasse  *
894f169c0eaSGlenn Lagasse  * Parameters:
895f169c0eaSGlenn Lagasse  *              bt - The transaction data for the BE we're activating.
896f169c0eaSGlenn Lagasse  * Return:
897f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
898f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
899f169c0eaSGlenn Lagasse  *
900f169c0eaSGlenn Lagasse  * Scope:
901f169c0eaSGlenn Lagasse  *		Private
902f169c0eaSGlenn Lagasse  */
903f169c0eaSGlenn Lagasse static int
be_do_installgrub(be_transaction_data_t * bt)904f169c0eaSGlenn Lagasse be_do_installgrub(be_transaction_data_t *bt)
905f169c0eaSGlenn Lagasse {
906f169c0eaSGlenn Lagasse 	zpool_handle_t  *zphp = NULL;
907f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
908f169c0eaSGlenn Lagasse 	nvlist_t **child, *nv, *config;
909f169c0eaSGlenn Lagasse 	uint_t c, children = 0;
910f169c0eaSGlenn Lagasse 	char *tmp_mntpt = NULL;
911f169c0eaSGlenn Lagasse 	char *pool_mntpnt = NULL;
912f169c0eaSGlenn Lagasse 	char *ptmp_mntpnt = NULL;
913f169c0eaSGlenn Lagasse 	char *orig_mntpnt = NULL;
914f169c0eaSGlenn Lagasse 	FILE *cap_fp = NULL;
915f169c0eaSGlenn Lagasse 	FILE *zpool_cap_fp = NULL;
916f169c0eaSGlenn Lagasse 	char line[BUFSIZ];
917f169c0eaSGlenn Lagasse 	char cap_file[MAXPATHLEN];
918f169c0eaSGlenn Lagasse 	char zpool_cap_file[MAXPATHLEN];
919f169c0eaSGlenn Lagasse 	char stage1[MAXPATHLEN];
920f169c0eaSGlenn Lagasse 	char stage2[MAXPATHLEN];
921f169c0eaSGlenn Lagasse 	char *vname;
922f169c0eaSGlenn Lagasse 	int ret = BE_SUCCESS;
923f169c0eaSGlenn Lagasse 	int err = 0;
924f169c0eaSGlenn Lagasse 	boolean_t be_mounted = B_FALSE;
925f169c0eaSGlenn Lagasse 	boolean_t pool_mounted = B_FALSE;
926f169c0eaSGlenn Lagasse 
927f169c0eaSGlenn Lagasse 	if (!be_has_grub()) {
928f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: Not supported "
929f169c0eaSGlenn Lagasse 		    "on this architecture\n"));
930f169c0eaSGlenn Lagasse 		return (BE_ERR_NOTSUP);
931f169c0eaSGlenn Lagasse 	}
932f169c0eaSGlenn Lagasse 
933f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
934f169c0eaSGlenn Lagasse 	    NULL) {
935f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: failed to "
936f169c0eaSGlenn Lagasse 		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
937f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
938f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
939f169c0eaSGlenn Lagasse 		return (ret);
940f169c0eaSGlenn Lagasse 	}
941f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
942f169c0eaSGlenn Lagasse 		if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
943f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
944f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_do_installgrub: failed to "
945f169c0eaSGlenn Lagasse 			    "mount BE (%s)\n"), bt->obe_name);
946f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
947f169c0eaSGlenn Lagasse 			return (ret);
948f169c0eaSGlenn Lagasse 		}
949f169c0eaSGlenn Lagasse 		be_mounted = B_TRUE;
950f169c0eaSGlenn Lagasse 	}
951f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
952f169c0eaSGlenn Lagasse 
953f169c0eaSGlenn Lagasse 	(void) snprintf(stage1, sizeof (stage1), "%s%s", tmp_mntpt, BE_STAGE_1);
954f169c0eaSGlenn Lagasse 	(void) snprintf(stage2, sizeof (stage2), "%s%s", tmp_mntpt, BE_STAGE_2);
955f169c0eaSGlenn Lagasse 
956f169c0eaSGlenn Lagasse 	if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
957f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: failed to open "
958f169c0eaSGlenn Lagasse 		    "pool (%s): %s\n"), bt->obe_zpool,
959f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
960f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
961f169c0eaSGlenn Lagasse 		if (be_mounted)
962f169c0eaSGlenn Lagasse 			(void) _be_unmount(bt->obe_name, 0);
963f169c0eaSGlenn Lagasse 		free(tmp_mntpt);
964f169c0eaSGlenn Lagasse 		return (ret);
965f169c0eaSGlenn Lagasse 	}
966f169c0eaSGlenn Lagasse 
967f169c0eaSGlenn Lagasse 	if ((config = zpool_get_config(zphp, NULL)) == NULL) {
968f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: failed to get zpool "
969f169c0eaSGlenn Lagasse 		    "configuration information. %s\n"),
970f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
971f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
972f169c0eaSGlenn Lagasse 		goto done;
973f169c0eaSGlenn Lagasse 	}
974f169c0eaSGlenn Lagasse 
975f169c0eaSGlenn Lagasse 	/*
976f169c0eaSGlenn Lagasse 	 * Get the vdev tree
977f169c0eaSGlenn Lagasse 	 */
978f169c0eaSGlenn Lagasse 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
979f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: failed to get vdev "
980f169c0eaSGlenn Lagasse 		    "tree: %s\n"), libzfs_error_description(g_zfs));
981f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
982f169c0eaSGlenn Lagasse 		goto done;
983f169c0eaSGlenn Lagasse 	}
984f169c0eaSGlenn Lagasse 
985f169c0eaSGlenn Lagasse 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
986f169c0eaSGlenn Lagasse 	    &children) != 0) {
987f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: failed to traverse "
988f169c0eaSGlenn Lagasse 		    "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
989f169c0eaSGlenn Lagasse 		ret = zfs_err_to_be_err(g_zfs);
990f169c0eaSGlenn Lagasse 		goto done;
991f169c0eaSGlenn Lagasse 	}
992f169c0eaSGlenn Lagasse 	for (c = 0; c < children; c++) {
993f169c0eaSGlenn Lagasse 		uint_t i, nchildren = 0;
994f169c0eaSGlenn Lagasse 		nvlist_t **nvchild;
995f169c0eaSGlenn Lagasse 		vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
996f169c0eaSGlenn Lagasse 		if (vname == NULL) {
997f169c0eaSGlenn Lagasse 			be_print_err(gettext(
998f169c0eaSGlenn Lagasse 			    "be_do_installgrub: "
999f169c0eaSGlenn Lagasse 			    "failed to get device name: %s\n"),
1000f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1001f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1002f169c0eaSGlenn Lagasse 			goto done;
1003f169c0eaSGlenn Lagasse 		}
1004f169c0eaSGlenn Lagasse 		if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {
1005*1a902ef8SHans Rosenfeld 			free(vname);
1006f169c0eaSGlenn Lagasse 
1007f169c0eaSGlenn Lagasse 			if (nvlist_lookup_nvlist_array(child[c],
1008f169c0eaSGlenn Lagasse 			    ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
1009f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_do_installgrub: "
1010f169c0eaSGlenn Lagasse 				    "failed to traverse the vdev tree: %s\n"),
1011f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
1012f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
1013f169c0eaSGlenn Lagasse 				goto done;
1014f169c0eaSGlenn Lagasse 			}
1015f169c0eaSGlenn Lagasse 
1016f169c0eaSGlenn Lagasse 			for (i = 0; i < nchildren; i++) {
1017*1a902ef8SHans Rosenfeld 				ret = be_do_installgrub_helper(zphp, nvchild[i],
1018*1a902ef8SHans Rosenfeld 				    stage1, stage2);
1019*1a902ef8SHans Rosenfeld 				if (ret != BE_SUCCESS)
1020f169c0eaSGlenn Lagasse 					goto done;
1021f169c0eaSGlenn Lagasse 			}
1022f169c0eaSGlenn Lagasse 		} else {
1023f169c0eaSGlenn Lagasse 			free(vname);
1024*1a902ef8SHans Rosenfeld 
1025*1a902ef8SHans Rosenfeld 			ret = be_do_installgrub_helper(zphp, child[c], stage1,
1026*1a902ef8SHans Rosenfeld 			    stage2);
1027*1a902ef8SHans Rosenfeld 			if (ret != BE_SUCCESS)
1028f169c0eaSGlenn Lagasse 				goto done;
1029f169c0eaSGlenn Lagasse 		}
1030f169c0eaSGlenn Lagasse 	}
1031f169c0eaSGlenn Lagasse 
1032f169c0eaSGlenn Lagasse 	/*
1033f169c0eaSGlenn Lagasse 	 * Copy the grub capability file from the BE we're activating into
1034f169c0eaSGlenn Lagasse 	 * the root pool.
1035f169c0eaSGlenn Lagasse 	 */
1036f169c0eaSGlenn Lagasse 	(void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpt,
1037f169c0eaSGlenn Lagasse 	    BE_CAP_FILE);
1038f169c0eaSGlenn Lagasse 
1039f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
1040f169c0eaSGlenn Lagasse 	    NULL) {
1041f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: zfs_open "
1042f169c0eaSGlenn Lagasse 		    "failed: %s\n"), libzfs_error_description(g_zfs));
1043f169c0eaSGlenn Lagasse 		zpool_close(zphp);
1044f169c0eaSGlenn Lagasse 		return (zfs_err_to_be_err(g_zfs));
1045f169c0eaSGlenn Lagasse 	}
1046f169c0eaSGlenn Lagasse 
1047f169c0eaSGlenn Lagasse 	/*
1048f169c0eaSGlenn Lagasse 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1049f169c0eaSGlenn Lagasse 	 * attempt to mount it.
1050f169c0eaSGlenn Lagasse 	 */
1051f169c0eaSGlenn Lagasse 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt,
1052f169c0eaSGlenn Lagasse 	    &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1053f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: pool dataset "
1054f169c0eaSGlenn Lagasse 		    "(%s) could not be mounted\n"), bt->obe_zpool);
1055f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1056f169c0eaSGlenn Lagasse 		zpool_close(zphp);
1057f169c0eaSGlenn Lagasse 		return (ret);
1058f169c0eaSGlenn Lagasse 	}
1059f169c0eaSGlenn Lagasse 
1060f169c0eaSGlenn Lagasse 	/*
1061f169c0eaSGlenn Lagasse 	 * Get the mountpoint for the root pool dataset.
1062f169c0eaSGlenn Lagasse 	 */
1063f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1064f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: pool "
1065f169c0eaSGlenn Lagasse 		    "dataset (%s) is not mounted. Can't check the grub "
1066f169c0eaSGlenn Lagasse 		    "version from the grub capability file.\n"), bt->obe_zpool);
1067f169c0eaSGlenn Lagasse 		ret = BE_ERR_NO_MENU;
1068f169c0eaSGlenn Lagasse 		goto done;
1069f169c0eaSGlenn Lagasse 	}
1070f169c0eaSGlenn Lagasse 
1071f169c0eaSGlenn Lagasse 	(void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1072f169c0eaSGlenn Lagasse 	    pool_mntpnt, BE_CAP_FILE);
1073f169c0eaSGlenn Lagasse 
1074f169c0eaSGlenn Lagasse 	free(pool_mntpnt);
1075f169c0eaSGlenn Lagasse 	pool_mntpnt = NULL;
1076f169c0eaSGlenn Lagasse 
1077f169c0eaSGlenn Lagasse 	if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1078f169c0eaSGlenn Lagasse 		err = errno;
1079f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: failed to open grub "
1080f169c0eaSGlenn Lagasse 		    "capability file\n"));
1081f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1082f169c0eaSGlenn Lagasse 		goto done;
1083f169c0eaSGlenn Lagasse 	}
1084f169c0eaSGlenn Lagasse 	if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1085f169c0eaSGlenn Lagasse 		err = errno;
1086f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_do_installgrub: failed to open new "
1087f169c0eaSGlenn Lagasse 		    "grub capability file\n"));
1088f169c0eaSGlenn Lagasse 		ret = errno_to_be_err(err);
1089f169c0eaSGlenn Lagasse 		(void) fclose(cap_fp);
1090f169c0eaSGlenn Lagasse 		goto done;
1091f169c0eaSGlenn Lagasse 	}
1092f169c0eaSGlenn Lagasse 
1093f169c0eaSGlenn Lagasse 	while (fgets(line, BUFSIZ, cap_fp)) {
1094f169c0eaSGlenn Lagasse 		(void) fputs(line, zpool_cap_fp);
1095f169c0eaSGlenn Lagasse 	}
1096f169c0eaSGlenn Lagasse 
1097f169c0eaSGlenn Lagasse 	(void) fclose(zpool_cap_fp);
1098f169c0eaSGlenn Lagasse 	(void) fclose(cap_fp);
1099f169c0eaSGlenn Lagasse 
1100f169c0eaSGlenn Lagasse done:
1101f169c0eaSGlenn Lagasse 	if (pool_mounted) {
1102f169c0eaSGlenn Lagasse 		int iret = 0;
1103f169c0eaSGlenn Lagasse 		iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1104f169c0eaSGlenn Lagasse 		if (ret == BE_SUCCESS)
1105f169c0eaSGlenn Lagasse 			ret = iret;
1106f169c0eaSGlenn Lagasse 		free(orig_mntpnt);
1107f169c0eaSGlenn Lagasse 		free(ptmp_mntpnt);
1108f169c0eaSGlenn Lagasse 	}
1109f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1110f169c0eaSGlenn Lagasse 	if (be_mounted)
1111f169c0eaSGlenn Lagasse 		(void) _be_unmount(bt->obe_name, 0);
1112f169c0eaSGlenn Lagasse 	zpool_close(zphp);
1113f169c0eaSGlenn Lagasse 	free(tmp_mntpt);
1114f169c0eaSGlenn Lagasse 	return (ret);
1115f169c0eaSGlenn Lagasse }
1116f169c0eaSGlenn Lagasse 
1117f169c0eaSGlenn Lagasse /*
1118f169c0eaSGlenn Lagasse  * Function:	be_promote_zone_ds
1119f169c0eaSGlenn Lagasse  * Description:	This function finds the zones for the BE being activated
1120f169c0eaSGlenn Lagasse  *              and the active zonepath dataset for each zone. Then each
1121f169c0eaSGlenn Lagasse  *              active zonepath dataset is promoted.
1122f169c0eaSGlenn Lagasse  *
1123f169c0eaSGlenn Lagasse  * Parameters:
1124f169c0eaSGlenn Lagasse  *              be_name - the name of the global zone BE that we need to
1125f169c0eaSGlenn Lagasse  *                       find the zones for.
1126f169c0eaSGlenn Lagasse  *              be_root_ds - the root dataset for be_name.
1127f169c0eaSGlenn Lagasse  * Return:
1128f169c0eaSGlenn Lagasse  *		BE_SUCCESS - Success
1129f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1130f169c0eaSGlenn Lagasse  *
1131f169c0eaSGlenn Lagasse  * Scope:
1132f169c0eaSGlenn Lagasse  *		Private
1133f169c0eaSGlenn Lagasse  */
1134f169c0eaSGlenn Lagasse static int
be_promote_zone_ds(char * be_name,char * be_root_ds)1135f169c0eaSGlenn Lagasse be_promote_zone_ds(char *be_name, char *be_root_ds)
1136f169c0eaSGlenn Lagasse {
1137f169c0eaSGlenn Lagasse 	char		*zone_ds = NULL;
1138f169c0eaSGlenn Lagasse 	char		*temp_mntpt = NULL;
1139f169c0eaSGlenn Lagasse 	char		origin[MAXPATHLEN];
1140f169c0eaSGlenn Lagasse 	char		zoneroot_ds[MAXPATHLEN];
1141f169c0eaSGlenn Lagasse 	zfs_handle_t	*zhp = NULL;
1142f169c0eaSGlenn Lagasse 	zfs_handle_t	*z_zhp = NULL;
1143f169c0eaSGlenn Lagasse 	zoneList_t	zone_list = NULL;
1144f169c0eaSGlenn Lagasse 	zoneBrandList_t *brands = NULL;
1145f169c0eaSGlenn Lagasse 	boolean_t	be_mounted = B_FALSE;
1146f169c0eaSGlenn Lagasse 	int		zone_index = 0;
1147f169c0eaSGlenn Lagasse 	int		err = BE_SUCCESS;
1148f169c0eaSGlenn Lagasse 
1149f169c0eaSGlenn Lagasse 	/*
1150f169c0eaSGlenn Lagasse 	 * Get the supported zone brands so we can pass that
1151f169c0eaSGlenn Lagasse 	 * to z_get_nonglobal_zone_list_by_brand. Currently
1152f169c0eaSGlenn Lagasse 	 * only the ipkg and labeled brand zones are supported
1153f169c0eaSGlenn Lagasse 	 *
1154f169c0eaSGlenn Lagasse 	 */
1155f169c0eaSGlenn Lagasse 	if ((brands = be_get_supported_brandlist()) == NULL) {
1156f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_promote_zone_ds: no supported "
1157f169c0eaSGlenn Lagasse 		    "brands\n"));
1158f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1159f169c0eaSGlenn Lagasse 	}
1160f169c0eaSGlenn Lagasse 
1161f169c0eaSGlenn Lagasse 	if ((zhp = zfs_open(g_zfs, be_root_ds,
1162f169c0eaSGlenn Lagasse 	    ZFS_TYPE_FILESYSTEM)) == NULL) {
1163f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_promote_zone_ds: Failed to open "
1164f169c0eaSGlenn Lagasse 		    "dataset (%s): %s\n"), be_root_ds,
1165f169c0eaSGlenn Lagasse 		    libzfs_error_description(g_zfs));
1166f169c0eaSGlenn Lagasse 		err = zfs_err_to_be_err(g_zfs);
1167f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
1168f169c0eaSGlenn Lagasse 		return (err);
1169f169c0eaSGlenn Lagasse 	}
1170f169c0eaSGlenn Lagasse 
1171f169c0eaSGlenn Lagasse 	if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1172f169c0eaSGlenn Lagasse 		if ((err = _be_mount(be_name, &temp_mntpt,
1173f169c0eaSGlenn Lagasse 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1174f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_promote_zone_ds: failed to "
1175f169c0eaSGlenn Lagasse 			    "mount the BE for zones procesing.\n"));
1176f169c0eaSGlenn Lagasse 			ZFS_CLOSE(zhp);
1177f169c0eaSGlenn Lagasse 			z_free_brand_list(brands);
1178f169c0eaSGlenn Lagasse 			return (err);
1179f169c0eaSGlenn Lagasse 		}
1180f169c0eaSGlenn Lagasse 		be_mounted = B_TRUE;
1181f169c0eaSGlenn Lagasse 	}
1182f169c0eaSGlenn Lagasse 
1183f169c0eaSGlenn Lagasse 	/*
1184f169c0eaSGlenn Lagasse 	 * Set the zone root to the temp mount point for the BE we just mounted.
1185f169c0eaSGlenn Lagasse 	 */
1186f169c0eaSGlenn Lagasse 	z_set_zone_root(temp_mntpt);
1187f169c0eaSGlenn Lagasse 
1188f169c0eaSGlenn Lagasse 	/*
1189f169c0eaSGlenn Lagasse 	 * Get all the zones based on the brands we're looking for. If no zones
1190f169c0eaSGlenn Lagasse 	 * are found that we're interested in unmount the BE and move on.
1191f169c0eaSGlenn Lagasse 	 */
1192f169c0eaSGlenn Lagasse 	if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1193f169c0eaSGlenn Lagasse 		if (be_mounted)
1194f169c0eaSGlenn Lagasse 			(void) _be_unmount(be_name, 0);
1195f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1196f169c0eaSGlenn Lagasse 		z_free_brand_list(brands);
1197f169c0eaSGlenn Lagasse 		free(temp_mntpt);
1198f169c0eaSGlenn Lagasse 		return (BE_SUCCESS);
1199f169c0eaSGlenn Lagasse 	}
1200f169c0eaSGlenn Lagasse 	for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1201f169c0eaSGlenn Lagasse 	    != NULL; zone_index++) {
1202f169c0eaSGlenn Lagasse 		char *zone_path = NULL;
1203f169c0eaSGlenn Lagasse 
1204f169c0eaSGlenn Lagasse 		/* Skip zones that aren't at least installed */
1205f169c0eaSGlenn Lagasse 		if (z_zlist_get_current_state(zone_list, zone_index) <
1206f169c0eaSGlenn Lagasse 		    ZONE_STATE_INSTALLED)
1207f169c0eaSGlenn Lagasse 			continue;
1208f169c0eaSGlenn Lagasse 
1209f169c0eaSGlenn Lagasse 		if (((zone_path =
1210f169c0eaSGlenn Lagasse 		    z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1211f169c0eaSGlenn Lagasse 		    ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1212f169c0eaSGlenn Lagasse 		    !be_zone_supported(zone_ds))
1213f169c0eaSGlenn Lagasse 			continue;
1214f169c0eaSGlenn Lagasse 
1215f169c0eaSGlenn Lagasse 		if (be_find_active_zone_root(zhp, zone_ds,
1216f169c0eaSGlenn Lagasse 		    zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1217f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_promote_zone_ds: "
1218f169c0eaSGlenn Lagasse 			    "Zone does not have an active root "
1219f169c0eaSGlenn Lagasse 			    "dataset, skipping this zone.\n"));
1220f169c0eaSGlenn Lagasse 			continue;
1221f169c0eaSGlenn Lagasse 		}
1222f169c0eaSGlenn Lagasse 
1223f169c0eaSGlenn Lagasse 		if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1224f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1225f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_promote_zone_ds: "
1226f169c0eaSGlenn Lagasse 			    "Failed to open dataset "
1227f169c0eaSGlenn Lagasse 			    "(%s): %s\n"), zoneroot_ds,
1228f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1229f169c0eaSGlenn Lagasse 			err = zfs_err_to_be_err(g_zfs);
1230f169c0eaSGlenn Lagasse 			goto done;
1231f169c0eaSGlenn Lagasse 		}
1232f169c0eaSGlenn Lagasse 
1233f169c0eaSGlenn Lagasse 		if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1234f169c0eaSGlenn Lagasse 		    sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1235f169c0eaSGlenn Lagasse 			ZFS_CLOSE(z_zhp);
1236f169c0eaSGlenn Lagasse 			continue;
1237f169c0eaSGlenn Lagasse 		}
1238f169c0eaSGlenn Lagasse 
1239f169c0eaSGlenn Lagasse 		/*
1240f169c0eaSGlenn Lagasse 		 * We don't need to close the zfs handle at this
1241f169c0eaSGlenn Lagasse 		 * point because the callback funtion
1242f169c0eaSGlenn Lagasse 		 * be_promote_ds_callback() will close it for us.
1243f169c0eaSGlenn Lagasse 		 */
1244f169c0eaSGlenn Lagasse 		if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1245f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_promote_zone_ds: "
1246f169c0eaSGlenn Lagasse 			    "failed to activate the "
1247f169c0eaSGlenn Lagasse 			    "datasets for %s: %s\n"),
1248f169c0eaSGlenn Lagasse 			    zoneroot_ds,
1249f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1250f169c0eaSGlenn Lagasse 			err = BE_ERR_PROMOTE;
1251f169c0eaSGlenn Lagasse 			goto done;
1252f169c0eaSGlenn Lagasse 		}
1253f169c0eaSGlenn Lagasse 	}
1254f169c0eaSGlenn Lagasse done:
1255f169c0eaSGlenn Lagasse 	if (be_mounted)
1256f169c0eaSGlenn Lagasse 		(void) _be_unmount(be_name, 0);
1257f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1258f169c0eaSGlenn Lagasse 	free(temp_mntpt);
1259f169c0eaSGlenn Lagasse 	z_free_brand_list(brands);
1260f169c0eaSGlenn Lagasse 	z_free_zone_list(zone_list);
1261f169c0eaSGlenn Lagasse 	return (err);
1262f169c0eaSGlenn Lagasse }
1263f169c0eaSGlenn Lagasse 
1264f169c0eaSGlenn Lagasse /*
1265f169c0eaSGlenn Lagasse  * Function:	be_promote_ds_callback
1266f169c0eaSGlenn Lagasse  * Description:	This function is used to promote the datasets for the BE
1267f169c0eaSGlenn Lagasse  *		being activated as well as the datasets for the zones BE
1268f169c0eaSGlenn Lagasse  *		being activated.
1269f169c0eaSGlenn Lagasse  *
1270f169c0eaSGlenn Lagasse  * Parameters:
1271f169c0eaSGlenn Lagasse  *              zhp - the zfs handle for zone BE being activated.
1272f169c0eaSGlenn Lagasse  *		data - not used.
1273f169c0eaSGlenn Lagasse  * Return:
1274f169c0eaSGlenn Lagasse  *		0 - Success
1275f169c0eaSGlenn Lagasse  *		be_errno_t - Failure
1276f169c0eaSGlenn Lagasse  *
1277f169c0eaSGlenn Lagasse  * Scope:
1278f169c0eaSGlenn Lagasse  *		Private
1279f169c0eaSGlenn Lagasse  */
1280f169c0eaSGlenn Lagasse static int
1281f169c0eaSGlenn Lagasse /* LINTED */
be_promote_ds_callback(zfs_handle_t * zhp,void * data)1282f169c0eaSGlenn Lagasse be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1283f169c0eaSGlenn Lagasse {
1284f169c0eaSGlenn Lagasse 	char	origin[MAXPATHLEN];
1285f169c0eaSGlenn Lagasse 	char	*sub_dataset = NULL;
1286f169c0eaSGlenn Lagasse 	int	ret = 0;
1287f169c0eaSGlenn Lagasse 
1288f169c0eaSGlenn Lagasse 	if (zhp != NULL) {
1289f169c0eaSGlenn Lagasse 		sub_dataset = strdup(zfs_get_name(zhp));
1290f169c0eaSGlenn Lagasse 		if (sub_dataset == NULL) {
1291f169c0eaSGlenn Lagasse 			ret = BE_ERR_NOMEM;
1292f169c0eaSGlenn Lagasse 			goto done;
1293f169c0eaSGlenn Lagasse 		}
1294f169c0eaSGlenn Lagasse 	} else {
1295f169c0eaSGlenn Lagasse 		be_print_err(gettext("be_promote_ds_callback: "
1296f169c0eaSGlenn Lagasse 		    "Invalid zfs handle passed into function\n"));
1297f169c0eaSGlenn Lagasse 		ret = BE_ERR_INVAL;
1298f169c0eaSGlenn Lagasse 		goto done;
1299f169c0eaSGlenn Lagasse 	}
1300f169c0eaSGlenn Lagasse 
1301f169c0eaSGlenn Lagasse 	/*
1302f169c0eaSGlenn Lagasse 	 * This loop makes sure that we promote the dataset to the
1303f169c0eaSGlenn Lagasse 	 * top of the tree so that it is no longer a decendent of any
1304f169c0eaSGlenn Lagasse 	 * dataset. The ZFS close and then open is used to make sure that
1305f169c0eaSGlenn Lagasse 	 * the promotion is updated before we move on.
1306f169c0eaSGlenn Lagasse 	 */
1307f169c0eaSGlenn Lagasse 	while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1308f169c0eaSGlenn Lagasse 	    sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1309f169c0eaSGlenn Lagasse 		if (zfs_promote(zhp) != 0) {
1310f169c0eaSGlenn Lagasse 			if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1311f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_promote_ds_callback: "
1312f169c0eaSGlenn Lagasse 				    "promote of %s failed: %s\n"),
1313f169c0eaSGlenn Lagasse 				    zfs_get_name(zhp),
1314f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
1315f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
1316f169c0eaSGlenn Lagasse 				goto done;
1317f169c0eaSGlenn Lagasse 			} else {
1318f169c0eaSGlenn Lagasse 				/*
1319f169c0eaSGlenn Lagasse 				 * If the call to zfs_promote returns the
1320f169c0eaSGlenn Lagasse 				 * error EZFS_EXISTS we've hit a snapshot name
1321f169c0eaSGlenn Lagasse 				 * collision. This means we're probably
1322f169c0eaSGlenn Lagasse 				 * attemping to promote a zone dataset above a
1323f169c0eaSGlenn Lagasse 				 * parent dataset that belongs to another zone
1324f169c0eaSGlenn Lagasse 				 * which this zone was cloned from.
1325f169c0eaSGlenn Lagasse 				 *
1326f169c0eaSGlenn Lagasse 				 * TODO: If this is a zone dataset at some
1327f169c0eaSGlenn Lagasse 				 * point we should skip this if the zone
1328f169c0eaSGlenn Lagasse 				 * paths for the dataset and the snapshot
1329f169c0eaSGlenn Lagasse 				 * don't match.
1330f169c0eaSGlenn Lagasse 				 */
1331f169c0eaSGlenn Lagasse 				be_print_err(gettext("be_promote_ds_callback: "
1332f169c0eaSGlenn Lagasse 				    "promote of %s failed due to snapshot "
1333f169c0eaSGlenn Lagasse 				    "name collision: %s\n"), zfs_get_name(zhp),
1334f169c0eaSGlenn Lagasse 				    libzfs_error_description(g_zfs));
1335f169c0eaSGlenn Lagasse 				ret = zfs_err_to_be_err(g_zfs);
1336f169c0eaSGlenn Lagasse 				goto done;
1337f169c0eaSGlenn Lagasse 			}
1338f169c0eaSGlenn Lagasse 		}
1339f169c0eaSGlenn Lagasse 		ZFS_CLOSE(zhp);
1340f169c0eaSGlenn Lagasse 		if ((zhp = zfs_open(g_zfs, sub_dataset,
1341f169c0eaSGlenn Lagasse 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1342f169c0eaSGlenn Lagasse 			be_print_err(gettext("be_promote_ds_callback: "
1343f169c0eaSGlenn Lagasse 			    "Failed to open dataset (%s): %s\n"), sub_dataset,
1344f169c0eaSGlenn Lagasse 			    libzfs_error_description(g_zfs));
1345f169c0eaSGlenn Lagasse 			ret = zfs_err_to_be_err(g_zfs);
1346f169c0eaSGlenn Lagasse 			goto done;
1347f169c0eaSGlenn Lagasse 		}
1348f169c0eaSGlenn Lagasse 	}
1349f169c0eaSGlenn Lagasse 
1350f169c0eaSGlenn Lagasse 	/* Iterate down this dataset's children and promote them */
1351f169c0eaSGlenn Lagasse 	ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1352f169c0eaSGlenn Lagasse 
1353f169c0eaSGlenn Lagasse done:
1354f169c0eaSGlenn Lagasse 	free(sub_dataset);
1355f169c0eaSGlenn Lagasse 	ZFS_CLOSE(zhp);
1356f169c0eaSGlenn Lagasse 	return (ret);
1357f169c0eaSGlenn Lagasse }
1358