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