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