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