xref: /titanic_51/usr/src/lib/libbe/common/be_activate.c (revision 71668a2f05bc8eb5e0c1f7eaf23e10cc7d40c90b)
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 
51 char	*mnttab = MNTTAB;
52 
53 /*
54  * Private function prototypes
55  */
56 static int set_bootfs(char *boot_rpool, char *be_root_ds);
57 static int set_canmount(be_node_list_t *, char *);
58 static boolean_t be_do_install_mbr(char *, nvlist_t *);
59 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
60     char *, uint16_t);
61 static int be_do_installboot(be_transaction_data_t *, uint16_t);
62 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
63 static int get_ver_from_capfile(char *, char **);
64 static int be_promote_zone_ds(char *, char *);
65 static 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  */
90 int
91 be_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  */
144 int
145 be_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  */
216 int
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 	}
392 done:
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  */
408 int
409 be_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  */
439 boolean_t
440 be_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  */
484 static int
485 set_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  */
524 static int
525 set_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  */
624 static int
625 be_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 
727 cleanup:
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  */
757 static int
758 get_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  */
817 static boolean_t
818 be_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 
875 static int
876 be_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, *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_PATH, &path) != 0) {
891 		be_print_err(gettext("be_do_installboot: "
892 		    "failed to get device path\n"));
893 		return (BE_ERR_NODEV);
894 	}
895 
896 	if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
897 	    (uint64_t **)&vs, &vsc) != 0) ||
898 	    vs->vs_state < VDEV_STATE_DEGRADED) {
899 		/*
900 		 * Don't try to run installgrub on a vdev that is not ONLINE
901 		 * or DEGRADED. Try to print a warning for each such vdev.
902 		 */
903 		be_print_err(gettext("be_do_installboot: "
904 		    "vdev %s is %s, can't install boot loader\n"),
905 		    path, zpool_state_to_name(vs->vs_state, vs->vs_aux));
906 		free(path);
907 		return (BE_SUCCESS);
908 	}
909 
910 	/*
911 	 * Modify the vdev path to point to the raw disk.
912 	 */
913 	path = strdup(path);
914 	if (path == NULL)
915 		return (BE_ERR_NOMEM);
916 
917 	dsk_ptr = strstr(path, "/dsk/");
918 	if (dsk_ptr != NULL) {
919 		*dsk_ptr = '\0';
920 		dsk_ptr++;
921 	} else {
922 		dsk_ptr = "";
923 	}
924 
925 	(void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
926 	free(path);
927 
928 	vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
929 	if (vname == NULL) {
930 		be_print_err(gettext("be_do_installboot: "
931 		    "failed to get device name: %s\n"),
932 		    libzfs_error_description(g_zfs));
933 		return (zfs_err_to_be_err(g_zfs));
934 	}
935 
936 	if (be_is_isa("i386")) {
937 		uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
938 		uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
939 
940 		if (force == BE_INSTALLBOOT_FLAG_FORCE) {
941 			if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
942 			    be_do_install_mbr(diskname, child))
943 				flag = "-F -m -f";
944 			else
945 				flag = "-F";
946 		} else {
947 			if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
948 			    be_do_install_mbr(diskname, child))
949 				flag = "-m -f";
950 		}
951 
952 		if (be_has_grub()) {
953 			(void) snprintf(install_cmd, sizeof (install_cmd),
954 			    "%s %s %s %s %s", BE_INSTALL_GRUB, flag,
955 			    stage1, stage2, diskname);
956 		} else {
957 			(void) snprintf(install_cmd, sizeof (install_cmd),
958 			    "%s %s %s %s %s", BE_INSTALL_BOOT, flag,
959 			    stage1, stage2, diskname);
960 		}
961 	} else if (be_is_isa("sparc")) {
962 		if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
963 		    BE_INSTALLBOOT_FLAG_FORCE)
964 			flag = "-f -F zfs";
965 		else
966 			flag = "-F zfs";
967 
968 		(void) snprintf(install_cmd, sizeof (install_cmd),
969 		    "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
970 	} else {
971 		be_print_err(gettext("be_do_installboot: unsupported "
972 		    "architecture.\n"));
973 		return (BE_ERR_BOOTFILE_INST);
974 	}
975 
976 	*be_run_cmd_outbuf = '\0';
977 	*be_run_cmd_errbuf = '\0';
978 
979 	ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
980 	    be_run_cmd_outbuf, BUFSIZ);
981 
982 	if (ret != BE_SUCCESS) {
983 		be_print_err(gettext("be_do_installboot: install "
984 		    "failed for device %s.\n"), vname);
985 		ret = BE_ERR_BOOTFILE_INST;
986 	}
987 
988 	be_print_err(gettext("  Command: \"%s\"\n"), install_cmd);
989 	if (be_run_cmd_outbuf[0] != 0) {
990 		be_print_err(gettext("  Output:\n"));
991 		be_print_err("%s", be_run_cmd_outbuf);
992 	}
993 
994 	if (be_run_cmd_errbuf[0] != 0) {
995 		be_print_err(gettext("  Errors:\n"));
996 		be_print_err("%s", be_run_cmd_errbuf);
997 	}
998 	free(vname);
999 
1000 	return (ret);
1001 }
1002 
1003 /*
1004  * Function:	be_do_copy_grub_cap
1005  * Description:	This function will copy grub capability file to BE.
1006  *
1007  * Parameters:
1008  *              bt - The transaction data for the BE we're activating.
1009  * Return:
1010  *		BE_SUCCESS - Success
1011  *		be_errno_t - Failure
1012  *
1013  * Scope:
1014  *		Private
1015  */
1016 static int
1017 be_do_copy_grub_cap(be_transaction_data_t *bt)
1018 {
1019 	zfs_handle_t *zhp = NULL;
1020 	char cap_file[MAXPATHLEN];
1021 	char zpool_cap_file[MAXPATHLEN];
1022 	char line[BUFSIZ];
1023 	char *tmp_mntpnt = NULL;
1024 	char *orig_mntpnt = NULL;
1025 	char *pool_mntpnt = NULL;
1026 	FILE *cap_fp = NULL;
1027 	FILE *zpool_cap_fp = NULL;
1028 	int err = 0;
1029 	int ret = BE_SUCCESS;
1030 	boolean_t pool_mounted = B_FALSE;
1031 	boolean_t be_mounted = B_FALSE;
1032 
1033 	/*
1034 	 * first get BE dataset mountpoint, we can free all the resources
1035 	 * once cap_file is built, leaving only be unmount to be done.
1036 	 */
1037 	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1038 	    NULL) {
1039 		be_print_err(gettext("be_do_copy_grub_cap: failed to "
1040 		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1041 		    libzfs_error_description(g_zfs));
1042 		return (zfs_err_to_be_err(g_zfs));
1043 	}
1044 
1045 	if (!zfs_is_mounted(zhp, &tmp_mntpnt)) {
1046 		if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt,
1047 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1048 			be_print_err(gettext("be_do_copy_grub_cap: failed to "
1049 			    "mount BE (%s)\n"), bt->obe_name);
1050 			ZFS_CLOSE(zhp);
1051 			goto done;
1052 		}
1053 		be_mounted = B_TRUE;
1054 	}
1055 	ZFS_CLOSE(zhp);	/* BE dataset handle is not needed any more */
1056 
1057 	(void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
1058 	    BE_CAP_FILE);
1059 	free(tmp_mntpnt);
1060 
1061 	/* get pool root dataset mountpoint */
1062 	zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM);
1063 	if (zhp == NULL) {
1064 		be_print_err(gettext("be_do_copy_grub_cap: zfs_open "
1065 		    "failed: %s\n"), libzfs_error_description(g_zfs));
1066 		ret = zfs_err_to_be_err(g_zfs);
1067 		goto done;
1068 	}
1069 
1070 	/*
1071 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1072 	 * attempt to mount it.
1073 	 */
1074 	if ((ret = be_mount_pool(zhp, &tmp_mntpnt,
1075 	    &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1076 		be_print_err(gettext("be_do_copy_grub_cap: pool dataset "
1077 		    "(%s) could not be mounted\n"), bt->obe_zpool);
1078 		ZFS_CLOSE(zhp);
1079 		goto done;
1080 	}
1081 
1082 	/*
1083 	 * Get the mountpoint for the root pool dataset.
1084 	 * NOTE: zhp must be kept for _be_unmount_pool()
1085 	 */
1086 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1087 		be_print_err(gettext("be_do_copy_grub_cap: pool "
1088 		    "dataset (%s) is not mounted. Can't check the grub "
1089 		    "version from the grub capability file.\n"), bt->obe_zpool);
1090 		ret = BE_ERR_NO_MENU;
1091 		goto done;
1092 	}
1093 
1094 	(void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1095 	    pool_mntpnt, BE_CAP_FILE);
1096 	free(pool_mntpnt);
1097 
1098 	if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1099 		err = errno;
1100 		be_print_err(gettext("be_do_copy_grub_cap: failed to open grub "
1101 		    "capability file\n"));
1102 		ret = errno_to_be_err(err);
1103 		goto done;
1104 	}
1105 	if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1106 		err = errno;
1107 		be_print_err(gettext("be_do_copy_grub_cap: failed to open new "
1108 		    "grub capability file\n"));
1109 		ret = errno_to_be_err(err);
1110 		(void) fclose(cap_fp);
1111 		goto done;
1112 	}
1113 
1114 	while (fgets(line, BUFSIZ, cap_fp)) {
1115 		(void) fputs(line, zpool_cap_fp);
1116 	}
1117 
1118 	(void) fclose(zpool_cap_fp);
1119 	(void) fclose(cap_fp);
1120 
1121 done:
1122 	if (be_mounted)
1123 		(void) _be_unmount(bt->obe_name, 0);
1124 
1125 	if (pool_mounted) {
1126 		err = be_unmount_pool(zhp, tmp_mntpnt, orig_mntpnt);
1127 		if (ret == BE_SUCCESS)
1128 			ret = err;
1129 		free(orig_mntpnt);
1130 		free(tmp_mntpnt);
1131 		zfs_close(zhp);
1132 	}
1133 	return (ret);
1134 }
1135 
1136 /*
1137  * Function:	be_is_install_needed
1138  * Description:	Check detached version files to detect if bootloader
1139  *		install/update is needed.
1140  *
1141  * Parameters:
1142  *              bt - The transaction data for the BE we're activating.
1143  *		update - set B_TRUE is update is needed.
1144  * Return:
1145  *		BE_SUCCESS - Success
1146  *		be_errno_t - Failure
1147  *
1148  * Scope:
1149  *		Private
1150  */
1151 static int
1152 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1153 {
1154 	int	ret = BE_SUCCESS;
1155 	char	*cur_vers = NULL, *new_vers = NULL;
1156 
1157 	assert(bt != NULL);
1158 	assert(update != NULL);
1159 
1160 	if (!be_has_grub()) {
1161 		/*
1162 		 * no detached versioning, let installboot to manage
1163 		 * versioning.
1164 		 */
1165 		*update = B_TRUE;
1166 		return (ret);
1167 	}
1168 
1169 	*update = B_FALSE;	/* set default */
1170 
1171 	/*
1172 	 * We need to check to see if the version number from
1173 	 * the BE being activated is greater than the current
1174 	 * one.
1175 	 */
1176 	ret = be_get_grub_vers(bt, &cur_vers, &new_vers);
1177 	if (ret != BE_SUCCESS) {
1178 		be_print_err(gettext("be_activate: failed to get grub "
1179 		    "versions from capability files.\n"));
1180 		return (ret);
1181 	}
1182 	/* update if we have both versions and can compare */
1183 	if (cur_vers != NULL) {
1184 		if (new_vers != NULL) {
1185 			if (atof(cur_vers) < atof(new_vers))
1186 				*update = B_TRUE;
1187 			free(new_vers);
1188 		}
1189 		free(cur_vers);
1190 	} else if (new_vers != NULL) {
1191 		/* we only got new version - update */
1192 		*update = B_TRUE;
1193 		free(new_vers);
1194 	}
1195 	return (ret);
1196 }
1197 
1198 /*
1199  * Function:	be_do_installboot
1200  * Description:	This function runs installgrub/installboot using the boot
1201  *		loader files from the BE we're activating and installing
1202  *		them on the pool the BE lives in.
1203  *
1204  * Parameters:
1205  *              bt - The transaction data for the BE we're activating.
1206  *		flags - flags for bootloader install
1207  * Return:
1208  *		BE_SUCCESS - Success
1209  *		be_errno_t - Failure
1210  *
1211  * Scope:
1212  *		Private
1213  */
1214 static int
1215 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
1216 {
1217 	zpool_handle_t  *zphp = NULL;
1218 	zfs_handle_t	*zhp = NULL;
1219 	nvlist_t **child, *nv, *config;
1220 	uint_t c, children = 0;
1221 	char *tmp_mntpt = NULL;
1222 	char stage1[MAXPATHLEN];
1223 	char stage2[MAXPATHLEN];
1224 	char *vname;
1225 	int ret = BE_SUCCESS;
1226 	boolean_t be_mounted = B_FALSE;
1227 	boolean_t update = B_FALSE;
1228 	boolean_t verbose = B_FALSE;
1229 
1230 	/*
1231 	 * check versions. This call is to support detached
1232 	 * version implementation like grub. Embedded versioning is
1233 	 * checked by actual installer.
1234 	 */
1235 	if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) {
1236 		ret = be_is_install_needed(bt, &update);
1237 		if (ret != BE_SUCCESS || update == B_FALSE)
1238 			return (ret);
1239 	}
1240 	verbose = do_print;
1241 
1242 	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1243 	    NULL) {
1244 		be_print_err(gettext("be_do_installboot: failed to "
1245 		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1246 		    libzfs_error_description(g_zfs));
1247 		ret = zfs_err_to_be_err(g_zfs);
1248 		return (ret);
1249 	}
1250 	if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
1251 		if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
1252 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1253 			be_print_err(gettext("be_do_installboot: failed to "
1254 			    "mount BE (%s)\n"), bt->obe_name);
1255 			ZFS_CLOSE(zhp);
1256 			return (ret);
1257 		}
1258 		be_mounted = B_TRUE;
1259 	}
1260 	ZFS_CLOSE(zhp);
1261 
1262 	if (be_is_isa("i386")) {
1263 		if (be_has_grub()) {
1264 			(void) snprintf(stage1, sizeof (stage1), "%s%s",
1265 			    tmp_mntpt, BE_GRUB_STAGE_1);
1266 			(void) snprintf(stage2, sizeof (stage2), "%s%s",
1267 			    tmp_mntpt, BE_GRUB_STAGE_2);
1268 		} else {
1269 			(void) snprintf(stage1, sizeof (stage1), "%s%s",
1270 			    tmp_mntpt, BE_LOADER_STAGE_1);
1271 			(void) snprintf(stage2, sizeof (stage2), "%s%s",
1272 			    tmp_mntpt, BE_LOADER_STAGE_2);
1273 		}
1274 	} else if (be_is_isa("sparc")) {
1275 		char *platform = be_get_platform();
1276 
1277 		if (platform == NULL) {
1278 			be_print_err(gettext("be_do_installboot: "
1279 			    "failed to detect system platform name\n"));
1280 			if (be_mounted)
1281 				(void) _be_unmount(bt->obe_name, 0);
1282 			free(tmp_mntpt);
1283 			return (BE_ERR_BOOTFILE_INST);
1284 		}
1285 		stage1[0] = '\0';	/* sparc has no stage1 */
1286 		(void) snprintf(stage2, sizeof (stage2),
1287 		    "%s/usr/platform/%s%s", tmp_mntpt,
1288 		    platform, BE_SPARC_BOOTBLK);
1289 	} else {
1290 		be_print_err(gettext("be_do_installboot: unsupported "
1291 		    "architecture.\n"));
1292 		return (BE_ERR_BOOTFILE_INST);
1293 	}
1294 
1295 	if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
1296 		be_print_err(gettext("be_do_installboot: failed to open "
1297 		    "pool (%s): %s\n"), bt->obe_zpool,
1298 		    libzfs_error_description(g_zfs));
1299 		ret = zfs_err_to_be_err(g_zfs);
1300 		if (be_mounted)
1301 			(void) _be_unmount(bt->obe_name, 0);
1302 		free(tmp_mntpt);
1303 		return (ret);
1304 	}
1305 
1306 	if ((config = zpool_get_config(zphp, NULL)) == NULL) {
1307 		be_print_err(gettext("be_do_installboot: failed to get zpool "
1308 		    "configuration information. %s\n"),
1309 		    libzfs_error_description(g_zfs));
1310 		ret = zfs_err_to_be_err(g_zfs);
1311 		goto done;
1312 	}
1313 
1314 	/*
1315 	 * Get the vdev tree
1316 	 */
1317 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
1318 		be_print_err(gettext("be_do_installboot: failed to get vdev "
1319 		    "tree: %s\n"), libzfs_error_description(g_zfs));
1320 		ret = zfs_err_to_be_err(g_zfs);
1321 		goto done;
1322 	}
1323 
1324 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1325 	    &children) != 0) {
1326 		be_print_err(gettext("be_do_installboot: failed to traverse "
1327 		    "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
1328 		ret = zfs_err_to_be_err(g_zfs);
1329 		goto done;
1330 	}
1331 	for (c = 0; c < children; c++) {
1332 		uint_t i, nchildren = 0;
1333 		nvlist_t **nvchild;
1334 
1335 		/* ensure update on child status */
1336 		vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose);
1337 		if (vname == NULL) {
1338 			be_print_err(gettext(
1339 			    "be_do_installboot: "
1340 			    "failed to get device name: %s\n"),
1341 			    libzfs_error_description(g_zfs));
1342 			ret = zfs_err_to_be_err(g_zfs);
1343 			goto done;
1344 		} else if (verbose == B_TRUE) {
1345 			be_print_err(gettext("be_do_installboot: "
1346 			    "device %s\n"), vname);
1347 		}
1348 		free(vname);
1349 
1350 		ret = nvlist_lookup_nvlist_array(child[c],
1351 		    ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren);
1352 		if (ret != 0) {
1353 			if (ret != ENOENT) {
1354 				be_print_err(gettext("be_do_installboot: "
1355 				    "failed to traverse the vdev tree: %s\n"),
1356 				    libzfs_error_description(g_zfs));
1357 				ret = zfs_err_to_be_err(g_zfs);
1358 				goto done;
1359 			}
1360 			nchildren = 0;	/* This is leaf device. */
1361 		}
1362 
1363 		if (nchildren != 0) {
1364 			for (i = 0; i < nchildren; i++) {
1365 				/* ensure update on child status */
1366 				vname = zpool_vdev_name(g_zfs, zphp,
1367 				    nvchild[i], verbose);
1368 				if (vname == NULL) {
1369 					be_print_err(gettext(
1370 					    "be_do_installboot: "
1371 					    "failed to get device name: %s\n"),
1372 					    libzfs_error_description(g_zfs));
1373 					ret = zfs_err_to_be_err(g_zfs);
1374 					goto done;
1375 				} else if (verbose == B_TRUE) {
1376 					be_print_err(gettext(
1377 					    "be_do_installboot: device %s\n"),
1378 					    vname);
1379 				}
1380 				free(vname);
1381 				ret = be_do_installboot_helper(zphp, nvchild[i],
1382 				    stage1, stage2, flags);
1383 				if (ret != BE_SUCCESS)
1384 					goto done;
1385 			}
1386 		} else {
1387 			ret = be_do_installboot_helper(zphp, child[c], stage1,
1388 			    stage2, flags);
1389 			if (ret != BE_SUCCESS)
1390 				goto done;
1391 		}
1392 	}
1393 
1394 	if (be_has_grub()) {
1395 		ret = be_do_copy_grub_cap(bt);
1396 	}
1397 
1398 done:
1399 	ZFS_CLOSE(zhp);
1400 	if (be_mounted)
1401 		(void) _be_unmount(bt->obe_name, 0);
1402 	zpool_close(zphp);
1403 	free(tmp_mntpt);
1404 	return (ret);
1405 }
1406 
1407 /*
1408  * Function:	be_promote_zone_ds
1409  * Description:	This function finds the zones for the BE being activated
1410  *              and the active zonepath dataset for each zone. Then each
1411  *              active zonepath dataset is promoted.
1412  *
1413  * Parameters:
1414  *              be_name - the name of the global zone BE that we need to
1415  *                       find the zones for.
1416  *              be_root_ds - the root dataset for be_name.
1417  * Return:
1418  *		BE_SUCCESS - Success
1419  *		be_errno_t - Failure
1420  *
1421  * Scope:
1422  *		Private
1423  */
1424 static int
1425 be_promote_zone_ds(char *be_name, char *be_root_ds)
1426 {
1427 	char		*zone_ds = NULL;
1428 	char		*temp_mntpt = NULL;
1429 	char		origin[MAXPATHLEN];
1430 	char		zoneroot_ds[MAXPATHLEN];
1431 	zfs_handle_t	*zhp = NULL;
1432 	zfs_handle_t	*z_zhp = NULL;
1433 	zoneList_t	zone_list = NULL;
1434 	zoneBrandList_t *brands = NULL;
1435 	boolean_t	be_mounted = B_FALSE;
1436 	int		zone_index = 0;
1437 	int		err = BE_SUCCESS;
1438 
1439 	/*
1440 	 * Get the supported zone brands so we can pass that
1441 	 * to z_get_nonglobal_zone_list_by_brand. Currently
1442 	 * only the ipkg and labeled brand zones are supported
1443 	 *
1444 	 */
1445 	if ((brands = be_get_supported_brandlist()) == NULL) {
1446 		be_print_err(gettext("be_promote_zone_ds: no supported "
1447 		    "brands\n"));
1448 		return (BE_SUCCESS);
1449 	}
1450 
1451 	if ((zhp = zfs_open(g_zfs, be_root_ds,
1452 	    ZFS_TYPE_FILESYSTEM)) == NULL) {
1453 		be_print_err(gettext("be_promote_zone_ds: Failed to open "
1454 		    "dataset (%s): %s\n"), be_root_ds,
1455 		    libzfs_error_description(g_zfs));
1456 		err = zfs_err_to_be_err(g_zfs);
1457 		z_free_brand_list(brands);
1458 		return (err);
1459 	}
1460 
1461 	if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1462 		if ((err = _be_mount(be_name, &temp_mntpt,
1463 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1464 			be_print_err(gettext("be_promote_zone_ds: failed to "
1465 			    "mount the BE for zones procesing.\n"));
1466 			ZFS_CLOSE(zhp);
1467 			z_free_brand_list(brands);
1468 			return (err);
1469 		}
1470 		be_mounted = B_TRUE;
1471 	}
1472 
1473 	/*
1474 	 * Set the zone root to the temp mount point for the BE we just mounted.
1475 	 */
1476 	z_set_zone_root(temp_mntpt);
1477 
1478 	/*
1479 	 * Get all the zones based on the brands we're looking for. If no zones
1480 	 * are found that we're interested in unmount the BE and move on.
1481 	 */
1482 	if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1483 		if (be_mounted)
1484 			(void) _be_unmount(be_name, 0);
1485 		ZFS_CLOSE(zhp);
1486 		z_free_brand_list(brands);
1487 		free(temp_mntpt);
1488 		return (BE_SUCCESS);
1489 	}
1490 	for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1491 	    != NULL; zone_index++) {
1492 		char *zone_path = NULL;
1493 
1494 		/* Skip zones that aren't at least installed */
1495 		if (z_zlist_get_current_state(zone_list, zone_index) <
1496 		    ZONE_STATE_INSTALLED)
1497 			continue;
1498 
1499 		if (((zone_path =
1500 		    z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1501 		    ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1502 		    !be_zone_supported(zone_ds))
1503 			continue;
1504 
1505 		if (be_find_active_zone_root(zhp, zone_ds,
1506 		    zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1507 			be_print_err(gettext("be_promote_zone_ds: "
1508 			    "Zone does not have an active root "
1509 			    "dataset, skipping this zone.\n"));
1510 			continue;
1511 		}
1512 
1513 		if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1514 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1515 			be_print_err(gettext("be_promote_zone_ds: "
1516 			    "Failed to open dataset "
1517 			    "(%s): %s\n"), zoneroot_ds,
1518 			    libzfs_error_description(g_zfs));
1519 			err = zfs_err_to_be_err(g_zfs);
1520 			goto done;
1521 		}
1522 
1523 		if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1524 		    sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1525 			ZFS_CLOSE(z_zhp);
1526 			continue;
1527 		}
1528 
1529 		/*
1530 		 * We don't need to close the zfs handle at this
1531 		 * point because the callback funtion
1532 		 * be_promote_ds_callback() will close it for us.
1533 		 */
1534 		if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1535 			be_print_err(gettext("be_promote_zone_ds: "
1536 			    "failed to activate the "
1537 			    "datasets for %s: %s\n"),
1538 			    zoneroot_ds,
1539 			    libzfs_error_description(g_zfs));
1540 			err = BE_ERR_PROMOTE;
1541 			goto done;
1542 		}
1543 	}
1544 done:
1545 	if (be_mounted)
1546 		(void) _be_unmount(be_name, 0);
1547 	ZFS_CLOSE(zhp);
1548 	free(temp_mntpt);
1549 	z_free_brand_list(brands);
1550 	z_free_zone_list(zone_list);
1551 	return (err);
1552 }
1553 
1554 /*
1555  * Function:	be_promote_ds_callback
1556  * Description:	This function is used to promote the datasets for the BE
1557  *		being activated as well as the datasets for the zones BE
1558  *		being activated.
1559  *
1560  * Parameters:
1561  *              zhp - the zfs handle for zone BE being activated.
1562  *		data - not used.
1563  * Return:
1564  *		0 - Success
1565  *		be_errno_t - Failure
1566  *
1567  * Scope:
1568  *		Private
1569  */
1570 static int
1571 /* LINTED */
1572 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1573 {
1574 	char	origin[MAXPATHLEN];
1575 	char	*sub_dataset = NULL;
1576 	int	ret = 0;
1577 
1578 	if (zhp != NULL) {
1579 		sub_dataset = strdup(zfs_get_name(zhp));
1580 		if (sub_dataset == NULL) {
1581 			ret = BE_ERR_NOMEM;
1582 			goto done;
1583 		}
1584 	} else {
1585 		be_print_err(gettext("be_promote_ds_callback: "
1586 		    "Invalid zfs handle passed into function\n"));
1587 		ret = BE_ERR_INVAL;
1588 		goto done;
1589 	}
1590 
1591 	/*
1592 	 * This loop makes sure that we promote the dataset to the
1593 	 * top of the tree so that it is no longer a decendent of any
1594 	 * dataset. The ZFS close and then open is used to make sure that
1595 	 * the promotion is updated before we move on.
1596 	 */
1597 	while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1598 	    sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1599 		if (zfs_promote(zhp) != 0) {
1600 			if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1601 				be_print_err(gettext("be_promote_ds_callback: "
1602 				    "promote of %s failed: %s\n"),
1603 				    zfs_get_name(zhp),
1604 				    libzfs_error_description(g_zfs));
1605 				ret = zfs_err_to_be_err(g_zfs);
1606 				goto done;
1607 			} else {
1608 				/*
1609 				 * If the call to zfs_promote returns the
1610 				 * error EZFS_EXISTS we've hit a snapshot name
1611 				 * collision. This means we're probably
1612 				 * attemping to promote a zone dataset above a
1613 				 * parent dataset that belongs to another zone
1614 				 * which this zone was cloned from.
1615 				 *
1616 				 * TODO: If this is a zone dataset at some
1617 				 * point we should skip this if the zone
1618 				 * paths for the dataset and the snapshot
1619 				 * don't match.
1620 				 */
1621 				be_print_err(gettext("be_promote_ds_callback: "
1622 				    "promote of %s failed due to snapshot "
1623 				    "name collision: %s\n"), zfs_get_name(zhp),
1624 				    libzfs_error_description(g_zfs));
1625 				ret = zfs_err_to_be_err(g_zfs);
1626 				goto done;
1627 			}
1628 		}
1629 		ZFS_CLOSE(zhp);
1630 		if ((zhp = zfs_open(g_zfs, sub_dataset,
1631 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1632 			be_print_err(gettext("be_promote_ds_callback: "
1633 			    "Failed to open dataset (%s): %s\n"), sub_dataset,
1634 			    libzfs_error_description(g_zfs));
1635 			ret = zfs_err_to_be_err(g_zfs);
1636 			goto done;
1637 		}
1638 	}
1639 
1640 	/* Iterate down this dataset's children and promote them */
1641 	ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1642 
1643 done:
1644 	free(sub_dataset);
1645 	ZFS_CLOSE(zhp);
1646 	return (ret);
1647 }
1648