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 #include <assert.h>
27 #include <libintl.h>
28 #include <libnvpair.h>
29 #include <libzfs.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <sys/mnttab.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 
39 #include <libbe.h>
40 #include <libbe_priv.h>
41 
42 char	*mnttab = MNTTAB;
43 
44 /*
45  * Private function prototypes
46  */
47 static int set_bootfs(char *boot_rpool, char *be_root_ds);
48 static int set_canmount(be_node_list_t *, char *);
49 static int be_do_installgrub(be_transaction_data_t *);
50 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
51 static int get_ver_from_capfile(char *, char **);
52 static int be_promote_zone_ds(char *, char *);
53 static int be_promote_ds_callback(zfs_handle_t *, void *);
54 
55 /* ******************************************************************** */
56 /*			Public Functions				*/
57 /* ******************************************************************** */
58 
59 /*
60  * Function:	be_activate
61  * Description:	Calls _be_activate which activates the BE named in the
62  *		attributes passed in through be_attrs. The process of
63  *		activation sets the bootfs property of the root pool, resets
64  *		the canmount property to noauto, and sets the default in the
65  *		grub menu to the entry corresponding to the entry for the named
66  *		BE.
67  * Parameters:
68  *		be_attrs - pointer to nvlist_t of attributes being passed in.
69  *			The follow attribute values are used by this function:
70  *
71  *			BE_ATTR_ORIG_BE_NAME		*required
72  * Return:
73  *		BE_SUCCESS - Success
74  *		be_errno_t - Failure
75  * Scope:
76  *		Public
77  */
78 int
79 be_activate(nvlist_t *be_attrs)
80 {
81 	int	ret = BE_SUCCESS;
82 	char	*be_name = NULL;
83 
84 	/* Initialize libzfs handle */
85 	if (!be_zfs_init())
86 		return (BE_ERR_INIT);
87 
88 	/* Get the BE name to activate */
89 	if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
90 	    != 0) {
91 		be_print_err(gettext("be_activate: failed to "
92 		    "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
93 		be_zfs_fini();
94 		return (BE_ERR_INVAL);
95 	}
96 
97 	/* Validate BE name */
98 	if (!be_valid_be_name(be_name)) {
99 		be_print_err(gettext("be_activate: invalid BE name %s\n"),
100 		    be_name);
101 		be_zfs_fini();
102 		return (BE_ERR_INVAL);
103 	}
104 
105 	ret = _be_activate(be_name);
106 
107 	be_zfs_fini();
108 
109 	return (ret);
110 }
111 
112 /* ******************************************************************** */
113 /*			Semi Private Functions				*/
114 /* ******************************************************************** */
115 
116 /*
117  * Function:	_be_activate
118  * Description:	This does the actual work described in be_activate.
119  * Parameters:
120  *		be_name - pointer to the name of BE to activate.
121  *
122  * Return:
123  *		BE_SUCCESS - Success
124  *		be_errnot_t - Failure
125  * Scope:
126  *		Public
127  */
128 int
129 _be_activate(char *be_name)
130 {
131 	be_transaction_data_t cb = { 0 };
132 	zfs_handle_t	*zhp = NULL;
133 	char		root_ds[MAXPATHLEN];
134 	char		*cur_vers = NULL, *new_vers = NULL;
135 	be_node_list_t	*be_nodes = NULL;
136 	uuid_t		uu = {0};
137 	int		entry, ret = BE_SUCCESS;
138 	int		zret = 0;
139 
140 	/*
141 	 * TODO: The BE needs to be validated to make sure that it is actually
142 	 * a bootable BE.
143 	 */
144 
145 	if (be_name == NULL)
146 		return (BE_ERR_INVAL);
147 
148 	/* Set obe_name to be_name in the cb structure */
149 	cb.obe_name = be_name;
150 
151 	/* find which zpool the be is in */
152 	if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
153 		be_print_err(gettext("be_activate: failed to "
154 		    "find zpool for BE (%s)\n"), cb.obe_name);
155 		return (BE_ERR_BE_NOENT);
156 	} else if (zret < 0) {
157 		be_print_err(gettext("be_activate: "
158 		    "zpool_iter failed: %s\n"),
159 		    libzfs_error_description(g_zfs));
160 		ret = zfs_err_to_be_err(g_zfs);
161 		return (ret);
162 	}
163 
164 	be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
165 	cb.obe_root_ds = strdup(root_ds);
166 
167 	if (getzoneid() == GLOBAL_ZONEID) {
168 		if (be_has_grub() && (ret = be_get_grub_vers(&cb, &cur_vers,
169 		    &new_vers)) != BE_SUCCESS) {
170 			be_print_err(gettext("be_activate: failed to get grub "
171 			    "versions from capability files.\n"));
172 			return (ret);
173 		}
174 		if (cur_vers != NULL) {
175 			/*
176 			 * We need to check to see if the version number from
177 			 * the BE being activated is greater than the current
178 			 * one.
179 			 */
180 			if (new_vers != NULL &&
181 			    atof(cur_vers) < atof(new_vers)) {
182 				if ((ret = be_do_installgrub(&cb))
183 				    != BE_SUCCESS) {
184 					free(new_vers);
185 					free(cur_vers);
186 					return (ret);
187 				}
188 				free(new_vers);
189 			}
190 			free(cur_vers);
191 		} else if (new_vers != NULL) {
192 			if ((ret = be_do_installgrub(&cb)) != BE_SUCCESS) {
193 				free(new_vers);
194 				return (ret);
195 			}
196 			free(new_vers);
197 		}
198 		if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
199 			if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
200 			    NULL, NULL, NULL)) != BE_SUCCESS) {
201 				be_print_err(gettext("be_activate: Failed to "
202 				    "add BE (%s) to the GRUB menu\n"),
203 				    cb.obe_name);
204 				goto done;
205 			}
206 		}
207 		if (be_has_grub()) {
208 			if ((ret = be_change_grub_default(cb.obe_name,
209 			    cb.obe_zpool)) != BE_SUCCESS) {
210 				be_print_err(gettext("be_activate: failed to "
211 				    "change the default entry in menu.lst\n"));
212 				goto done;
213 			}
214 		}
215 	}
216 
217 	if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
218 		return (ret);
219 	}
220 
221 	if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
222 		be_print_err(gettext("be_activate: failed to set "
223 		    "canmount dataset property\n"));
224 		goto done;
225 	}
226 
227 	if ((ret = set_bootfs(be_nodes->be_rpool, root_ds)) != BE_SUCCESS) {
228 		be_print_err(gettext("be_activate: failed to set "
229 		    "bootfs pool property for %s\n"), root_ds);
230 		goto done;
231 	}
232 
233 	if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
234 		/*
235 		 * We don't need to close the zfs handle at this
236 		 * point because The callback funtion
237 		 * be_promote_ds_callback() will close it for us.
238 		 */
239 		if (be_promote_ds_callback(zhp, NULL) != 0) {
240 			be_print_err(gettext("be_activate: "
241 			    "failed to activate the "
242 			    "datasets for %s: %s\n"),
243 			    root_ds,
244 			    libzfs_error_description(g_zfs));
245 			ret = BE_ERR_PROMOTE;
246 			goto done;
247 		}
248 	} else {
249 		be_print_err(gettext("be_activate:: failed to open "
250 		    "dataset (%s): %s\n"), root_ds,
251 		    libzfs_error_description(g_zfs));
252 		ret = zfs_err_to_be_err(g_zfs);
253 		goto done;
254 	}
255 
256 	if (getzoneid() == GLOBAL_ZONEID &&
257 	    be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
258 	    (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
259 	    != BE_SUCCESS) {
260 		be_print_err(gettext("be_activate: failed to promote "
261 		    "the active zonepath datasets for zones in BE %s\n"),
262 		    cb.obe_name);
263 	}
264 
265 done:
266 	be_free_list(be_nodes);
267 	return (ret);
268 }
269 
270 /*
271  * Function:	be_activate_current_be
272  * Description:	Set the currently "active" BE to be "active on boot"
273  * Paramters:
274  *		none
275  * Returns:
276  *		BE_SUCCESS - Success
277  *		be_errnot_t - Failure
278  * Scope:
279  *		Semi-private (library wide use only)
280  */
281 int
282 be_activate_current_be(void)
283 {
284 	int ret = BE_SUCCESS;
285 	be_transaction_data_t bt = { 0 };
286 
287 	if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
288 		return (ret);
289 	}
290 
291 	if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
292 		be_print_err(gettext("be_activate_current_be: failed to "
293 		    "activate %s\n"), bt.obe_name);
294 		return (ret);
295 	}
296 
297 	return (BE_SUCCESS);
298 }
299 
300 /*
301  * Function:	be_is_active_on_boot
302  * Description:	Checks if the BE name passed in has the "active on boot"
303  *		property set to B_TRUE.
304  * Paramters:
305  *		be_name - the name of the BE to check
306  * Returns:
307  *		B_TRUE - if active on boot.
308  *		B_FALSE - if not active on boot.
309  * Scope:
310  *		Semi-private (library wide use only)
311  */
312 boolean_t
313 be_is_active_on_boot(char *be_name)
314 {
315 	be_node_list_t *be_node = NULL;
316 
317 	if (be_name == NULL) {
318 		be_print_err(gettext("be_is_active_on_boot: "
319 		    "be_name must not be NULL\n"));
320 		return (B_FALSE);
321 	}
322 
323 	if (_be_list(be_name, &be_node) != BE_SUCCESS) {
324 		return (B_FALSE);
325 	}
326 
327 	if (be_node == NULL) {
328 		return (B_FALSE);
329 	}
330 
331 	if (be_node->be_active_on_boot) {
332 		be_free_list(be_node);
333 		return (B_TRUE);
334 	} else {
335 		be_free_list(be_node);
336 		return (B_FALSE);
337 	}
338 }
339 
340 /* ******************************************************************** */
341 /*			Private Functions				*/
342 /* ******************************************************************** */
343 
344 /*
345  * Function:	set_bootfs
346  * Description:	Sets the bootfs property on the boot pool to be the
347  *		root dataset of the activated BE.
348  * Parameters:
349  *		boot_pool - The pool we're setting bootfs in.
350  *		be_root_ds - The main dataset for the BE.
351  * Return:
352  *		BE_SUCCESS - Success
353  *		be_errno_t - Failure
354  * Scope:
355  *		Private
356  */
357 static int
358 set_bootfs(char *boot_rpool, char *be_root_ds)
359 {
360 	zpool_handle_t *zhp;
361 	int err = BE_SUCCESS;
362 
363 	if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
364 		be_print_err(gettext("set_bootfs: failed to open pool "
365 		    "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
366 		err = zfs_err_to_be_err(g_zfs);
367 		return (err);
368 	}
369 
370 	err = zpool_set_prop(zhp, "bootfs", be_root_ds);
371 	if (err) {
372 		be_print_err(gettext("set_bootfs: failed to set "
373 		    "bootfs property for pool %s: %s\n"), boot_rpool,
374 		    libzfs_error_description(g_zfs));
375 		err = zfs_err_to_be_err(g_zfs);
376 		zpool_close(zhp);
377 		return (err);
378 	}
379 
380 	zpool_close(zhp);
381 	return (BE_SUCCESS);
382 }
383 
384 /*
385  * Function:	set_canmount
386  * Description:	Sets the canmount property on the datasets of the
387  *		activated BE.
388  * Parameters:
389  *		be_nodes - The be_node_t returned from be_list
390  *		value - The value of canmount we setting, on|off|noauto.
391  * Return:
392  *		BE_SUCCESS - Success
393  *		be_errno_t - Failure
394  * Scope:
395  *		Private
396  */
397 static int
398 set_canmount(be_node_list_t *be_nodes, char *value)
399 {
400 	char		ds_path[MAXPATHLEN];
401 	zfs_handle_t	*zhp = NULL;
402 	be_node_list_t	*list = be_nodes;
403 	int		err = BE_SUCCESS;
404 
405 	while (list != NULL) {
406 		be_dataset_list_t *datasets = list->be_node_datasets;
407 
408 		be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
409 		    sizeof (ds_path));
410 
411 		if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
412 		    NULL) {
413 			be_print_err(gettext("set_canmount: failed to open "
414 			    "dataset (%s): %s\n"), ds_path,
415 			    libzfs_error_description(g_zfs));
416 			err = zfs_err_to_be_err(g_zfs);
417 			return (err);
418 		}
419 		if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
420 			/*
421 			 * it's already mounted so we can't change the
422 			 * canmount property anyway.
423 			 */
424 			err = BE_SUCCESS;
425 		} else {
426 			err = zfs_prop_set(zhp,
427 			    zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
428 			if (err) {
429 				ZFS_CLOSE(zhp);
430 				be_print_err(gettext("set_canmount: failed to "
431 				    "set dataset property (%s): %s\n"),
432 				    ds_path, libzfs_error_description(g_zfs));
433 				err = zfs_err_to_be_err(g_zfs);
434 				return (err);
435 			}
436 		}
437 		ZFS_CLOSE(zhp);
438 
439 		while (datasets != NULL) {
440 			be_make_root_ds(list->be_rpool,
441 			    datasets->be_dataset_name, ds_path,
442 			    sizeof (ds_path));
443 
444 			if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
445 			    == NULL) {
446 				be_print_err(gettext("set_canmount: failed to "
447 				    "open dataset %s: %s\n"), ds_path,
448 				    libzfs_error_description(g_zfs));
449 				err = zfs_err_to_be_err(g_zfs);
450 				return (err);
451 			}
452 			if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
453 				/*
454 				 * it's already mounted so we can't change the
455 				 * canmount property anyway.
456 				 */
457 				err = BE_SUCCESS;
458 				ZFS_CLOSE(zhp);
459 				break;
460 			}
461 			err = zfs_prop_set(zhp,
462 			    zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
463 			if (err) {
464 				ZFS_CLOSE(zhp);
465 				be_print_err(gettext("set_canmount: "
466 				    "Failed to set property value %s "
467 				    "for dataset %s: %s\n"), value, ds_path,
468 				    libzfs_error_description(g_zfs));
469 				err = zfs_err_to_be_err(g_zfs);
470 				return (err);
471 			}
472 			ZFS_CLOSE(zhp);
473 			datasets = datasets->be_next_dataset;
474 		}
475 		list = list->be_next_node;
476 	}
477 	return (err);
478 }
479 
480 /*
481  * Function:	be_get_grub_vers
482  * Description:	Gets the grub version number from /boot/grub/capability. If
483  *              capability file doesn't exist NULL is returned.
484  * Parameters:
485  *              bt - The transaction data for the BE we're getting the grub
486  *                   version for.
487  *              cur_vers - used to return the current version of grub from
488  *                         the root pool.
489  *              new_vers - used to return the grub version of the BE we're
490  *                         activating.
491  * Return:
492  *              BE_SUCCESS - Success
493  *              be_errno_t - Failed to find version
494  * Scope:
495  *		Private
496  */
497 static int
498 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
499 {
500 	zfs_handle_t	*zhp = NULL;
501 	zfs_handle_t	*pool_zhp = NULL;
502 	int ret = BE_SUCCESS;
503 	char cap_file[MAXPATHLEN];
504 	char *temp_mntpnt = NULL;
505 	char *zpool_mntpt = NULL;
506 	char *ptmp_mntpnt = NULL;
507 	char *orig_mntpnt = NULL;
508 	boolean_t be_mounted = B_FALSE;
509 	boolean_t pool_mounted = B_FALSE;
510 
511 	if (!be_has_grub()) {
512 		be_print_err(gettext("be_get_grub_vers: Not supported on "
513 		    "this architecture\n"));
514 		return (BE_ERR_NOTSUP);
515 	}
516 
517 	if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
518 	    bt->obe_root_ds == NULL) {
519 		be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
520 		return (BE_ERR_INVAL);
521 	}
522 
523 	if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
524 	    NULL) {
525 		be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
526 		    libzfs_error_description(g_zfs));
527 		return (zfs_err_to_be_err(g_zfs));
528 	}
529 
530 	/*
531 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
532 	 * attempt to mount it.
533 	 */
534 	if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
535 	    &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
536 		be_print_err(gettext("be_get_grub_vers: pool dataset "
537 		    "(%s) could not be mounted\n"), bt->obe_zpool);
538 		ZFS_CLOSE(pool_zhp);
539 		return (ret);
540 	}
541 
542 	/*
543 	 * Get the mountpoint for the root pool dataset.
544 	 */
545 	if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
546 		be_print_err(gettext("be_get_grub_vers: pool "
547 		    "dataset (%s) is not mounted. Can't set the "
548 		    "default BE in the grub menu.\n"), bt->obe_zpool);
549 		ret = BE_ERR_NO_MENU;
550 		goto cleanup;
551 	}
552 
553 	/*
554 	 * get the version of the most recent grub update.
555 	 */
556 	(void) snprintf(cap_file, sizeof (cap_file), "%s%s",
557 	    zpool_mntpt, BE_CAP_FILE);
558 	free(zpool_mntpt);
559 	zpool_mntpt = NULL;
560 
561 	if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
562 		goto cleanup;
563 
564 	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
565 	    NULL) {
566 		be_print_err(gettext("be_get_grub_vers: failed to "
567 		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
568 		    libzfs_error_description(g_zfs));
569 		free(cur_vers);
570 		ret = zfs_err_to_be_err(g_zfs);
571 		goto cleanup;
572 	}
573 	if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
574 		if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
575 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
576 			be_print_err(gettext("be_get_grub_vers: failed to "
577 			    "mount BE (%s)\n"), bt->obe_name);
578 			free(*cur_vers);
579 			*cur_vers = NULL;
580 			ZFS_CLOSE(zhp);
581 			goto cleanup;
582 		}
583 		be_mounted = B_TRUE;
584 	}
585 	ZFS_CLOSE(zhp);
586 
587 	/*
588 	 * Now get the grub version for the BE being activated.
589 	 */
590 	(void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
591 	    BE_CAP_FILE);
592 	ret = get_ver_from_capfile(cap_file, new_vers);
593 	if (ret != BE_SUCCESS) {
594 		free(*cur_vers);
595 		*cur_vers = NULL;
596 	}
597 	if (be_mounted)
598 		(void) _be_unmount(bt->obe_name, 0);
599 
600 cleanup:
601 	if (pool_mounted) {
602 		int iret = BE_SUCCESS;
603 		iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
604 		if (ret == BE_SUCCESS)
605 			ret = iret;
606 		free(orig_mntpnt);
607 		free(ptmp_mntpnt);
608 	}
609 	ZFS_CLOSE(pool_zhp);
610 
611 	free(temp_mntpnt);
612 	return (ret);
613 }
614 
615 /*
616  * Function:	get_ver_from_capfile
617  * Description: Parses the capability file passed in looking for the VERSION
618  *              line. If found the version is returned in vers, if not then
619  *              NULL is returned in vers.
620  *
621  * Parameters:
622  *              file - the path to the capability file we want to parse.
623  *              vers - the version string that will be passed back.
624  * Return:
625  *              BE_SUCCESS - Success
626  *              be_errno_t - Failed to find version
627  * Scope:
628  *		Private
629  */
630 static int
631 get_ver_from_capfile(char *file, char **vers)
632 {
633 	FILE *fp = NULL;
634 	char line[BUFSIZ];
635 	char *last = NULL;
636 	int err = BE_SUCCESS;
637 	errno = 0;
638 
639 	if (!be_has_grub()) {
640 		be_print_err(gettext("get_ver_from_capfile: Not supported "
641 		    "on this architecture\n"));
642 		return (BE_ERR_NOTSUP);
643 	}
644 
645 	/*
646 	 * Set version string to NULL; the only case this shouldn't be set
647 	 * to be NULL is when we've actually found a version in the capability
648 	 * file, which is set below.
649 	 */
650 	*vers = NULL;
651 
652 	/*
653 	 * If the capability file doesn't exist, we're returning success
654 	 * because on older releases, the capability file did not exist
655 	 * so this is a valid scenario.
656 	 */
657 	if (access(file, F_OK) == 0) {
658 		if ((fp = fopen(file, "r")) == NULL) {
659 			err = errno;
660 			be_print_err(gettext("get_ver_from_capfile: failed to "
661 			    "open file %s with error %s\n"), file,
662 			    strerror(err));
663 			err = errno_to_be_err(err);
664 			return (err);
665 		}
666 
667 		while (fgets(line, BUFSIZ, fp)) {
668 			char *tok = strtok_r(line, "=", &last);
669 
670 			if (tok == NULL || tok[0] == '#') {
671 				continue;
672 			} else if (strcmp(tok, "VERSION") == 0) {
673 				*vers = strdup(last);
674 				break;
675 			}
676 		}
677 		(void) fclose(fp);
678 	}
679 
680 	return (BE_SUCCESS);
681 }
682 
683 /*
684  * Function:	be_do_installgrub
685  * Description:	This function runs installgrub using the grub loader files
686  *              from the BE we're activating and installing them on the
687  *              pool the BE lives in.
688  *
689  * Parameters:
690  *              bt - The transaction data for the BE we're activating.
691  * Return:
692  *		BE_SUCCESS - Success
693  *		be_errno_t - Failure
694  *
695  * Scope:
696  *		Private
697  */
698 static int
699 be_do_installgrub(be_transaction_data_t *bt)
700 {
701 	zpool_handle_t  *zphp = NULL;
702 	zfs_handle_t	*zhp = NULL;
703 	nvlist_t **child, *nv, *config;
704 	uint_t c, children = 0;
705 	char *tmp_mntpt = NULL;
706 	char *pool_mntpnt = NULL;
707 	char *ptmp_mntpnt = NULL;
708 	char *orig_mntpnt = NULL;
709 	FILE *cap_fp = NULL;
710 	FILE *zpool_cap_fp = NULL;
711 	char line[BUFSIZ];
712 	char cap_file[MAXPATHLEN];
713 	char zpool_cap_file[MAXPATHLEN];
714 	char stage1[MAXPATHLEN];
715 	char stage2[MAXPATHLEN];
716 	char installgrub_cmd[MAXPATHLEN];
717 	char *vname;
718 	char be_run_cmd_errbuf[BUFSIZ];
719 	int ret = BE_SUCCESS;
720 	int err = 0;
721 	boolean_t be_mounted = B_FALSE;
722 	boolean_t pool_mounted = B_FALSE;
723 
724 	if (!be_has_grub()) {
725 		be_print_err(gettext("be_do_installgrub: Not supported "
726 		    "on this architecture\n"));
727 		return (BE_ERR_NOTSUP);
728 	}
729 
730 	if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
731 	    NULL) {
732 		be_print_err(gettext("be_do_installgrub: failed to "
733 		    "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
734 		    libzfs_error_description(g_zfs));
735 		ret = zfs_err_to_be_err(g_zfs);
736 		return (ret);
737 	}
738 	if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
739 		if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
740 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
741 			be_print_err(gettext("be_do_installgrub: failed to "
742 			    "mount BE (%s)\n"), bt->obe_name);
743 			ZFS_CLOSE(zhp);
744 			return (ret);
745 		}
746 		be_mounted = B_TRUE;
747 	}
748 	ZFS_CLOSE(zhp);
749 
750 	(void) snprintf(stage1, sizeof (stage1), "%s%s", tmp_mntpt, BE_STAGE_1);
751 	(void) snprintf(stage2, sizeof (stage2), "%s%s", tmp_mntpt, BE_STAGE_2);
752 
753 	if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
754 		be_print_err(gettext("be_do_installgrub: failed to open "
755 		    "pool (%s): %s\n"), bt->obe_zpool,
756 		    libzfs_error_description(g_zfs));
757 		ret = zfs_err_to_be_err(g_zfs);
758 		if (be_mounted)
759 			(void) _be_unmount(bt->obe_name, 0);
760 		free(tmp_mntpt);
761 		return (ret);
762 	}
763 
764 	if ((config = zpool_get_config(zphp, NULL)) == NULL) {
765 		be_print_err(gettext("be_do_installgrub: failed to get zpool "
766 		    "configuration information. %s\n"),
767 		    libzfs_error_description(g_zfs));
768 		ret = zfs_err_to_be_err(g_zfs);
769 		goto done;
770 	}
771 
772 	/*
773 	 * Get the vdev tree
774 	 */
775 	if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
776 		be_print_err(gettext("be_do_installgrub: failed to get vdev "
777 		    "tree: %s\n"), libzfs_error_description(g_zfs));
778 		ret = zfs_err_to_be_err(g_zfs);
779 		goto done;
780 	}
781 
782 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
783 	    &children) != 0) {
784 		be_print_err(gettext("be_do_installgrub: failed to traverse "
785 		    "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
786 		ret = zfs_err_to_be_err(g_zfs);
787 		goto done;
788 	}
789 	for (c = 0; c < children; c++) {
790 		uint_t i, nchildren = 0;
791 		nvlist_t **nvchild;
792 		vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
793 		if (vname == NULL) {
794 			be_print_err(gettext(
795 			    "be_do_installgrub: "
796 			    "failed to get device name: %s\n"),
797 			    libzfs_error_description(g_zfs));
798 			ret = zfs_err_to_be_err(g_zfs);
799 			goto done;
800 		}
801 		if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {
802 
803 			if (nvlist_lookup_nvlist_array(child[c],
804 			    ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
805 				be_print_err(gettext("be_do_installgrub: "
806 				    "failed to traverse the vdev tree: %s\n"),
807 				    libzfs_error_description(g_zfs));
808 				ret = zfs_err_to_be_err(g_zfs);
809 				goto done;
810 			}
811 
812 			for (i = 0; i < nchildren; i++) {
813 				vname = zpool_vdev_name(g_zfs, zphp,
814 				    nvchild[i], B_FALSE);
815 				if (vname == NULL) {
816 					be_print_err(gettext(
817 					    "be_do_installgrub: "
818 					    "failed to get device name: %s\n"),
819 					    libzfs_error_description(g_zfs));
820 					ret = zfs_err_to_be_err(g_zfs);
821 					goto done;
822 				}
823 
824 				(void) snprintf(installgrub_cmd,
825 				    sizeof (installgrub_cmd),
826 				    "%s %s %s /dev/rdsk/%s",
827 				    BE_INSTALL_GRUB, stage1, stage2, vname);
828 				if (be_run_cmd(installgrub_cmd,
829 				    be_run_cmd_errbuf, BUFSIZ, NULL, 0) !=
830 				    BE_SUCCESS) {
831 					be_print_err(gettext(
832 					    "be_do_installgrub: installgrub "
833 					    "failed for device %s.\n"), vname);
834 					/* Assume localized cmd err output. */
835 					be_print_err(gettext(
836 					    "  Command: \"%s\"\n"),
837 					    installgrub_cmd);
838 					be_print_err("%s", be_run_cmd_errbuf);
839 					free(vname);
840 					ret = BE_ERR_BOOTFILE_INST;
841 					goto done;
842 				}
843 				free(vname);
844 			}
845 		} else {
846 			(void) snprintf(installgrub_cmd,
847 			    sizeof (installgrub_cmd), "%s %s %s /dev/rdsk/%s",
848 			    BE_INSTALL_GRUB, stage1, stage2, vname);
849 			if (be_run_cmd(installgrub_cmd, be_run_cmd_errbuf,
850 			    BUFSIZ, NULL, 0) != BE_SUCCESS) {
851 				be_print_err(gettext(
852 				    "be_do_installgrub: installgrub "
853 				    "failed for device %s.\n"), vname);
854 				/* Assume localized cmd err output. */
855 				be_print_err(gettext("  Command: \"%s\"\n"),
856 				    installgrub_cmd);
857 				be_print_err("%s", be_run_cmd_errbuf);
858 				free(vname);
859 				ret = BE_ERR_BOOTFILE_INST;
860 				goto done;
861 			}
862 			free(vname);
863 		}
864 	}
865 
866 	/*
867 	 * Copy the grub capability file from the BE we're activating into
868 	 * the root pool.
869 	 */
870 	(void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpt,
871 	    BE_CAP_FILE);
872 
873 	if ((zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
874 	    NULL) {
875 		be_print_err(gettext("be_do_installgrub: zfs_open "
876 		    "failed: %s\n"), libzfs_error_description(g_zfs));
877 		zpool_close(zphp);
878 		return (zfs_err_to_be_err(g_zfs));
879 	}
880 
881 	/*
882 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
883 	 * attempt to mount it.
884 	 */
885 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt,
886 	    &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
887 		be_print_err(gettext("be_do_installgrub: pool dataset "
888 		    "(%s) could not be mounted\n"), bt->obe_zpool);
889 		ZFS_CLOSE(zhp);
890 		zpool_close(zphp);
891 		return (ret);
892 	}
893 
894 	/*
895 	 * Get the mountpoint for the root pool dataset.
896 	 */
897 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
898 		be_print_err(gettext("be_do_installgrub: pool "
899 		    "dataset (%s) is not mounted. Can't check the grub "
900 		    "version from the grub capability file.\n"), bt->obe_zpool);
901 		ret = BE_ERR_NO_MENU;
902 		goto done;
903 	}
904 
905 	(void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
906 	    pool_mntpnt, BE_CAP_FILE);
907 
908 	free(pool_mntpnt);
909 	pool_mntpnt = NULL;
910 
911 	if ((cap_fp = fopen(cap_file, "r")) == NULL) {
912 		err = errno;
913 		be_print_err(gettext("be_do_installgrub: failed to open grub "
914 		    "capability file\n"));
915 		ret = errno_to_be_err(err);
916 		goto done;
917 	}
918 	if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
919 		err = errno;
920 		be_print_err(gettext("be_do_installgrub: failed to open new "
921 		    "grub capability file\n"));
922 		ret = errno_to_be_err(err);
923 		(void) fclose(cap_fp);
924 		goto done;
925 	}
926 
927 	while (fgets(line, BUFSIZ, cap_fp)) {
928 		(void) fputs(line, zpool_cap_fp);
929 	}
930 
931 	(void) fclose(zpool_cap_fp);
932 	(void) fclose(cap_fp);
933 
934 done:
935 	if (pool_mounted) {
936 		int iret = 0;
937 		iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
938 		if (ret == BE_SUCCESS)
939 			ret = iret;
940 		free(orig_mntpnt);
941 		free(ptmp_mntpnt);
942 	}
943 	ZFS_CLOSE(zhp);
944 	if (be_mounted)
945 		(void) _be_unmount(bt->obe_name, 0);
946 	zpool_close(zphp);
947 	free(tmp_mntpt);
948 	return (ret);
949 }
950 
951 /*
952  * Function:	be_promote_zone_ds
953  * Description:	This function finds the zones for the BE being activated
954  *              and the active zonepath dataset for each zone. Then each
955  *              active zonepath dataset is promoted.
956  *
957  * Parameters:
958  *              be_name - the name of the global zone BE that we need to
959  *                       find the zones for.
960  *              be_root_ds - the root dataset for be_name.
961  * Return:
962  *		BE_SUCCESS - Success
963  *		be_errno_t - Failure
964  *
965  * Scope:
966  *		Private
967  */
968 static int
969 be_promote_zone_ds(char *be_name, char *be_root_ds)
970 {
971 	char		*zone_ds = NULL;
972 	char		*temp_mntpt = NULL;
973 	char		origin[MAXPATHLEN];
974 	char		zoneroot_ds[MAXPATHLEN];
975 	zfs_handle_t	*zhp = NULL;
976 	zfs_handle_t	*z_zhp = NULL;
977 	zoneList_t	zone_list = NULL;
978 	zoneBrandList_t *brands = NULL;
979 	boolean_t	be_mounted = B_FALSE;
980 	int		zone_index = 0;
981 	int		err = BE_SUCCESS;
982 
983 	/*
984 	 * Get the supported zone brands so we can pass that
985 	 * to z_get_nonglobal_zone_list_by_brand. Currently
986 	 * only the ipkg and labeled brand zones are supported
987 	 *
988 	 */
989 	if ((brands = be_get_supported_brandlist()) == NULL) {
990 		be_print_err(gettext("be_promote_zone_ds: no supported "
991 		    "brands\n"));
992 		return (BE_SUCCESS);
993 	}
994 
995 	if ((zhp = zfs_open(g_zfs, be_root_ds,
996 	    ZFS_TYPE_FILESYSTEM)) == NULL) {
997 		be_print_err(gettext("be_promote_zone_ds: Failed to open "
998 		    "dataset (%s): %s\n"), be_root_ds,
999 		    libzfs_error_description(g_zfs));
1000 		err = zfs_err_to_be_err(g_zfs);
1001 		z_free_brand_list(brands);
1002 		return (err);
1003 	}
1004 
1005 	if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1006 		if ((err = _be_mount(be_name, &temp_mntpt,
1007 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1008 			be_print_err(gettext("be_promote_zone_ds: failed to "
1009 			    "mount the BE for zones procesing.\n"));
1010 			ZFS_CLOSE(zhp);
1011 			z_free_brand_list(brands);
1012 			return (err);
1013 		}
1014 		be_mounted = B_TRUE;
1015 	}
1016 
1017 	/*
1018 	 * Set the zone root to the temp mount point for the BE we just mounted.
1019 	 */
1020 	z_set_zone_root(temp_mntpt);
1021 
1022 	/*
1023 	 * Get all the zones based on the brands we're looking for. If no zones
1024 	 * are found that we're interested in unmount the BE and move on.
1025 	 */
1026 	if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1027 		if (be_mounted)
1028 			(void) _be_unmount(be_name, 0);
1029 		ZFS_CLOSE(zhp);
1030 		z_free_brand_list(brands);
1031 		free(temp_mntpt);
1032 		return (BE_SUCCESS);
1033 	}
1034 	for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1035 	    != NULL; zone_index++) {
1036 		char *zone_path = NULL;
1037 
1038 		/* Skip zones that aren't at least installed */
1039 		if (z_zlist_get_current_state(zone_list, zone_index) <
1040 		    ZONE_STATE_INSTALLED)
1041 			continue;
1042 
1043 		if (((zone_path =
1044 		    z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1045 		    ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1046 		    !be_zone_supported(zone_ds))
1047 			continue;
1048 
1049 		if (be_find_active_zone_root(zhp, zone_ds,
1050 		    zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1051 			be_print_err(gettext("be_promote_zone_ds: "
1052 			    "Zone does not have an active root "
1053 			    "dataset, skipping this zone.\n"));
1054 			continue;
1055 		}
1056 
1057 		if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1058 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1059 			be_print_err(gettext("be_promote_zone_ds: "
1060 			    "Failed to open dataset "
1061 			    "(%s): %s\n"), zoneroot_ds,
1062 			    libzfs_error_description(g_zfs));
1063 			err = zfs_err_to_be_err(g_zfs);
1064 			goto done;
1065 		}
1066 
1067 		if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1068 		    sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1069 			ZFS_CLOSE(z_zhp);
1070 			continue;
1071 		}
1072 
1073 		/*
1074 		 * We don't need to close the zfs handle at this
1075 		 * point because the callback funtion
1076 		 * be_promote_ds_callback() will close it for us.
1077 		 */
1078 		if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1079 			be_print_err(gettext("be_promote_zone_ds: "
1080 			    "failed to activate the "
1081 			    "datasets for %s: %s\n"),
1082 			    zoneroot_ds,
1083 			    libzfs_error_description(g_zfs));
1084 			err = BE_ERR_PROMOTE;
1085 			goto done;
1086 		}
1087 	}
1088 done:
1089 	if (be_mounted)
1090 		(void) _be_unmount(be_name, 0);
1091 	ZFS_CLOSE(zhp);
1092 	free(temp_mntpt);
1093 	z_free_brand_list(brands);
1094 	z_free_zone_list(zone_list);
1095 	return (err);
1096 }
1097 
1098 /*
1099  * Function:	be_promote_ds_callback
1100  * Description:	This function is used to promote the datasets for the BE
1101  *		being activated as well as the datasets for the zones BE
1102  *		being activated.
1103  *
1104  * Parameters:
1105  *              zhp - the zfs handle for zone BE being activated.
1106  *		data - not used.
1107  * Return:
1108  *		0 - Success
1109  *		be_errno_t - Failure
1110  *
1111  * Scope:
1112  *		Private
1113  */
1114 static int
1115 /* LINTED */
1116 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1117 {
1118 	char	origin[MAXPATHLEN];
1119 	char	*sub_dataset = NULL;
1120 	int	ret = 0;
1121 
1122 	if (zhp != NULL) {
1123 		sub_dataset = strdup(zfs_get_name(zhp));
1124 		if (sub_dataset == NULL) {
1125 			ret = BE_ERR_NOMEM;
1126 			goto done;
1127 		}
1128 	} else {
1129 		be_print_err(gettext("be_promote_ds_callback: "
1130 		    "Invalid zfs handle passed into function\n"));
1131 		ret = BE_ERR_INVAL;
1132 		goto done;
1133 	}
1134 
1135 	/*
1136 	 * This loop makes sure that we promote the dataset to the
1137 	 * top of the tree so that it is no longer a decendent of any
1138 	 * dataset. The ZFS close and then open is used to make sure that
1139 	 * the promotion is updated before we move on.
1140 	 */
1141 	while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1142 	    sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1143 		if (zfs_promote(zhp) != 0) {
1144 			if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1145 				be_print_err(gettext("be_promote_ds_callback: "
1146 				    "promote of %s failed: %s\n"),
1147 				    zfs_get_name(zhp),
1148 				    libzfs_error_description(g_zfs));
1149 				ret = zfs_err_to_be_err(g_zfs);
1150 				goto done;
1151 			} else {
1152 				/*
1153 				 * If the call to zfs_promote returns the
1154 				 * error EZFS_EXISTS we've hit a snapshot name
1155 				 * collision. This means we're probably
1156 				 * attemping to promote a zone dataset above a
1157 				 * parent dataset that belongs to another zone
1158 				 * which this zone was cloned from.
1159 				 *
1160 				 * TODO: If this is a zone dataset at some
1161 				 * point we should skip this if the zone
1162 				 * paths for the dataset and the snapshot
1163 				 * don't match.
1164 				 */
1165 				be_print_err(gettext("be_promote_ds_callback: "
1166 				    "promote of %s failed due to snapshot "
1167 				    "name collision: %s\n"), zfs_get_name(zhp),
1168 				    libzfs_error_description(g_zfs));
1169 				ret = zfs_err_to_be_err(g_zfs);
1170 				goto done;
1171 			}
1172 		}
1173 		ZFS_CLOSE(zhp);
1174 		if ((zhp = zfs_open(g_zfs, sub_dataset,
1175 		    ZFS_TYPE_FILESYSTEM)) == NULL) {
1176 			be_print_err(gettext("be_promote_ds_callback: "
1177 			    "Failed to open dataset (%s): %s\n"), sub_dataset,
1178 			    libzfs_error_description(g_zfs));
1179 			ret = zfs_err_to_be_err(g_zfs);
1180 			goto done;
1181 		}
1182 	}
1183 
1184 	/* Iterate down this dataset's children and promote them */
1185 	ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1186 
1187 done:
1188 	free(sub_dataset);
1189 	ZFS_CLOSE(zhp);
1190 	return (ret);
1191 }
1192