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