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