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