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