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