xref: /illumos-gate/usr/src/lib/libbe/common/be_activate.c (revision 3665ce8aeee26b1a84fb98951ef011e0779e1ae2)
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, *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  */
1027 static int
1028 be_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 
1133 done:
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  */
1163 static int
1164 be_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 
1210 static int
1211 be_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  */
1281 static int
1282 be_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 
1392 done:
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  */
1418 static int
1419 be_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 	}
1538 done:
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  */
1564 static int
1565 /* LINTED */
1566 be_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 
1637 done:
1638 	free(sub_dataset);
1639 	ZFS_CLOSE(zhp);
1640 	return (ret);
1641 }
1642