xref: /titanic_50/usr/src/lib/libbe/common/be_utils.c (revision 5e12ddada2833f3aa285210603ce9aaeb8be35cc)
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  * System includes
28  */
29 #include <assert.h>
30 #include <errno.h>
31 #include <libgen.h>
32 #include <libintl.h>
33 #include <libnvpair.h>
34 #include <libzfs.h>
35 #include <libgen.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/vfstab.h>
42 #include <sys/param.h>
43 #include <sys/systeminfo.h>
44 #include <ctype.h>
45 #include <time.h>
46 #include <unistd.h>
47 #include <fcntl.h>
48 #include <wait.h>
49 
50 #include <libbe.h>
51 #include <libbe_priv.h>
52 
53 #define	INST_ICT "/usr/lib/python2.6/vendor-packages/osol_install/ict.py"
54 
55 /* Private function prototypes */
56 static int update_dataset(char *, int, char *, char *, char *);
57 static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *);
58 static int be_open_menu(char *, char *, char *, FILE **, char *, boolean_t);
59 static int be_create_menu(char *, char *, char *, FILE **, char *);
60 static char *be_get_auto_name(char *, char *, boolean_t);
61 
62 /*
63  * Global error printing
64  */
65 boolean_t do_print = B_FALSE;
66 
67 /*
68  * Private datatypes
69  */
70 typedef struct zone_be_name_cb_data {
71 	char *base_be_name;
72 	int num;
73 } zone_be_name_cb_data_t;
74 
75 /* ********************************************************************	*/
76 /*			Public Functions				*/
77 /* ******************************************************************** */
78 
79 /*
80  * Function:	be_max_avail
81  * Description:	Returns the available size for the zfs dataset passed in.
82  * Parameters:
83  *		dataset - The dataset we want to get the available space for.
84  *		ret - The available size will be returned in this.
85  * Returns:
86  *		The error returned by the zfs get property function.
87  * Scope:
88  *		Public
89  */
90 int
91 be_max_avail(char *dataset, uint64_t *ret)
92 {
93 	zfs_handle_t *zhp;
94 	int err = 0;
95 
96 	/* Initialize libzfs handle */
97 	if (!be_zfs_init())
98 		return (BE_ERR_INIT);
99 
100 	zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET);
101 	if (zhp == NULL) {
102 		/*
103 		 * The zfs_open failed return an error
104 		 */
105 		err = zfs_err_to_be_err(g_zfs);
106 	} else {
107 		err = be_maxsize_avail(zhp, ret);
108 	}
109 	ZFS_CLOSE(zhp);
110 	be_zfs_fini();
111 	return (err);
112 }
113 
114 /*
115  * Function:	libbe_print_errors
116  * Description:	Turns on/off error output for the library.
117  * Parameter:
118  *		set_do_print - Boolean that turns library error
119  *			       printing on or off.
120  * Returns:
121  *		None
122  * Scope:
123  *		Public;
124  */
125 void
126 libbe_print_errors(boolean_t set_do_print)
127 {
128 	do_print = set_do_print;
129 }
130 
131 /* ********************************************************************	*/
132 /*			Semi-Private Functions				*/
133 /* ******************************************************************** */
134 
135 /*
136  * Function:	be_zfs_init
137  * Description:	Initializes the libary global libzfs handle.
138  * Parameters:
139  *		None
140  * Returns:
141  *		B_TRUE - Success
142  *		B_FALSE - Failure
143  * Scope:
144  *		Semi-private (library wide use only)
145  */
146 boolean_t
147 be_zfs_init(void)
148 {
149 	be_zfs_fini();
150 
151 	if ((g_zfs = libzfs_init()) == NULL) {
152 		be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
153 		    "library\n"));
154 		return (B_FALSE);
155 	}
156 
157 	return (B_TRUE);
158 }
159 
160 /*
161  * Function:	be_zfs_fini
162  * Description:	Closes the library global libzfs handle if it currently open.
163  * Parameter:
164  *		None
165  * Returns:
166  *		None
167  * Scope:
168  *		Semi-private (library wide use only)
169  */
170 void
171 be_zfs_fini(void)
172 {
173 	if (g_zfs)
174 		libzfs_fini(g_zfs);
175 
176 	g_zfs = NULL;
177 }
178 
179 /*
180  * Function:	be_make_root_ds
181  * Description:	Generate string for BE's root dataset given the pool
182  *		it lives in and the BE name.
183  * Parameters:
184  *		zpool - pointer zpool name.
185  *		be_name - pointer to BE name.
186  *		be_root_ds - pointer to buffer to return BE root dataset in.
187  *		be_root_ds_size - size of be_root_ds
188  * Returns:
189  *		None
190  * Scope:
191  *		Semi-private (library wide use only)
192  */
193 void
194 be_make_root_ds(const char *zpool, const char *be_name, char *be_root_ds,
195     int be_root_ds_size)
196 {
197 	(void) snprintf(be_root_ds, be_root_ds_size, "%s/%s/%s", zpool,
198 	    BE_CONTAINER_DS_NAME, be_name);
199 }
200 
201 /*
202  * Function:	be_make_container_ds
203  * Description:	Generate string for the BE container dataset given a pool name.
204  * Parameters:
205  *		zpool - pointer zpool name.
206  *		container_ds - pointer to buffer to return BE container
207  *			dataset in.
208  *		container_ds_size - size of container_ds
209  * Returns:
210  *		None
211  * Scope:
212  *		Semi-private (library wide use only)
213  */
214 void
215 be_make_container_ds(const char *zpool,  char *container_ds,
216     int container_ds_size)
217 {
218 	(void) snprintf(container_ds, container_ds_size, "%s/%s", zpool,
219 	    BE_CONTAINER_DS_NAME);
220 }
221 
222 /*
223  * Function:	be_make_name_from_ds
224  * Description:	This function takes a dataset name and strips off the
225  *		BE container dataset portion from the beginning.  The
226  *		returned name is allocated in heap storage, so the caller
227  *		is responsible for freeing it.
228  * Parameters:
229  *		dataset - dataset to get name from.
230  *		rc_loc - dataset underwhich the root container dataset lives.
231  * Returns:
232  *		name of dataset relative to BE container dataset.
233  *		NULL if dataset is not under a BE root dataset.
234  * Scope:
235  *		Semi-primate (library wide use only)
236  */
237 char *
238 be_make_name_from_ds(const char *dataset, char *rc_loc)
239 {
240 	char	ds[ZFS_MAXNAMELEN];
241 	char	*tok = NULL;
242 	char	*name = NULL;
243 
244 	/*
245 	 * First token is the location of where the root container dataset
246 	 * lives; it must match rc_loc.
247 	 */
248 	if (strncmp(dataset, rc_loc, strlen(rc_loc)) == 0 &&
249 	    dataset[strlen(rc_loc)] == '/') {
250 		(void) strlcpy(ds, dataset + strlen(rc_loc) + 1, sizeof (ds));
251 	} else {
252 		return (NULL);
253 	}
254 
255 	/* Second token must be BE container dataset name */
256 	if ((tok = strtok(ds, "/")) == NULL ||
257 	    strcmp(tok, BE_CONTAINER_DS_NAME) != 0)
258 		return (NULL);
259 
260 	/* Return the remaining token if one exists */
261 	if ((tok = strtok(NULL, "")) == NULL)
262 		return (NULL);
263 
264 	if ((name = strdup(tok)) == NULL) {
265 		be_print_err(gettext("be_make_name_from_ds: "
266 		    "memory allocation failed\n"));
267 		return (NULL);
268 	}
269 
270 	return (name);
271 }
272 
273 /*
274  * Function:	be_maxsize_avail
275  * Description:	Returns the available size for the zfs handle passed in.
276  * Parameters:
277  *		zhp - A pointer to the open zfs handle.
278  *		ret - The available size will be returned in this.
279  * Returns:
280  *		The error returned by the zfs get property function.
281  * Scope:
282  *		Semi-private (library wide use only)
283  */
284 int
285 be_maxsize_avail(zfs_handle_t *zhp, uint64_t *ret)
286 {
287 	return ((*ret = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE)));
288 }
289 
290 /*
291  * Function:	be_append_menu
292  * Description:	Appends an entry for a BE into the menu.lst.
293  * Parameters:
294  *		be_name - pointer to name of BE to add boot menu entry for.
295  *		be_root_pool - pointer to name of pool BE lives in.
296  *		boot_pool - Used if the pool containing the grub menu is
297  *			    different than the one contaiing the BE. This
298  *			    will normally be NULL.
299  *		be_orig_root_ds - The root dataset for the BE. This is
300  *			used to check to see if an entry already exists
301  *			for this BE.
302  *		description - pointer to description of BE to be added in
303  *			the title line for this BEs entry.
304  * Returns:
305  *		BE_SUCCESS - Success
306  *		be_errno_t - Failure
307  * Scope:
308  *		Semi-private (library wide use only)
309  */
310 int
311 be_append_menu(char *be_name, char *be_root_pool, char *boot_pool,
312     char *be_orig_root_ds, char *description)
313 {
314 	zfs_handle_t *zhp = NULL;
315 	char menu_file[MAXPATHLEN];
316 	char be_root_ds[MAXPATHLEN];
317 	char line[BUFSIZ];
318 	char temp_line[BUFSIZ];
319 	char title[MAXPATHLEN];
320 	char *entries[BUFSIZ];
321 	char *tmp_entries[BUFSIZ];
322 	char *pool_mntpnt = NULL;
323 	char *ptmp_mntpnt = NULL;
324 	char *orig_mntpnt = NULL;
325 	boolean_t found_be = B_FALSE;
326 	boolean_t found_orig_be = B_FALSE;
327 	boolean_t found_title = B_FALSE;
328 	boolean_t pool_mounted = B_FALSE;
329 	boolean_t collect_lines = B_FALSE;
330 	FILE *menu_fp = NULL;
331 	int err = 0, ret = BE_SUCCESS;
332 	int i, num_tmp_lines = 0, num_lines = 0;
333 
334 	if (be_name == NULL || be_root_pool == NULL)
335 		return (BE_ERR_INVAL);
336 
337 	if (boot_pool == NULL)
338 		boot_pool = be_root_pool;
339 
340 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
341 		be_print_err(gettext("be_append_menu: failed to open "
342 		    "pool dataset for %s: %s\n"), be_root_pool,
343 		    libzfs_error_description(g_zfs));
344 		return (zfs_err_to_be_err(g_zfs));
345 	}
346 
347 	/*
348 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
349 	 * attempt to mount it.
350 	 */
351 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
352 	    &pool_mounted)) != BE_SUCCESS) {
353 		be_print_err(gettext("be_append_menu: pool dataset "
354 		    "(%s) could not be mounted\n"), be_root_pool);
355 		ZFS_CLOSE(zhp);
356 		return (ret);
357 	}
358 
359 	/*
360 	 * Get the mountpoint for the root pool dataset.
361 	 */
362 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
363 		be_print_err(gettext("be_append_menu: pool "
364 		    "dataset (%s) is not mounted. Can't set "
365 		    "the default BE in the grub menu.\n"), be_root_pool);
366 		ret = BE_ERR_NO_MENU;
367 		goto cleanup;
368 	}
369 
370 	/*
371 	 * Check to see if this system supports grub
372 	 */
373 	if (be_has_grub()) {
374 		(void) snprintf(menu_file, sizeof (menu_file),
375 		    "%s%s", pool_mntpnt, BE_GRUB_MENU);
376 	} else {
377 		(void) snprintf(menu_file, sizeof (menu_file),
378 		    "%s%s", pool_mntpnt, BE_SPARC_MENU);
379 	}
380 
381 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
382 
383 	/*
384 	 * Iterate through menu first to make sure the BE doesn't already
385 	 * have an entry in the menu.
386 	 *
387 	 * Additionally while iterating through the menu, if we have an
388 	 * original root dataset for a BE we're cloning from, we need to keep
389 	 * track of that BE's menu entry. We will then use the lines from
390 	 * that entry to create the entry for the new BE.
391 	 */
392 	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu_file,
393 	    &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
394 		goto cleanup;
395 	} else if (menu_fp == NULL) {
396 		ret = BE_ERR_NO_MENU;
397 		goto cleanup;
398 	}
399 
400 	free(pool_mntpnt);
401 	pool_mntpnt = NULL;
402 
403 	while (fgets(line, BUFSIZ, menu_fp)) {
404 		char *tok = NULL;
405 
406 		(void) strlcpy(temp_line, line, BUFSIZ);
407 		tok = strtok(line, BE_WHITE_SPACE);
408 
409 		if (tok == NULL || tok[0] == '#') {
410 			continue;
411 		} else if (strcmp(tok, "title") == 0) {
412 			collect_lines = B_FALSE;
413 			if ((tok = strtok(NULL, "\n")) == NULL)
414 				(void) strlcpy(title, "", sizeof (title));
415 			else
416 				(void) strlcpy(title, tok, sizeof (title));
417 			found_title = B_TRUE;
418 
419 			if (num_tmp_lines != 0) {
420 				for (i = 0; i < num_tmp_lines; i++) {
421 					free(tmp_entries[i]);
422 					tmp_entries[i] = NULL;
423 				}
424 				num_tmp_lines = 0;
425 			}
426 		} else if (strcmp(tok, "bootfs") == 0) {
427 			char *bootfs = strtok(NULL, BE_WHITE_SPACE);
428 			found_title = B_FALSE;
429 			if (bootfs == NULL)
430 				continue;
431 
432 			if (strcmp(bootfs, be_root_ds) == 0) {
433 				found_be = B_TRUE;
434 				break;
435 			}
436 
437 			if (be_orig_root_ds != NULL &&
438 			    strcmp(bootfs, be_orig_root_ds) == 0 &&
439 			    !found_orig_be) {
440 				char str[BUFSIZ];
441 				found_orig_be = B_TRUE;
442 				num_lines = 0;
443 				/*
444 				 * Store the new title line
445 				 */
446 				(void) snprintf(str, BUFSIZ, "title %s\n",
447 				    description ? description : be_name);
448 				entries[num_lines] = strdup(str);
449 				num_lines++;
450 				/*
451 				 * If there are any lines between the title
452 				 * and the bootfs line store these. Also
453 				 * free the temporary lines.
454 				 */
455 				for (i = 0; i < num_tmp_lines; i++) {
456 					entries[num_lines] = tmp_entries[i];
457 					tmp_entries[i] = NULL;
458 					num_lines++;
459 				}
460 				num_tmp_lines = 0;
461 				/*
462 				 * Store the new bootfs line.
463 				 */
464 				(void) snprintf(str, BUFSIZ, "bootfs %s\n",
465 				    be_root_ds);
466 				entries[num_lines] = strdup(str);
467 				num_lines++;
468 				collect_lines = B_TRUE;
469 			}
470 		} else if (found_orig_be && collect_lines) {
471 			/*
472 			 * get the rest of the lines for the original BE and
473 			 * store them.
474 			 */
475 			if (strstr(line, BE_GRUB_COMMENT) != NULL ||
476 			    strstr(line, "BOOTADM") != NULL)
477 				continue;
478 			entries[num_lines] = strdup(temp_line);
479 			num_lines++;
480 		} else if (found_title && !found_orig_be) {
481 			tmp_entries[num_tmp_lines] = strdup(temp_line);
482 			num_tmp_lines++;
483 		}
484 	}
485 
486 	(void) fclose(menu_fp);
487 
488 	if (found_be) {
489 		/*
490 		 * If an entry for this BE was already in the menu, then if
491 		 * that entry's title matches what we would have put in
492 		 * return success.  Otherwise return failure.
493 		 */
494 		char *new_title = description ? description : be_name;
495 
496 		if (strcmp(title, new_title) == 0) {
497 			ret = BE_SUCCESS;
498 			goto cleanup;
499 		} else {
500 			if (be_remove_menu(be_name, be_root_pool,
501 			    boot_pool) != BE_SUCCESS) {
502 				be_print_err(gettext("be_append_menu: "
503 				    "Failed to remove existing unusable "
504 				    "entry '%s' in boot menu.\n"), be_name);
505 				ret = BE_ERR_BE_EXISTS;
506 				goto cleanup;
507 			}
508 		}
509 	}
510 
511 	/* Append BE entry to the end of the file */
512 	menu_fp = fopen(menu_file, "a+");
513 	err = errno;
514 	if (menu_fp == NULL) {
515 		be_print_err(gettext("be_append_menu: failed "
516 		    "to open menu.lst file %s\n"), menu_file);
517 		ret = errno_to_be_err(err);
518 		goto cleanup;
519 	}
520 
521 	if (found_orig_be) {
522 		/*
523 		 * write out all the stored lines
524 		 */
525 		for (i = 0; i < num_lines; i++) {
526 			(void) fprintf(menu_fp, "%s", entries[i]);
527 			free(entries[i]);
528 		}
529 		num_lines = 0;
530 
531 		/*
532 		 * Check to see if this system supports grub
533 		 */
534 		if (be_has_grub())
535 			(void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
536 		ret = BE_SUCCESS;
537 	} else {
538 		(void) fprintf(menu_fp, "title %s\n",
539 		    description ? description : be_name);
540 		(void) fprintf(menu_fp, "bootfs %s\n", be_root_ds);
541 
542 		/*
543 		 * Check to see if this system supports grub
544 		 */
545 		if (be_has_grub()) {
546 			(void) fprintf(menu_fp, "kernel$ "
547 			    "/platform/i86pc/kernel/$ISADIR/unix -B "
548 			    "$ZFS-BOOTFS\n");
549 			(void) fprintf(menu_fp, "module$ "
550 			    "/platform/i86pc/$ISADIR/boot_archive\n");
551 			(void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
552 		}
553 		ret = BE_SUCCESS;
554 	}
555 	(void) fclose(menu_fp);
556 cleanup:
557 	if (pool_mounted) {
558 		int err = BE_SUCCESS;
559 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
560 		if (ret == BE_SUCCESS)
561 			ret = err;
562 		free(orig_mntpnt);
563 		free(ptmp_mntpnt);
564 	}
565 	ZFS_CLOSE(zhp);
566 	if (num_tmp_lines > 0) {
567 		for (i = 0; i < num_tmp_lines; i++) {
568 			free(tmp_entries[i]);
569 			tmp_entries[i] = NULL;
570 		}
571 	}
572 	if (num_lines > 0) {
573 		for (i = 0; i < num_lines; i++) {
574 			free(entries[i]);
575 			entries[i] = NULL;
576 		}
577 	}
578 	return (ret);
579 }
580 
581 /*
582  * Function:	be_remove_menu
583  * Description:	Removes a BE's entry from a menu.lst file.
584  * Parameters:
585  *		be_name - the name of BE whose entry is to be removed from
586  *			the menu.lst file.
587  *		be_root_pool - the pool that be_name lives in.
588  *		boot_pool - the pool where the BE is, if different than
589  *			the pool containing the boot menu.  If this is
590  *			NULL it will be set to be_root_pool.
591  * Returns:
592  *		BE_SUCCESS - Success
593  *		be_errno_t - Failure
594  * Scope:
595  *		Semi-private (library wide use only)
596  */
597 int
598 be_remove_menu(char *be_name, char *be_root_pool, char *boot_pool)
599 {
600 	zfs_handle_t	*zhp = NULL;
601 	char		be_root_ds[MAXPATHLEN];
602 	char		**buffer = NULL;
603 	char		menu_buf[BUFSIZ];
604 	char		menu[MAXPATHLEN];
605 	char		*pool_mntpnt = NULL;
606 	char		*ptmp_mntpnt = NULL;
607 	char		*orig_mntpnt = NULL;
608 	char		*tmp_menu = NULL;
609 	FILE		*menu_fp = NULL;
610 	FILE		*tmp_menu_fp = NULL;
611 	struct stat	sb;
612 	int		ret = BE_SUCCESS;
613 	int		i;
614 	int		fd;
615 	int		err = 0;
616 	int		nlines = 0;
617 	int		default_entry = 0;
618 	int		entry_cnt = 0;
619 	int		entry_del = 0;
620 	int		num_entry_del = 0;
621 	int		tmp_menu_len = 0;
622 	boolean_t	write = B_TRUE;
623 	boolean_t	do_buffer = B_FALSE;
624 	boolean_t	pool_mounted = B_FALSE;
625 
626 	if (boot_pool == NULL)
627 		boot_pool = be_root_pool;
628 
629 	/* Get name of BE's root dataset */
630 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
631 
632 	/* Get handle to pool dataset */
633 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
634 		be_print_err(gettext("be_remove_menu: "
635 		    "failed to open pool dataset for %s: %s"),
636 		    be_root_pool, libzfs_error_description(g_zfs));
637 		return (zfs_err_to_be_err(g_zfs));
638 	}
639 
640 	/*
641 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
642 	 * attempt to mount it.
643 	 */
644 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
645 	    &pool_mounted)) != BE_SUCCESS) {
646 		be_print_err(gettext("be_remove_menu: pool dataset "
647 		    "(%s) could not be mounted\n"), be_root_pool);
648 		ZFS_CLOSE(zhp);
649 		return (ret);
650 	}
651 
652 	/*
653 	 * Get the mountpoint for the root pool dataset.
654 	 */
655 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
656 		be_print_err(gettext("be_remove_menu: pool "
657 		    "dataset (%s) is not mounted. Can't set "
658 		    "the default BE in the grub menu.\n"), be_root_pool);
659 		ret = BE_ERR_NO_MENU;
660 		goto cleanup;
661 	}
662 
663 	/* Get path to boot menu */
664 	(void) strlcpy(menu, pool_mntpnt, sizeof (menu));
665 
666 	/*
667 	 * Check to see if this system supports grub
668 	 */
669 	if (be_has_grub())
670 		(void) strlcat(menu, BE_GRUB_MENU, sizeof (menu));
671 	else
672 		(void) strlcat(menu, BE_SPARC_MENU, sizeof (menu));
673 
674 	/* Get handle to boot menu file */
675 	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu, &menu_fp, "r",
676 	    B_TRUE)) != BE_SUCCESS) {
677 		goto cleanup;
678 	} else if (menu_fp == NULL) {
679 		ret = BE_ERR_NO_MENU;
680 		goto cleanup;
681 	}
682 
683 	free(pool_mntpnt);
684 	pool_mntpnt = NULL;
685 
686 	/* Grab the stats of the original menu file */
687 	if (stat(menu, &sb) != 0) {
688 		err = errno;
689 		be_print_err(gettext("be_remove_menu: "
690 		    "failed to stat file %s: %s\n"), menu, strerror(err));
691 		ret = errno_to_be_err(err);
692 		goto cleanup;
693 	}
694 
695 	/* Create a tmp file for the modified menu.lst */
696 	tmp_menu_len = strlen(menu) + 7;
697 	if ((tmp_menu = (char *)malloc(tmp_menu_len)) == NULL) {
698 		be_print_err(gettext("be_remove_menu: malloc failed\n"));
699 		ret = BE_ERR_NOMEM;
700 		goto cleanup;
701 	}
702 	(void) memset(tmp_menu, 0, tmp_menu_len);
703 	(void) strlcpy(tmp_menu, menu, tmp_menu_len);
704 	(void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
705 	if ((fd = mkstemp(tmp_menu)) == -1) {
706 		err = errno;
707 		be_print_err(gettext("be_remove_menu: mkstemp failed\n"));
708 		ret = errno_to_be_err(err);
709 		free(tmp_menu);
710 		tmp_menu = NULL;
711 		goto cleanup;
712 	}
713 	if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
714 		err = errno;
715 		be_print_err(gettext("be_remove_menu: "
716 		    "could not open tmp file for write: %s\n"), strerror(err));
717 		(void) close(fd);
718 		ret = errno_to_be_err(err);
719 		goto cleanup;
720 	}
721 
722 	while (fgets(menu_buf, BUFSIZ, menu_fp)) {
723 		char tline [BUFSIZ];
724 		char *tok = NULL;
725 
726 		(void) strlcpy(tline, menu_buf, sizeof (tline));
727 
728 		/* Tokenize line */
729 		tok = strtok(tline, BE_WHITE_SPACE);
730 
731 		if (tok == NULL || tok[0] == '#') {
732 			/* Found empty line or comment line */
733 			if (do_buffer) {
734 				/* Buffer this line */
735 				if ((buffer = (char **)realloc(buffer,
736 				    sizeof (char *)*(nlines + 1))) == NULL) {
737 					ret = BE_ERR_NOMEM;
738 					goto cleanup;
739 				}
740 				if ((buffer[nlines++] = strdup(menu_buf))
741 				    == NULL) {
742 					ret = BE_ERR_NOMEM;
743 					goto cleanup;
744 				}
745 
746 			} else if (write || strncmp(menu_buf, BE_GRUB_COMMENT,
747 			    strlen(BE_GRUB_COMMENT)) != 0) {
748 				/* Write this line out */
749 				(void) fputs(menu_buf, tmp_menu_fp);
750 			}
751 		} else if (strcmp(tok, "default") == 0) {
752 			/*
753 			 * Record what 'default' is set to because we might
754 			 * need to adjust this upon deleting an entry.
755 			 */
756 			tok = strtok(NULL, BE_WHITE_SPACE);
757 
758 			if (tok != NULL) {
759 				default_entry = atoi(tok);
760 			}
761 
762 			(void) fputs(menu_buf, tmp_menu_fp);
763 		} else if (strcmp(tok, "title") == 0) {
764 			/*
765 			 * If we've reached a 'title' line and do_buffer is
766 			 * is true, that means we've just buffered an entire
767 			 * entry without finding a 'bootfs' directive.  We
768 			 * need to write that entry out and keep searching.
769 			 */
770 			if (do_buffer) {
771 				for (i = 0; i < nlines; i++) {
772 					(void) fputs(buffer[i], tmp_menu_fp);
773 					free(buffer[i]);
774 				}
775 				free(buffer);
776 				buffer = NULL;
777 				nlines = 0;
778 			}
779 
780 			/*
781 			 * Turn writing off and buffering on, and increment
782 			 * our entry counter.
783 			 */
784 			write = B_FALSE;
785 			do_buffer = B_TRUE;
786 			entry_cnt++;
787 
788 			/* Buffer this 'title' line */
789 			if ((buffer = (char **)realloc(buffer,
790 			    sizeof (char *)*(nlines + 1))) == NULL) {
791 				ret = BE_ERR_NOMEM;
792 				goto cleanup;
793 			}
794 			if ((buffer[nlines++] = strdup(menu_buf)) == NULL) {
795 				ret = BE_ERR_NOMEM;
796 				goto cleanup;
797 			}
798 
799 		} else if (strcmp(tok, "bootfs") == 0) {
800 			char *bootfs = NULL;
801 
802 			/*
803 			 * Found a 'bootfs' line.  See if it matches the
804 			 * BE we're looking for.
805 			 */
806 			if ((bootfs = strtok(NULL, BE_WHITE_SPACE)) == NULL ||
807 			    strcmp(bootfs, be_root_ds) != 0) {
808 				/*
809 				 * Either there's nothing after the 'bootfs'
810 				 * or this is not the BE we're looking for,
811 				 * write out the line(s) we've buffered since
812 				 * finding the title.
813 				 */
814 				for (i = 0; i < nlines; i++) {
815 					(void) fputs(buffer[i], tmp_menu_fp);
816 					free(buffer[i]);
817 				}
818 				free(buffer);
819 				buffer = NULL;
820 				nlines = 0;
821 
822 				/*
823 				 * Turn writing back on, and turn off buffering
824 				 * since this isn't the entry we're looking
825 				 * for.
826 				 */
827 				write = B_TRUE;
828 				do_buffer = B_FALSE;
829 
830 				/* Write this 'bootfs' line out. */
831 				(void) fputs(menu_buf, tmp_menu_fp);
832 			} else {
833 				/*
834 				 * Found the entry we're looking for.
835 				 * Record its entry number, increment the
836 				 * number of entries we've deleted, and turn
837 				 * writing off.  Also, throw away the lines
838 				 * we've buffered for this entry so far, we
839 				 * don't need them.
840 				 */
841 				entry_del = entry_cnt - 1;
842 				num_entry_del++;
843 				write = B_FALSE;
844 				do_buffer = B_FALSE;
845 
846 				for (i = 0; i < nlines; i++) {
847 					free(buffer[i]);
848 				}
849 				free(buffer);
850 				buffer = NULL;
851 				nlines = 0;
852 			}
853 		} else {
854 			if (do_buffer) {
855 				/* Buffer this line */
856 				if ((buffer = (char **)realloc(buffer,
857 				    sizeof (char *)*(nlines + 1))) == NULL) {
858 					ret = BE_ERR_NOMEM;
859 					goto cleanup;
860 				}
861 				if ((buffer[nlines++] = strdup(menu_buf))
862 				    == NULL) {
863 					ret = BE_ERR_NOMEM;
864 					goto cleanup;
865 				}
866 			} else if (write) {
867 				/* Write this line out */
868 				(void) fputs(menu_buf, tmp_menu_fp);
869 			}
870 		}
871 	}
872 
873 	(void) fclose(menu_fp);
874 	menu_fp = NULL;
875 	(void) fclose(tmp_menu_fp);
876 	tmp_menu_fp = NULL;
877 
878 	/* Copy the modified menu.lst into place */
879 	if (rename(tmp_menu, menu) != 0) {
880 		err = errno;
881 		be_print_err(gettext("be_remove_menu: "
882 		    "failed to rename file %s to %s: %s\n"),
883 		    tmp_menu, menu, strerror(err));
884 		ret = errno_to_be_err(err);
885 		goto cleanup;
886 	}
887 	free(tmp_menu);
888 	tmp_menu = NULL;
889 
890 	/*
891 	 * If we've removed an entry, see if we need to
892 	 * adjust the default value in the menu.lst.  If the
893 	 * entry we've deleted comes before the default entry
894 	 * we need to adjust the default value accordingly.
895 	 *
896 	 * be_has_grub is used here to check to see if this system
897 	 * supports grub.
898 	 */
899 	if (be_has_grub() && num_entry_del > 0) {
900 		if (entry_del <= default_entry) {
901 			default_entry = default_entry - num_entry_del;
902 			if (default_entry < 0)
903 				default_entry = 0;
904 
905 			/*
906 			 * Adjust the default value by rewriting the
907 			 * menu.lst file.  This may be overkill, but to
908 			 * preserve the location of the 'default' entry
909 			 * in the file, we need to do this.
910 			 */
911 
912 			/* Get handle to boot menu file */
913 			if ((menu_fp = fopen(menu, "r")) == NULL) {
914 				err = errno;
915 				be_print_err(gettext("be_remove_menu: "
916 				    "failed to open menu.lst (%s): %s\n"),
917 				    menu, strerror(err));
918 				ret = errno_to_be_err(err);
919 				goto cleanup;
920 			}
921 
922 			/* Create a tmp file for the modified menu.lst */
923 			tmp_menu_len = strlen(menu) + 7;
924 			if ((tmp_menu = (char *)malloc(tmp_menu_len))
925 			    == NULL) {
926 				be_print_err(gettext("be_remove_menu: "
927 				    "malloc failed\n"));
928 				ret = BE_ERR_NOMEM;
929 				goto cleanup;
930 			}
931 			(void) memset(tmp_menu, 0, tmp_menu_len);
932 			(void) strlcpy(tmp_menu, menu, tmp_menu_len);
933 			(void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
934 			if ((fd = mkstemp(tmp_menu)) == -1) {
935 				err = errno;
936 				be_print_err(gettext("be_remove_menu: "
937 				    "mkstemp failed: %s\n"), strerror(err));
938 				ret = errno_to_be_err(err);
939 				free(tmp_menu);
940 				tmp_menu = NULL;
941 				goto cleanup;
942 			}
943 			if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
944 				err = errno;
945 				be_print_err(gettext("be_remove_menu: "
946 				    "could not open tmp file for write: %s\n"),
947 				    strerror(err));
948 				(void) close(fd);
949 				ret = errno_to_be_err(err);
950 				goto cleanup;
951 			}
952 
953 			while (fgets(menu_buf, BUFSIZ, menu_fp)) {
954 				char tline [BUFSIZ];
955 				char *tok = NULL;
956 
957 				(void) strlcpy(tline, menu_buf, sizeof (tline));
958 
959 				/* Tokenize line */
960 				tok = strtok(tline, BE_WHITE_SPACE);
961 
962 				if (tok == NULL) {
963 					/* Found empty line, write it out */
964 					(void) fputs(menu_buf, tmp_menu_fp);
965 				} else if (strcmp(tok, "default") == 0) {
966 					/* Found the default line, adjust it */
967 					(void) snprintf(tline, sizeof (tline),
968 					    "default %d\n", default_entry);
969 
970 					(void) fputs(tline, tmp_menu_fp);
971 				} else {
972 					/* Pass through all other lines */
973 					(void) fputs(menu_buf, tmp_menu_fp);
974 				}
975 			}
976 
977 			(void) fclose(menu_fp);
978 			menu_fp = NULL;
979 			(void) fclose(tmp_menu_fp);
980 			tmp_menu_fp = NULL;
981 
982 			/* Copy the modified menu.lst into place */
983 			if (rename(tmp_menu, menu) != 0) {
984 				err = errno;
985 				be_print_err(gettext("be_remove_menu: "
986 				    "failed to rename file %s to %s: %s\n"),
987 				    tmp_menu, menu, strerror(err));
988 				ret = errno_to_be_err(err);
989 				goto cleanup;
990 			}
991 
992 			free(tmp_menu);
993 			tmp_menu = NULL;
994 		}
995 	}
996 
997 	/* Set the perms and ownership of the updated file */
998 	if (chmod(menu, sb.st_mode) != 0) {
999 		err = errno;
1000 		be_print_err(gettext("be_remove_menu: "
1001 		    "failed to chmod %s: %s\n"), menu, strerror(err));
1002 		ret = errno_to_be_err(err);
1003 		goto cleanup;
1004 	}
1005 	if (chown(menu, sb.st_uid, sb.st_gid) != 0) {
1006 		err = errno;
1007 		be_print_err(gettext("be_remove_menu: "
1008 		    "failed to chown %s: %s\n"), menu, strerror(err));
1009 		ret = errno_to_be_err(err);
1010 		goto cleanup;
1011 	}
1012 
1013 cleanup:
1014 	if (pool_mounted) {
1015 		int err = BE_SUCCESS;
1016 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1017 		if (ret == BE_SUCCESS)
1018 			ret = err;
1019 		free(orig_mntpnt);
1020 		free(ptmp_mntpnt);
1021 	}
1022 	ZFS_CLOSE(zhp);
1023 
1024 	free(buffer);
1025 	if (menu_fp != NULL)
1026 		(void) fclose(menu_fp);
1027 	if (tmp_menu_fp != NULL)
1028 		(void) fclose(tmp_menu_fp);
1029 	if (tmp_menu != NULL) {
1030 		(void) unlink(tmp_menu);
1031 		free(tmp_menu);
1032 	}
1033 
1034 	return (ret);
1035 }
1036 
1037 /*
1038  * Function:	be_default_grub_bootfs
1039  * Description:	This function returns the dataset in the default entry of
1040  *		the grub menu. If no default entry is found with a valid bootfs
1041  *		entry NULL is returned.
1042  * Parameters:
1043  *		be_root_pool - This is the name of the root pool where the
1044  *			       grub menu can be found.
1045  *              def_bootfs - This is used to pass back the bootfs string. On
1046  *				error NULL is returned here.
1047  * Returns:
1048  *		Success - BE_SUCCESS is returned.
1049  *		Failure - a be_errno_t is returned.
1050  * Scope:
1051  *		Semi-private (library wide use only)
1052  */
1053 int
1054 be_default_grub_bootfs(const char *be_root_pool, char **def_bootfs)
1055 {
1056 	zfs_handle_t	*zhp = NULL;
1057 	char		grub_file[MAXPATHLEN];
1058 	FILE		*menu_fp;
1059 	char		line[BUFSIZ];
1060 	char		*pool_mntpnt = NULL;
1061 	char		*ptmp_mntpnt = NULL;
1062 	char		*orig_mntpnt = NULL;
1063 	int		default_entry = 0, entries = 0;
1064 	int		found_default = 0;
1065 	int		ret = BE_SUCCESS;
1066 	boolean_t	pool_mounted = B_FALSE;
1067 
1068 	errno = 0;
1069 
1070 	/*
1071 	 * Check to see if this system supports grub
1072 	 */
1073 	if (!be_has_grub()) {
1074 		be_print_err(gettext("be_default_grub_bootfs: operation "
1075 		    "not supported on this architecture\n"));
1076 		return (BE_ERR_NOTSUP);
1077 	}
1078 
1079 	*def_bootfs = NULL;
1080 
1081 	/* Get handle to pool dataset */
1082 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1083 		be_print_err(gettext("be_default_grub_bootfs: "
1084 		    "failed to open pool dataset for %s: %s"),
1085 		    be_root_pool, libzfs_error_description(g_zfs));
1086 		return (zfs_err_to_be_err(g_zfs));
1087 	}
1088 
1089 	/*
1090 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1091 	 * attempt to mount it.
1092 	 */
1093 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1094 	    &pool_mounted)) != BE_SUCCESS) {
1095 		be_print_err(gettext("be_default_grub_bootfs: pool dataset "
1096 		    "(%s) could not be mounted\n"), be_root_pool);
1097 		ZFS_CLOSE(zhp);
1098 		return (ret);
1099 	}
1100 
1101 	/*
1102 	 * Get the mountpoint for the root pool dataset.
1103 	 */
1104 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1105 		be_print_err(gettext("be_default_grub_bootfs: failed "
1106 		    "to get mount point for the root pool. Can't set "
1107 		    "the default BE in the grub menu.\n"));
1108 		ret = BE_ERR_NO_MENU;
1109 		goto cleanup;
1110 	}
1111 
1112 	(void) snprintf(grub_file, MAXPATHLEN, "%s%s",
1113 	    pool_mntpnt, BE_GRUB_MENU);
1114 
1115 	if ((ret = be_open_menu((char *)be_root_pool, pool_mntpnt, grub_file,
1116 	    &menu_fp, "r", B_FALSE)) != BE_SUCCESS) {
1117 		goto cleanup;
1118 	} else if (menu_fp == NULL) {
1119 		ret = BE_ERR_NO_MENU;
1120 		goto cleanup;
1121 	}
1122 
1123 	free(pool_mntpnt);
1124 	pool_mntpnt = NULL;
1125 
1126 	while (fgets(line, BUFSIZ, menu_fp)) {
1127 		char *tok = strtok(line, BE_WHITE_SPACE);
1128 
1129 		if (tok != NULL && tok[0] != '#') {
1130 			if (!found_default) {
1131 				if (strcmp(tok, "default") == 0) {
1132 					tok = strtok(NULL, BE_WHITE_SPACE);
1133 					if (tok != NULL) {
1134 						default_entry = atoi(tok);
1135 						rewind(menu_fp);
1136 						found_default = 1;
1137 					}
1138 				}
1139 				continue;
1140 			}
1141 			if (strcmp(tok, "title") == 0) {
1142 				entries++;
1143 			} else if (default_entry == entries - 1) {
1144 				if (strcmp(tok, "bootfs") == 0) {
1145 					tok = strtok(NULL, BE_WHITE_SPACE);
1146 					(void) fclose(menu_fp);
1147 
1148 					if (tok == NULL) {
1149 						ret = BE_SUCCESS;
1150 						goto cleanup;
1151 					}
1152 
1153 					if ((*def_bootfs = strdup(tok)) !=
1154 					    NULL) {
1155 						ret = BE_SUCCESS;
1156 						goto cleanup;
1157 					}
1158 					be_print_err(gettext(
1159 					    "be_default_grub_bootfs: "
1160 					    "memory allocation failed\n"));
1161 					ret = BE_ERR_NOMEM;
1162 					goto cleanup;
1163 				}
1164 			} else if (default_entry < entries - 1) {
1165 				/*
1166 				 * no bootfs entry for the default entry.
1167 				 */
1168 				break;
1169 			}
1170 		}
1171 	}
1172 	(void) fclose(menu_fp);
1173 
1174 cleanup:
1175 	if (pool_mounted) {
1176 		int err = BE_SUCCESS;
1177 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1178 		if (ret == BE_SUCCESS)
1179 			ret = err;
1180 		free(orig_mntpnt);
1181 		free(ptmp_mntpnt);
1182 	}
1183 	ZFS_CLOSE(zhp);
1184 	return (ret);
1185 }
1186 
1187 /*
1188  * Function:	be_change_grub_default
1189  * Description:	This function takes two parameters. These are the name of
1190  *		the BE we want to have as the default booted in the grub
1191  *		menu and the root pool where the path to the grub menu exists.
1192  *		The code takes this and finds the BE's entry in the grub menu
1193  *		and changes the default entry to point to that entry in the
1194  *		list.
1195  * Parameters:
1196  *		be_name - This is the name of the BE wanted as the default
1197  *			for the next boot.
1198  *		be_root_pool - This is the name of the root pool where the
1199  *			grub menu can be found.
1200  * Returns:
1201  *		BE_SUCCESS - Success
1202  *		be_errno_t - Failure
1203  * Scope:
1204  *		Semi-private (library wide use only)
1205  */
1206 int
1207 be_change_grub_default(char *be_name, char *be_root_pool)
1208 {
1209 	zfs_handle_t	*zhp = NULL;
1210 	char	grub_file[MAXPATHLEN];
1211 	char	*temp_grub;
1212 	char	*pool_mntpnt = NULL;
1213 	char	*ptmp_mntpnt = NULL;
1214 	char	*orig_mntpnt = NULL;
1215 	char	line[BUFSIZ];
1216 	char	temp_line[BUFSIZ];
1217 	char	be_root_ds[MAXPATHLEN];
1218 	FILE	*grub_fp = NULL;
1219 	FILE	*temp_fp = NULL;
1220 	struct stat	sb;
1221 	int	temp_grub_len = 0;
1222 	int	fd, entries = 0;
1223 	int	err = 0;
1224 	int	ret = BE_SUCCESS;
1225 	boolean_t	found_default = B_FALSE;
1226 	boolean_t	pool_mounted = B_FALSE;
1227 
1228 	errno = 0;
1229 
1230 	/*
1231 	 * Check to see if this system supports grub
1232 	 */
1233 	if (!be_has_grub()) {
1234 		be_print_err(gettext("be_change_grub_default: operation "
1235 		    "not supported on this architecture\n"));
1236 		return (BE_ERR_NOTSUP);
1237 	}
1238 
1239 	/* Generate string for BE's root dataset */
1240 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
1241 
1242 	/* Get handle to pool dataset */
1243 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1244 		be_print_err(gettext("be_change_grub_default: "
1245 		    "failed to open pool dataset for %s: %s"),
1246 		    be_root_pool, libzfs_error_description(g_zfs));
1247 		return (zfs_err_to_be_err(g_zfs));
1248 	}
1249 
1250 	/*
1251 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1252 	 * attempt to mount it.
1253 	 */
1254 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1255 	    &pool_mounted)) != BE_SUCCESS) {
1256 		be_print_err(gettext("be_change_grub_default: pool dataset "
1257 		    "(%s) could not be mounted\n"), be_root_pool);
1258 		ZFS_CLOSE(zhp);
1259 		return (ret);
1260 	}
1261 
1262 	/*
1263 	 * Get the mountpoint for the root pool dataset.
1264 	 */
1265 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1266 		be_print_err(gettext("be_change_grub_default: pool "
1267 		    "dataset (%s) is not mounted. Can't set "
1268 		    "the default BE in the grub menu.\n"), be_root_pool);
1269 		ret = BE_ERR_NO_MENU;
1270 		goto cleanup;
1271 	}
1272 
1273 	(void) snprintf(grub_file, MAXPATHLEN, "%s%s",
1274 	    pool_mntpnt, BE_GRUB_MENU);
1275 
1276 	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, grub_file,
1277 	    &grub_fp, "r+", B_TRUE)) != BE_SUCCESS) {
1278 		goto cleanup;
1279 	} else if (grub_fp == NULL) {
1280 		ret = BE_ERR_NO_MENU;
1281 		goto cleanup;
1282 	}
1283 
1284 	free(pool_mntpnt);
1285 	pool_mntpnt = NULL;
1286 
1287 	/* Grab the stats of the original menu file */
1288 	if (stat(grub_file, &sb) != 0) {
1289 		err = errno;
1290 		be_print_err(gettext("be_change_grub_default: "
1291 		    "failed to stat file %s: %s\n"), grub_file, strerror(err));
1292 		ret = errno_to_be_err(err);
1293 		goto cleanup;
1294 	}
1295 
1296 	/* Create a tmp file for the modified menu.lst */
1297 	temp_grub_len = strlen(grub_file) + 7;
1298 	if ((temp_grub = (char *)malloc(temp_grub_len)) == NULL) {
1299 		be_print_err(gettext("be_change_grub_default: "
1300 		    "malloc failed\n"));
1301 		ret = BE_ERR_NOMEM;
1302 		goto cleanup;
1303 	}
1304 	(void) memset(temp_grub, 0, temp_grub_len);
1305 	(void) strlcpy(temp_grub, grub_file, temp_grub_len);
1306 	(void) strlcat(temp_grub, "XXXXXX", temp_grub_len);
1307 	if ((fd = mkstemp(temp_grub)) == -1) {
1308 		err = errno;
1309 		be_print_err(gettext("be_change_grub_default: "
1310 		    "mkstemp failed: %s\n"), strerror(err));
1311 		ret = errno_to_be_err(err);
1312 		free(temp_grub);
1313 		temp_grub = NULL;
1314 		goto cleanup;
1315 	}
1316 	if ((temp_fp = fdopen(fd, "w")) == NULL) {
1317 		err = errno;
1318 		be_print_err(gettext("be_change_grub_default: "
1319 		    "failed to open %s file: %s\n"),
1320 		    temp_grub, strerror(err));
1321 		(void) close(fd);
1322 		ret = errno_to_be_err(err);
1323 		goto cleanup;
1324 	}
1325 
1326 	while (fgets(line, BUFSIZ, grub_fp)) {
1327 		char *tok = strtok(line, BE_WHITE_SPACE);
1328 
1329 		if (tok == NULL || tok[0] == '#') {
1330 			continue;
1331 		} else if (strcmp(tok, "title") == 0) {
1332 			entries++;
1333 			continue;
1334 		} else if (strcmp(tok, "bootfs") == 0) {
1335 			char *bootfs = strtok(NULL, BE_WHITE_SPACE);
1336 			if (bootfs == NULL)
1337 				continue;
1338 
1339 			if (strcmp(bootfs, be_root_ds) == 0) {
1340 				found_default = B_TRUE;
1341 				break;
1342 			}
1343 		}
1344 	}
1345 
1346 	if (!found_default) {
1347 		be_print_err(gettext("be_change_grub_default: failed "
1348 		    "to find entry for %s in the grub menu\n"),
1349 		    be_name);
1350 		ret = BE_ERR_BE_NOENT;
1351 		goto cleanup;
1352 	}
1353 
1354 	rewind(grub_fp);
1355 
1356 	while (fgets(line, BUFSIZ, grub_fp)) {
1357 		char *tok = NULL;
1358 
1359 		(void) strncpy(temp_line, line, BUFSIZ);
1360 
1361 		if ((tok = strtok(temp_line, BE_WHITE_SPACE)) != NULL &&
1362 		    strcmp(tok, "default") == 0) {
1363 			(void) snprintf(temp_line, BUFSIZ, "default %d\n",
1364 			    entries - 1 >= 0 ? entries - 1 : 0);
1365 			(void) fputs(temp_line, temp_fp);
1366 		} else {
1367 			(void) fputs(line, temp_fp);
1368 		}
1369 	}
1370 
1371 	(void) fclose(grub_fp);
1372 	grub_fp = NULL;
1373 	(void) fclose(temp_fp);
1374 	temp_fp = NULL;
1375 
1376 	if (rename(temp_grub, grub_file) != 0) {
1377 		err = errno;
1378 		be_print_err(gettext("be_change_grub_default: "
1379 		    "failed to rename file %s to %s: %s\n"),
1380 		    temp_grub, grub_file, strerror(err));
1381 		ret = errno_to_be_err(err);
1382 		goto cleanup;
1383 	}
1384 	free(temp_grub);
1385 	temp_grub = NULL;
1386 
1387 	/* Set the perms and ownership of the updated file */
1388 	if (chmod(grub_file, sb.st_mode) != 0) {
1389 		err = errno;
1390 		be_print_err(gettext("be_change_grub_default: "
1391 		    "failed to chmod %s: %s\n"), grub_file, strerror(err));
1392 		ret = errno_to_be_err(err);
1393 		goto cleanup;
1394 	}
1395 	if (chown(grub_file, sb.st_uid, sb.st_gid) != 0) {
1396 		err = errno;
1397 		be_print_err(gettext("be_change_grub_default: "
1398 		    "failed to chown %s: %s\n"), grub_file, strerror(err));
1399 		ret = errno_to_be_err(err);
1400 	}
1401 
1402 cleanup:
1403 	if (pool_mounted) {
1404 		int err = BE_SUCCESS;
1405 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1406 		if (ret == BE_SUCCESS)
1407 			ret = err;
1408 		free(orig_mntpnt);
1409 		free(ptmp_mntpnt);
1410 	}
1411 	ZFS_CLOSE(zhp);
1412 	if (grub_fp != NULL)
1413 		(void) fclose(grub_fp);
1414 	if (temp_fp != NULL)
1415 		(void) fclose(temp_fp);
1416 	if (temp_grub != NULL) {
1417 		(void) unlink(temp_grub);
1418 		free(temp_grub);
1419 	}
1420 
1421 	return (ret);
1422 }
1423 
1424 /*
1425  * Function:	be_update_menu
1426  * Description:	This function is used by be_rename to change the BE name in
1427  *		an existing entry in the grub menu to the new name of the BE.
1428  * Parameters:
1429  *		be_orig_name - the original name of the BE
1430  *		be_new_name - the new name the BE is being renameed to.
1431  *		be_root_pool - The pool which contains the grub menu
1432  *		boot_pool - the pool where the BE is, if different than
1433  *			the pool containing the boot menu.  If this is
1434  *			NULL it will be set to be_root_pool.
1435  * Returns:
1436  *		BE_SUCCESS - Success
1437  *		be_errno_t - Failure
1438  * Scope:
1439  *		Semi-private (library wide use only)
1440  */
1441 int
1442 be_update_menu(char *be_orig_name, char *be_new_name, char *be_root_pool,
1443     char *boot_pool)
1444 {
1445 	zfs_handle_t *zhp = NULL;
1446 	char menu_file[MAXPATHLEN];
1447 	char be_root_ds[MAXPATHLEN];
1448 	char be_new_root_ds[MAXPATHLEN];
1449 	char line[BUFSIZ];
1450 	char *pool_mntpnt = NULL;
1451 	char *ptmp_mntpnt = NULL;
1452 	char *orig_mntpnt = NULL;
1453 	char *temp_menu = NULL;
1454 	FILE *menu_fp = NULL;
1455 	FILE *new_fp = NULL;
1456 	struct stat sb;
1457 	int temp_menu_len = 0;
1458 	int tmp_fd;
1459 	int ret = BE_SUCCESS;
1460 	int err = 0;
1461 	boolean_t pool_mounted = B_FALSE;
1462 
1463 	errno = 0;
1464 
1465 	if (boot_pool == NULL)
1466 		boot_pool = be_root_pool;
1467 
1468 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1469 		be_print_err(gettext("be_update_menu: failed to open "
1470 		    "pool dataset for %s: %s\n"), be_root_pool,
1471 		    libzfs_error_description(g_zfs));
1472 		return (zfs_err_to_be_err(g_zfs));
1473 	}
1474 
1475 	/*
1476 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1477 	 * attempt to mount it.
1478 	 */
1479 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1480 	    &pool_mounted)) != BE_SUCCESS) {
1481 		be_print_err(gettext("be_update_menu: pool dataset "
1482 		    "(%s) could not be mounted\n"), be_root_pool);
1483 		ZFS_CLOSE(zhp);
1484 		return (ret);
1485 	}
1486 
1487 	/*
1488 	 * Get the mountpoint for the root pool dataset.
1489 	 */
1490 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1491 		be_print_err(gettext("be_update_menu: failed "
1492 		    "to get mount point for the root pool. Can't set "
1493 		    "the default BE in the grub menu.\n"));
1494 		ret = BE_ERR_NO_MENU;
1495 		goto cleanup;
1496 	}
1497 
1498 	/*
1499 	 * Check to see if this system supports grub
1500 	 */
1501 	if (be_has_grub()) {
1502 		(void) snprintf(menu_file, sizeof (menu_file),
1503 		    "%s%s", pool_mntpnt, BE_GRUB_MENU);
1504 	} else {
1505 		(void) snprintf(menu_file, sizeof (menu_file),
1506 		    "%s%s", pool_mntpnt, BE_SPARC_MENU);
1507 	}
1508 
1509 	be_make_root_ds(be_root_pool, be_orig_name, be_root_ds,
1510 	    sizeof (be_root_ds));
1511 	be_make_root_ds(be_root_pool, be_new_name, be_new_root_ds,
1512 	    sizeof (be_new_root_ds));
1513 
1514 	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu_file,
1515 	    &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
1516 		goto cleanup;
1517 	} else if (menu_fp == NULL) {
1518 		ret = BE_ERR_NO_MENU;
1519 		goto cleanup;
1520 	}
1521 
1522 	free(pool_mntpnt);
1523 	pool_mntpnt = NULL;
1524 
1525 	/* Grab the stat of the original menu file */
1526 	if (stat(menu_file, &sb) != 0) {
1527 		err = errno;
1528 		be_print_err(gettext("be_update_menu: "
1529 		    "failed to stat file %s: %s\n"), menu_file, strerror(err));
1530 		(void) fclose(menu_fp);
1531 		ret = errno_to_be_err(err);
1532 		goto cleanup;
1533 	}
1534 
1535 	/* Create tmp file for modified menu.lst */
1536 	temp_menu_len = strlen(menu_file) + 7;
1537 	if ((temp_menu = (char *)malloc(temp_menu_len))
1538 	    == NULL) {
1539 		be_print_err(gettext("be_update_menu: "
1540 		    "malloc failed\n"));
1541 		(void) fclose(menu_fp);
1542 		ret = BE_ERR_NOMEM;
1543 		goto cleanup;
1544 	}
1545 	(void) memset(temp_menu, 0, temp_menu_len);
1546 	(void) strlcpy(temp_menu, menu_file, temp_menu_len);
1547 	(void) strlcat(temp_menu, "XXXXXX", temp_menu_len);
1548 	if ((tmp_fd = mkstemp(temp_menu)) == -1) {
1549 		err = errno;
1550 		be_print_err(gettext("be_update_menu: "
1551 		    "mkstemp failed: %s\n"), strerror(err));
1552 		(void) fclose(menu_fp);
1553 		free(temp_menu);
1554 		ret = errno_to_be_err(err);
1555 		goto cleanup;
1556 	}
1557 	if ((new_fp = fdopen(tmp_fd, "w")) == NULL) {
1558 		err = errno;
1559 		be_print_err(gettext("be_update_menu: "
1560 		    "fdopen failed: %s\n"), strerror(err));
1561 		(void) close(tmp_fd);
1562 		(void) fclose(menu_fp);
1563 		free(temp_menu);
1564 		ret = errno_to_be_err(err);
1565 		goto cleanup;
1566 	}
1567 
1568 	while (fgets(line, BUFSIZ, menu_fp)) {
1569 		char tline[BUFSIZ];
1570 		char new_line[BUFSIZ];
1571 		char *c = NULL;
1572 
1573 		(void) strlcpy(tline, line, sizeof (tline));
1574 
1575 		/* Tokenize line */
1576 		c = strtok(tline, BE_WHITE_SPACE);
1577 
1578 		if (c == NULL) {
1579 			/* Found empty line, write it out. */
1580 			(void) fputs(line, new_fp);
1581 		} else if (c[0] == '#') {
1582 			/* Found a comment line, write it out. */
1583 			(void) fputs(line, new_fp);
1584 		} else if (strcmp(c, "title") == 0) {
1585 			char *name = NULL;
1586 			char *desc = NULL;
1587 
1588 			/*
1589 			 * Found a 'title' line, parse out BE name or
1590 			 * the description.
1591 			 */
1592 			name = strtok(NULL, BE_WHITE_SPACE);
1593 
1594 			if (name == NULL) {
1595 				/*
1596 				 * Nothing after 'title', just push
1597 				 * this line through
1598 				 */
1599 				(void) fputs(line, new_fp);
1600 			} else {
1601 				/*
1602 				 * Grab the remainder of the title which
1603 				 * could be a multi worded description
1604 				 */
1605 				desc = strtok(NULL, "\n");
1606 
1607 				if (strcmp(name, be_orig_name) == 0) {
1608 					/*
1609 					 * The first token of the title is
1610 					 * the old BE name, replace it with
1611 					 * the new one, and write it out
1612 					 * along with the remainder of
1613 					 * description if there is one.
1614 					 */
1615 					if (desc) {
1616 						(void) snprintf(new_line,
1617 						    sizeof (new_line),
1618 						    "title %s %s\n",
1619 						    be_new_name, desc);
1620 					} else {
1621 						(void) snprintf(new_line,
1622 						    sizeof (new_line),
1623 						    "title %s\n", be_new_name);
1624 					}
1625 
1626 					(void) fputs(new_line, new_fp);
1627 				} else {
1628 					(void) fputs(line, new_fp);
1629 				}
1630 			}
1631 		} else if (strcmp(c, "bootfs") == 0) {
1632 			/*
1633 			 * Found a 'bootfs' line, parse out the BE root
1634 			 * dataset value.
1635 			 */
1636 			char *root_ds = strtok(NULL, BE_WHITE_SPACE);
1637 
1638 			if (root_ds == NULL) {
1639 				/*
1640 				 * Nothing after 'bootfs', just push
1641 				 * this line through
1642 				 */
1643 				(void) fputs(line, new_fp);
1644 			} else {
1645 				/*
1646 				 * If this bootfs is the one we're renaming,
1647 				 * write out the new root dataset value
1648 				 */
1649 				if (strcmp(root_ds, be_root_ds) == 0) {
1650 					(void) snprintf(new_line,
1651 					    sizeof (new_line), "bootfs %s\n",
1652 					    be_new_root_ds);
1653 
1654 					(void) fputs(new_line, new_fp);
1655 				} else {
1656 					(void) fputs(line, new_fp);
1657 				}
1658 			}
1659 		} else {
1660 			/*
1661 			 * Found some other line we don't care
1662 			 * about, write it out.
1663 			 */
1664 			(void) fputs(line, new_fp);
1665 		}
1666 	}
1667 
1668 	(void) fclose(menu_fp);
1669 	(void) fclose(new_fp);
1670 	(void) close(tmp_fd);
1671 
1672 	if (rename(temp_menu, menu_file) != 0) {
1673 		err = errno;
1674 		be_print_err(gettext("be_update_menu: "
1675 		    "failed to rename file %s to %s: %s\n"),
1676 		    temp_menu, menu_file, strerror(err));
1677 		ret = errno_to_be_err(err);
1678 	}
1679 	free(temp_menu);
1680 
1681 	/* Set the perms and ownership of the updated file */
1682 	if (chmod(menu_file, sb.st_mode) != 0) {
1683 		err = errno;
1684 		be_print_err(gettext("be_update_menu: "
1685 		    "failed to chmod %s: %s\n"), menu_file, strerror(err));
1686 		ret = errno_to_be_err(err);
1687 		goto cleanup;
1688 	}
1689 	if (chown(menu_file, sb.st_uid, sb.st_gid) != 0) {
1690 		err = errno;
1691 		be_print_err(gettext("be_update_menu: "
1692 		    "failed to chown %s: %s\n"), menu_file, strerror(err));
1693 		ret = errno_to_be_err(err);
1694 	}
1695 
1696 cleanup:
1697 	if (pool_mounted) {
1698 		int err = BE_SUCCESS;
1699 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1700 		if (ret == BE_SUCCESS)
1701 			ret = err;
1702 		free(orig_mntpnt);
1703 		free(ptmp_mntpnt);
1704 	}
1705 	ZFS_CLOSE(zhp);
1706 	return (ret);
1707 }
1708 
1709 /*
1710  * Function:	be_has_menu_entry
1711  * Description:	Checks to see if the BEs root dataset has an entry in the grub
1712  *		menu.
1713  * Parameters:
1714  *		be_dataset - The root dataset of the BE
1715  *		be_root_pool - The pool which contains the boot menu
1716  *		entry - A pointer the the entry number of the BE if found.
1717  * Returns:
1718  *		B_TRUE - Success
1719  *		B_FALSE - Failure
1720  * Scope:
1721  *		Semi-private (library wide use only)
1722  */
1723 boolean_t
1724 be_has_menu_entry(char *be_dataset, char *be_root_pool, int *entry)
1725 {
1726 	zfs_handle_t *zhp = NULL;
1727 	char		menu_file[MAXPATHLEN];
1728 	FILE		*menu_fp;
1729 	char		line[BUFSIZ];
1730 	char		*last;
1731 	char		*rpool_mntpnt = NULL;
1732 	char		*ptmp_mntpnt = NULL;
1733 	char		*orig_mntpnt = NULL;
1734 	int		ent_num = 0;
1735 	boolean_t	ret = 0;
1736 	boolean_t	pool_mounted = B_FALSE;
1737 
1738 
1739 	/*
1740 	 * Check to see if this system supports grub
1741 	 */
1742 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
1743 		be_print_err(gettext("be_has_menu_entry: failed to open "
1744 		    "pool dataset for %s: %s\n"), be_root_pool,
1745 		    libzfs_error_description(g_zfs));
1746 		return (B_FALSE);
1747 	}
1748 
1749 	/*
1750 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
1751 	 * attempt to mount it.
1752 	 */
1753 	if (be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
1754 	    &pool_mounted) != 0) {
1755 		be_print_err(gettext("be_has_menu_entry: pool dataset "
1756 		    "(%s) could not be mounted\n"), be_root_pool);
1757 		ZFS_CLOSE(zhp);
1758 		return (B_FALSE);
1759 	}
1760 
1761 	/*
1762 	 * Get the mountpoint for the root pool dataset.
1763 	 */
1764 	if (!zfs_is_mounted(zhp, &rpool_mntpnt)) {
1765 		be_print_err(gettext("be_has_menu_entry: pool "
1766 		    "dataset (%s) is not mounted. Can't set "
1767 		    "the default BE in the grub menu.\n"), be_root_pool);
1768 		ret = B_FALSE;
1769 		goto cleanup;
1770 	}
1771 
1772 	if (be_has_grub()) {
1773 		(void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
1774 		    rpool_mntpnt, BE_GRUB_MENU);
1775 	} else {
1776 		(void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
1777 		    rpool_mntpnt, BE_SPARC_MENU);
1778 	}
1779 
1780 	if (be_open_menu(be_root_pool, rpool_mntpnt, menu_file, &menu_fp, "r",
1781 	    B_FALSE) != 0) {
1782 		ret = B_FALSE;
1783 		goto cleanup;
1784 	} else if (menu_fp == NULL) {
1785 		ret = B_FALSE;
1786 		goto cleanup;
1787 	}
1788 
1789 	free(rpool_mntpnt);
1790 	rpool_mntpnt = NULL;
1791 
1792 	while (fgets(line, BUFSIZ, menu_fp)) {
1793 		char *tok = strtok_r(line, BE_WHITE_SPACE, &last);
1794 
1795 		if (tok != NULL && tok[0] != '#') {
1796 			if (strcmp(tok, "bootfs") == 0) {
1797 				tok = strtok_r(last, BE_WHITE_SPACE, &last);
1798 				if (tok != NULL && strcmp(tok,
1799 				    be_dataset) == 0) {
1800 					(void) fclose(menu_fp);
1801 					/*
1802 					 * The entry number needs to be
1803 					 * decremented here because the title
1804 					 * will always be the first line for
1805 					 * an entry. Because of this we'll
1806 					 * always be off by one entry when we
1807 					 * check for bootfs.
1808 					 */
1809 					*entry = ent_num - 1;
1810 					ret = B_TRUE;
1811 					goto cleanup;
1812 				}
1813 			} else if (strcmp(tok, "title") == 0)
1814 				ent_num++;
1815 		}
1816 	}
1817 
1818 cleanup:
1819 	if (pool_mounted) {
1820 		(void) be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1821 		free(orig_mntpnt);
1822 		free(ptmp_mntpnt);
1823 	}
1824 	ZFS_CLOSE(zhp);
1825 	(void) fclose(menu_fp);
1826 	return (ret);
1827 }
1828 
1829 /*
1830  * Function:	be_update_vfstab
1831  * Description:	This function digs into a BE's vfstab and updates all
1832  *		entries with file systems listed in be_fs_list_data_t.
1833  *		The entry's root container dataset and be_name will be
1834  *		updated with the parameters passed in.
1835  * Parameters:
1836  *		be_name - name of BE to update
1837  *		old_rc_loc - dataset under which the root container dataset
1838  *			of the old BE resides in.
1839  *		new_rc_loc - dataset under which the root container dataset
1840  *			of the new BE resides in.
1841  *		fld - be_fs_list_data_t pointer providing the list of
1842  *			file systems to look for in vfstab.
1843  *		mountpoint - directory of where BE is currently mounted.
1844  *			If NULL, then BE is not currently mounted.
1845  * Returns:
1846  *		BE_SUCCESS - Success
1847  *		be_errno_t - Failure
1848  * Scope:
1849  *		Semi-private (library wide use only)
1850  */
1851 int
1852 be_update_vfstab(char *be_name, char *old_rc_loc, char *new_rc_loc,
1853     be_fs_list_data_t *fld, char *mountpoint)
1854 {
1855 	char		*tmp_mountpoint = NULL;
1856 	char		alt_vfstab[MAXPATHLEN];
1857 	int		ret = BE_SUCCESS, err = BE_SUCCESS;
1858 
1859 	if (fld == NULL || fld->fs_list == NULL || fld->fs_num == 0)
1860 		return (BE_SUCCESS);
1861 
1862 	/* If BE not already mounted, mount the BE */
1863 	if (mountpoint == NULL) {
1864 		if ((ret = _be_mount(be_name, &tmp_mountpoint,
1865 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1866 			be_print_err(gettext("be_update_vfstab: "
1867 			    "failed to mount BE (%s)\n"), be_name);
1868 			return (ret);
1869 		}
1870 	} else {
1871 		tmp_mountpoint = mountpoint;
1872 	}
1873 
1874 	/* Get string for vfstab in the mounted BE. */
1875 	(void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
1876 	    tmp_mountpoint);
1877 
1878 	/* Update the vfstab */
1879 	ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
1880 	    fld);
1881 
1882 	/* Unmount BE if we mounted it */
1883 	if (mountpoint == NULL) {
1884 		if ((err = _be_unmount(be_name, 0)) == BE_SUCCESS) {
1885 			/* Remove temporary mountpoint */
1886 			(void) rmdir(tmp_mountpoint);
1887 		} else {
1888 			be_print_err(gettext("be_update_vfstab: "
1889 			    "failed to unmount BE %s mounted at %s\n"),
1890 			    be_name, tmp_mountpoint);
1891 			if (ret == BE_SUCCESS)
1892 				ret = err;
1893 		}
1894 
1895 		free(tmp_mountpoint);
1896 	}
1897 
1898 	return (ret);
1899 }
1900 
1901 /*
1902  * Function:	be_update_zone_vfstab
1903  * Description:	This function digs into a zone BE's vfstab and updates all
1904  *		entries with file systems listed in be_fs_list_data_t.
1905  *		The entry's root container dataset and be_name will be
1906  *		updated with the parameters passed in.
1907  * Parameters:
1908  *		zhp - zfs_handle_t pointer to zone root dataset.
1909  *		be_name - name of zone BE to update
1910  *		old_rc_loc - dataset under which the root container dataset
1911  *			of the old zone BE resides in.
1912  *		new_rc_loc - dataset under which the root container dataset
1913  *			of the new zone BE resides in.
1914  *		fld - be_fs_list_data_t pointer providing the list of
1915  *			file systems to look for in vfstab.
1916  * Returns:
1917  *		BE_SUCCESS - Success
1918  *		be_errno_t - Failure
1919  * Scope:
1920  *		Semi-private (library wide use only)
1921  */
1922 int
1923 be_update_zone_vfstab(zfs_handle_t *zhp, char *be_name, char *old_rc_loc,
1924     char *new_rc_loc, be_fs_list_data_t *fld)
1925 {
1926 	be_mount_data_t		md = { 0 };
1927 	be_unmount_data_t	ud = { 0 };
1928 	char			alt_vfstab[MAXPATHLEN];
1929 	boolean_t		mounted_here = B_FALSE;
1930 	int			ret = BE_SUCCESS;
1931 
1932 	/*
1933 	 * If zone root not already mounted, mount it at a
1934 	 * temporary location.
1935 	 */
1936 	if (!zfs_is_mounted(zhp, &md.altroot)) {
1937 		/* Generate temporary mountpoint to mount zone root */
1938 		if ((ret = be_make_tmp_mountpoint(&md.altroot)) != BE_SUCCESS) {
1939 			be_print_err(gettext("be_update_zone_vfstab: "
1940 			    "failed to make temporary mountpoint to "
1941 			    "mount zone root\n"));
1942 			return (ret);
1943 		}
1944 
1945 		if (be_mount_zone_root(zhp, &md) != BE_SUCCESS) {
1946 			be_print_err(gettext("be_update_zone_vfstab: "
1947 			    "failed to mount zone root %s\n"),
1948 			    zfs_get_name(zhp));
1949 			free(md.altroot);
1950 			return (BE_ERR_MOUNT_ZONEROOT);
1951 		}
1952 		mounted_here = B_TRUE;
1953 	}
1954 
1955 	/* Get string from vfstab in the mounted zone BE */
1956 	(void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
1957 	    md.altroot);
1958 
1959 	/* Update the vfstab */
1960 	ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
1961 	    fld);
1962 
1963 	/* Unmount zone root if we mounted it */
1964 	if (mounted_here) {
1965 		ud.force = B_TRUE;
1966 
1967 		if (be_unmount_zone_root(zhp, &ud) == BE_SUCCESS) {
1968 			/* Remove the temporary mountpoint */
1969 			(void) rmdir(md.altroot);
1970 		} else {
1971 			be_print_err(gettext("be_update_zone_vfstab: "
1972 			    "failed to unmount zone root %s from %s\n"),
1973 			    zfs_get_name(zhp), md.altroot);
1974 			if (ret == 0)
1975 				ret = BE_ERR_UMOUNT_ZONEROOT;
1976 		}
1977 	}
1978 
1979 	free(md.altroot);
1980 	return (ret);
1981 }
1982 
1983 /*
1984  * Function:	be_auto_snap_name
1985  * Description:	Generate an auto snapshot name constructed based on the
1986  *		current date and time.  The auto snapshot name is of the form:
1987  *
1988  *			<date>-<time>
1989  *
1990  *		where <date> is in ISO standard format, so the resultant name
1991  *		is of the form:
1992  *
1993  *			%Y-%m-%d-%H:%M:%S
1994  *
1995  * Parameters:
1996  *		None
1997  * Returns:
1998  *		Success - pointer to auto generated snapshot name.  The name
1999  *			is allocated in heap storage so the caller is
2000  *			responsible for free'ing the name.
2001  *		Failure - NULL
2002  * Scope:
2003  *		Semi-private (library wide use only)
2004  */
2005 char *
2006 be_auto_snap_name(void)
2007 {
2008 	time_t		utc_tm = NULL;
2009 	struct tm	*gmt_tm = NULL;
2010 	char		gmt_time_str[64];
2011 	char		*auto_snap_name = NULL;
2012 
2013 	if (time(&utc_tm) == -1) {
2014 		be_print_err(gettext("be_auto_snap_name: time() failed\n"));
2015 		return (NULL);
2016 	}
2017 
2018 	if ((gmt_tm = gmtime(&utc_tm)) == NULL) {
2019 		be_print_err(gettext("be_auto_snap_name: gmtime() failed\n"));
2020 		return (NULL);
2021 	}
2022 
2023 	(void) strftime(gmt_time_str, sizeof (gmt_time_str), "%F-%T", gmt_tm);
2024 
2025 	if ((auto_snap_name = strdup(gmt_time_str)) == NULL) {
2026 		be_print_err(gettext("be_auto_snap_name: "
2027 		    "memory allocation failed\n"));
2028 		return (NULL);
2029 	}
2030 
2031 	return (auto_snap_name);
2032 }
2033 
2034 /*
2035  * Function:	be_auto_be_name
2036  * Description:	Generate an auto BE name constructed based on the BE name
2037  *		of the original BE being cloned.
2038  * Parameters:
2039  *		obe_name - name of the original BE being cloned.
2040  * Returns:
2041  *		Success - pointer to auto generated BE name.  The name
2042  *			is allocated in heap storage so the caller is
2043  *			responsible for free'ing the name.
2044  *		Failure - NULL
2045  * Scope:
2046  *		Semi-private (library wide use only)
2047  */
2048 char *
2049 be_auto_be_name(char *obe_name)
2050 {
2051 	return (be_get_auto_name(obe_name, NULL, B_FALSE));
2052 }
2053 
2054 /*
2055  * Function:	be_auto_zone_be_name
2056  * Description:	Generate an auto BE name for a zone constructed based on
2057  *              the BE name of the original zone BE being cloned.
2058  * Parameters:
2059  *              container_ds - container dataset for the zone.
2060  *		zbe_name - name of the original zone BE being cloned.
2061  * Returns:
2062  *		Success - pointer to auto generated BE name.  The name
2063  *			is allocated in heap storage so the caller is
2064  *			responsible for free'ing the name.
2065  *		Failure - NULL
2066  * Scope:
2067  *		Semi-private (library wide use only)
2068  */
2069 char *
2070 be_auto_zone_be_name(char *container_ds, char *zbe_name)
2071 {
2072 	return (be_get_auto_name(zbe_name, container_ds, B_TRUE));
2073 }
2074 
2075 /*
2076  * Function:	be_valid_be_name
2077  * Description:	Validates a BE name.
2078  * Parameters:
2079  *		be_name - name of BE to validate
2080  * Returns:
2081  *		B_TRUE - be_name is valid
2082  *		B_FALSE - be_name is invalid
2083  * Scope:
2084  *		Semi-private (library wide use only)
2085  */
2086 
2087 boolean_t
2088 be_valid_be_name(const char *be_name)
2089 {
2090 	const char	*c = NULL;
2091 
2092 	if (be_name == NULL)
2093 		return (B_FALSE);
2094 
2095 	/*
2096 	 * A BE name must not be a multi-level dataset name.  We also check
2097 	 * that it does not contain the ' ' and '%' characters.  The ' ' is
2098 	 * a valid character for datasets, however we don't allow that in a
2099 	 * BE name.  The '%' is invalid, but zfs_name_valid() allows it for
2100 	 * internal reasons, so we explicitly check for it here.
2101 	 */
2102 	c = be_name;
2103 	while (*c != '\0' && *c != '/' && *c != ' ' && *c != '%')
2104 		c++;
2105 
2106 	if (*c != '\0')
2107 		return (B_FALSE);
2108 
2109 	/*
2110 	 * The BE name must comply with a zfs dataset filesystem. We also
2111 	 * verify its length to be < BE_NAME_MAX_LEN.
2112 	 */
2113 	if (!zfs_name_valid(be_name, ZFS_TYPE_FILESYSTEM) ||
2114 	    strlen(be_name) > BE_NAME_MAX_LEN)
2115 		return (B_FALSE);
2116 
2117 	return (B_TRUE);
2118 }
2119 
2120 /*
2121  * Function:	be_valid_auto_snap_name
2122  * Description:	This function checks that a snapshot name is a valid auto
2123  *		generated snapshot name.  A valid auto generated snapshot
2124  *		name is of the form:
2125  *
2126  *			%Y-%m-%d-%H:%M:%S
2127  *
2128  *		An older form of the auto generated snapshot name also
2129  *		included the snapshot's BE cleanup policy and a reserved
2130  *		field.  Those names will also be verified by this function.
2131  *
2132  *		Examples of valid auto snapshot names are:
2133  *
2134  *			2008-03-31-18:41:30
2135  *			2008-03-31-22:17:24
2136  *			<policy>:-:2008:04-05-09:12:55
2137  *			<policy>:-:2008:04-06-15:34:12
2138  *
2139  * Parameters:
2140  *		name - name of the snapshot to be validated.
2141  * Returns:
2142  *		B_TRUE - the name is a valid auto snapshot name.
2143  *		B_FALSE - the name is not a valid auto snapshot name.
2144  * Scope:
2145  *		Semi-private (library wide use only)
2146  */
2147 boolean_t
2148 be_valid_auto_snap_name(char *name)
2149 {
2150 	struct tm gmt_tm;
2151 
2152 	char *policy = NULL;
2153 	char *reserved = NULL;
2154 	char *date = NULL;
2155 	char *c = NULL;
2156 
2157 	/* Validate the snapshot name by converting it into utc time */
2158 	if (strptime(name, "%Y-%m-%d-%T", &gmt_tm) != NULL &&
2159 	    (mktime(&gmt_tm) != -1)) {
2160 		return (B_TRUE);
2161 	}
2162 
2163 	/*
2164 	 * Validate the snapshot name against the older form of an
2165 	 * auto generated snapshot name.
2166 	 */
2167 	policy = strdup(name);
2168 
2169 	/*
2170 	 * Get the first field from the snapshot name,
2171 	 * which is the BE policy
2172 	 */
2173 	c = strchr(policy, ':');
2174 	if (c == NULL) {
2175 		free(policy);
2176 		return (B_FALSE);
2177 	}
2178 	c[0] = '\0';
2179 
2180 	/* Validate the policy name */
2181 	if (!valid_be_policy(policy)) {
2182 		free(policy);
2183 		return (B_FALSE);
2184 	}
2185 
2186 	/* Get the next field, which is the reserved field. */
2187 	if (c[1] == NULL || c[1] == '\0') {
2188 		free(policy);
2189 		return (B_FALSE);
2190 	}
2191 	reserved = c+1;
2192 	c = strchr(reserved, ':');
2193 	if (c == NULL) {
2194 		free(policy);
2195 		return (B_FALSE);
2196 	}
2197 	c[0] = '\0';
2198 
2199 	/* Validate the reserved field */
2200 	if (strcmp(reserved, "-") != 0) {
2201 		free(policy);
2202 		return (B_FALSE);
2203 	}
2204 
2205 	/* The remaining string should be the date field */
2206 	if (c[1] == NULL || c[1] == '\0') {
2207 		free(policy);
2208 		return (B_FALSE);
2209 	}
2210 	date = c+1;
2211 
2212 	/* Validate the date string by converting it into utc time */
2213 	if (strptime(date, "%Y-%m-%d-%T", &gmt_tm) == NULL ||
2214 	    (mktime(&gmt_tm) == -1)) {
2215 		be_print_err(gettext("be_valid_auto_snap_name: "
2216 		    "invalid auto snapshot name\n"));
2217 		free(policy);
2218 		return (B_FALSE);
2219 	}
2220 
2221 	free(policy);
2222 	return (B_TRUE);
2223 }
2224 
2225 /*
2226  * Function:	be_default_policy
2227  * Description:	Temporary hardcoded policy support.  This function returns
2228  *		the default policy type to be used to create a BE or a BE
2229  *		snapshot.
2230  * Parameters:
2231  *		None
2232  * Returns:
2233  *		Name of default BE policy.
2234  * Scope:
2235  *		Semi-private (library wide use only)
2236  */
2237 char *
2238 be_default_policy(void)
2239 {
2240 	return (BE_PLCY_STATIC);
2241 }
2242 
2243 /*
2244  * Function:	valid_be_policy
2245  * Description:	Temporary hardcoded policy support.  This function valids
2246  *		whether a policy is a valid known policy or not.
2247  * Paramters:
2248  *		policy - name of policy to validate.
2249  * Returns:
2250  *		B_TRUE - policy is a valid.
2251  *		B_FALSE - policy is invalid.
2252  * Scope:
2253  *		Semi-private (library wide use only)
2254  */
2255 boolean_t
2256 valid_be_policy(char *policy)
2257 {
2258 	if (policy == NULL)
2259 		return (B_FALSE);
2260 
2261 	if (strcmp(policy, BE_PLCY_STATIC) == 0 ||
2262 	    strcmp(policy, BE_PLCY_VOLATILE) == 0) {
2263 		return (B_TRUE);
2264 	}
2265 
2266 	return (B_FALSE);
2267 }
2268 
2269 /*
2270  * Function:	be_print_err
2271  * Description:	This function prints out error messages if do_print is
2272  *		set to B_TRUE or if the BE_PRINT_ERR environment variable
2273  *		is set to true.
2274  * Paramters:
2275  *		prnt_str - the string we wish to print and any arguments
2276  *		for the format of that string.
2277  * Returns:
2278  *		void
2279  * Scope:
2280  *		Semi-private (library wide use only)
2281  */
2282 void
2283 be_print_err(char *prnt_str, ...)
2284 {
2285 	va_list ap;
2286 	char buf[BUFSIZ];
2287 	char *env_buf;
2288 	static boolean_t env_checked = B_FALSE;
2289 
2290 	if (!env_checked) {
2291 		if ((env_buf = getenv("BE_PRINT_ERR")) != NULL) {
2292 			if (strcasecmp(env_buf, "true") == 0) {
2293 				do_print = B_TRUE;
2294 			}
2295 		}
2296 		env_checked = B_TRUE;
2297 	}
2298 
2299 	if (do_print) {
2300 		va_start(ap, prnt_str);
2301 		/* LINTED variable format specifier */
2302 		(void) vsnprintf(buf, BUFSIZ, prnt_str, ap);
2303 		(void) fputs(buf, stderr);
2304 		va_end(ap);
2305 	}
2306 }
2307 
2308 /*
2309  * Function:	be_find_current_be
2310  * Description:	Find the currently "active" BE. Fill in the
2311  * 		passed in be_transaction_data_t reference with the
2312  *		active BE's data.
2313  * Paramters:
2314  *		none
2315  * Returns:
2316  *		BE_SUCCESS - Success
2317  *		be_errnot_t - Failure
2318  * Scope:
2319  *		Semi-private (library wide use only)
2320  * Notes:
2321  *		The caller is responsible for initializing the libzfs handle
2322  *		and freeing the memory used by the active be_name.
2323  */
2324 int
2325 be_find_current_be(be_transaction_data_t *bt)
2326 {
2327 	int	zret;
2328 
2329 	if ((zret = zpool_iter(g_zfs, be_zpool_find_current_be_callback,
2330 	    bt)) == 0) {
2331 		be_print_err(gettext("be_find_current_be: failed to "
2332 		    "find current BE name\n"));
2333 		return (BE_ERR_BE_NOENT);
2334 	} else if (zret < 0) {
2335 		be_print_err(gettext("be_find_current_be: "
2336 		    "zpool_iter failed: %s\n"),
2337 		    libzfs_error_description(g_zfs));
2338 		return (zfs_err_to_be_err(g_zfs));
2339 	}
2340 
2341 	return (BE_SUCCESS);
2342 }
2343 
2344 /*
2345  * Function:	be_zpool_find_current_be_callback
2346  * Description: Callback function used to iterate through all existing pools
2347  *		to find the BE that is the currently booted BE.
2348  * Parameters:
2349  *		zlp - zpool_handle_t pointer to the current pool being
2350  *			looked at.
2351  *		data - be_transaction_data_t pointer.
2352  *			Upon successfully finding the current BE, the
2353  *			obe_zpool member of this parameter is set to the
2354  *			pool it is found in.
2355  * Return:
2356  *		1 - Found current BE in this pool.
2357  *		0 - Did not find current BE in this pool.
2358  * Scope:
2359  *		Semi-private (library wide use only)
2360  */
2361 int
2362 be_zpool_find_current_be_callback(zpool_handle_t *zlp, void *data)
2363 {
2364 	be_transaction_data_t	*bt = data;
2365 	zfs_handle_t		*zhp = NULL;
2366 	const char		*zpool =  zpool_get_name(zlp);
2367 	char			be_container_ds[MAXPATHLEN];
2368 
2369 	/*
2370 	 * Generate string for BE container dataset
2371 	 */
2372 	be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds));
2373 
2374 	/*
2375 	 * Check if a BE container dataset exists in this pool.
2376 	 */
2377 	if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
2378 		zpool_close(zlp);
2379 		return (0);
2380 	}
2381 
2382 	/*
2383 	 * Get handle to this zpool's BE container dataset.
2384 	 */
2385 	if ((zhp = zfs_open(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) ==
2386 	    NULL) {
2387 		be_print_err(gettext("be_zpool_find_current_be_callback: "
2388 		    "failed to open BE container dataset (%s)\n"),
2389 		    be_container_ds);
2390 		zpool_close(zlp);
2391 		return (0);
2392 	}
2393 
2394 	/*
2395 	 * Iterate through all potential BEs in this zpool
2396 	 */
2397 	if (zfs_iter_filesystems(zhp, be_zfs_find_current_be_callback, bt)) {
2398 		/*
2399 		 * Found current BE dataset; set obe_zpool
2400 		 */
2401 		if ((bt->obe_zpool = strdup(zpool)) == NULL) {
2402 			be_print_err(gettext(
2403 			    "be_zpool_find_current_be_callback: "
2404 			    "memory allocation failed\n"));
2405 			ZFS_CLOSE(zhp);
2406 			zpool_close(zlp);
2407 			return (0);
2408 		}
2409 
2410 		ZFS_CLOSE(zhp);
2411 		zpool_close(zlp);
2412 		return (1);
2413 	}
2414 
2415 	ZFS_CLOSE(zhp);
2416 	zpool_close(zlp);
2417 
2418 	return (0);
2419 }
2420 
2421 /*
2422  * Function:	be_zfs_find_current_be_callback
2423  * Description:	Callback function used to iterate through all BEs in a
2424  *		pool to find the BE that is the currently booted BE.
2425  * Parameters:
2426  *		zhp - zfs_handle_t pointer to current filesystem being checked.
2427  *		data - be_transaction-data_t pointer
2428  *			Upon successfully finding the current BE, the
2429  *			obe_name and obe_root_ds members of this parameter
2430  *			are set to the BE name and BE's root dataset
2431  *			respectively.
2432  * Return:
2433  *		1 - Found current BE.
2434  *		0 - Did not find current BE.
2435  * Scope:
2436  *		Semi-private (library wide use only)
2437  */
2438 int
2439 be_zfs_find_current_be_callback(zfs_handle_t *zhp, void *data)
2440 {
2441 	be_transaction_data_t	*bt = data;
2442 	char			*mp = NULL;
2443 
2444 	/*
2445 	 * Check if dataset is mounted, and if so where.
2446 	 */
2447 	if (zfs_is_mounted(zhp, &mp)) {
2448 		/*
2449 		 * If mounted at root, set obe_root_ds and obe_name
2450 		 */
2451 		if (mp != NULL && strcmp(mp, "/") == 0) {
2452 			free(mp);
2453 
2454 			if ((bt->obe_root_ds = strdup(zfs_get_name(zhp)))
2455 			    == NULL) {
2456 				be_print_err(gettext(
2457 				    "be_zfs_find_current_be_callback: "
2458 				    "memory allocation failed\n"));
2459 				ZFS_CLOSE(zhp);
2460 				return (0);
2461 			}
2462 			if ((bt->obe_name = strdup(basename(bt->obe_root_ds)))
2463 			    == NULL) {
2464 				be_print_err(gettext(
2465 				    "be_zfs_find_current_be_callback: "
2466 				    "memory allocation failed\n"));
2467 				ZFS_CLOSE(zhp);
2468 				return (0);
2469 			}
2470 
2471 			ZFS_CLOSE(zhp);
2472 			return (1);
2473 		}
2474 
2475 		free(mp);
2476 	}
2477 	ZFS_CLOSE(zhp);
2478 
2479 	return (0);
2480 }
2481 
2482 /*
2483  * Function:	be_check_be_roots_callback
2484  * Description:	This function checks whether or not the dataset name passed
2485  *		is hierachically located under the BE root container dataset
2486  *		for this pool.
2487  * Parameters:
2488  *		zlp - zpool_handle_t pointer to current pool being processed.
2489  *		data - name of dataset to check
2490  * Returns:
2491  *		0 - dataset is not in this pool's BE root container dataset
2492  *		1 - dataset is in this pool's BE root container dataset
2493  * Scope:
2494  *		Semi-private (library wide use only)
2495  */
2496 int
2497 be_check_be_roots_callback(zpool_handle_t *zlp, void *data)
2498 {
2499 	const char	*zpool = zpool_get_name(zlp);
2500 	char		*ds = data;
2501 	char		be_container_ds[MAXPATHLEN];
2502 
2503 	/* Generate string for this pool's BE root container dataset */
2504 	be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds));
2505 
2506 	/*
2507 	 * If dataset lives under the BE root container dataset
2508 	 * of this pool, return failure.
2509 	 */
2510 	if (strncmp(be_container_ds, ds, strlen(be_container_ds)) == 0 &&
2511 	    ds[strlen(be_container_ds)] == '/') {
2512 		zpool_close(zlp);
2513 		return (1);
2514 	}
2515 
2516 	zpool_close(zlp);
2517 	return (0);
2518 }
2519 
2520 /*
2521  * Function:	zfs_err_to_be_err
2522  * Description:	This function takes the error stored in the libzfs handle
2523  *		and maps it to an be_errno_t. If there are no matching
2524  *		be_errno_t's then BE_ERR_ZFS is returned.
2525  * Paramters:
2526  *		zfsh - The libzfs handle containing the error we're looking up.
2527  * Returns:
2528  *		be_errno_t
2529  * Scope:
2530  *		Semi-private (library wide use only)
2531  */
2532 int
2533 zfs_err_to_be_err(libzfs_handle_t *zfsh)
2534 {
2535 	int err = libzfs_errno(zfsh);
2536 
2537 	switch (err) {
2538 	case 0:
2539 		return (BE_SUCCESS);
2540 	case EZFS_PERM:
2541 		return (BE_ERR_PERM);
2542 	case EZFS_INTR:
2543 		return (BE_ERR_INTR);
2544 	case EZFS_NOENT:
2545 		return (BE_ERR_NOENT);
2546 	case EZFS_NOSPC:
2547 		return (BE_ERR_NOSPC);
2548 	case EZFS_MOUNTFAILED:
2549 		return (BE_ERR_MOUNT);
2550 	case EZFS_UMOUNTFAILED:
2551 		return (BE_ERR_UMOUNT);
2552 	case EZFS_EXISTS:
2553 		return (BE_ERR_BE_EXISTS);
2554 	case EZFS_BUSY:
2555 		return (BE_ERR_DEV_BUSY);
2556 	case EZFS_POOLREADONLY:
2557 		return (BE_ERR_ROFS);
2558 	case EZFS_NAMETOOLONG:
2559 		return (BE_ERR_NAMETOOLONG);
2560 	case EZFS_NODEVICE:
2561 		return (BE_ERR_NODEV);
2562 	case EZFS_POOL_INVALARG:
2563 		return (BE_ERR_INVAL);
2564 	case EZFS_PROPTYPE:
2565 		return (BE_ERR_INVALPROP);
2566 	case EZFS_BADTYPE:
2567 		return (BE_ERR_DSTYPE);
2568 	case EZFS_PROPNONINHERIT:
2569 		return (BE_ERR_NONINHERIT);
2570 	case EZFS_PROPREADONLY:
2571 		return (BE_ERR_READONLYPROP);
2572 	case EZFS_RESILVERING:
2573 	case EZFS_POOLUNAVAIL:
2574 		return (BE_ERR_UNAVAIL);
2575 	case EZFS_DSREADONLY:
2576 		return (BE_ERR_READONLYDS);
2577 	default:
2578 		return (BE_ERR_ZFS);
2579 	}
2580 }
2581 
2582 /*
2583  * Function:	errno_to_be_err
2584  * Description:	This function takes an errno and maps it to an be_errno_t.
2585  *		If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
2586  *		returned.
2587  * Paramters:
2588  *		err - The errno we're compairing against.
2589  * Returns:
2590  *		be_errno_t
2591  * Scope:
2592  *		Semi-private (library wide use only)
2593  */
2594 int
2595 errno_to_be_err(int err)
2596 {
2597 	switch (err) {
2598 	case EPERM:
2599 		return (BE_ERR_PERM);
2600 	case EACCES:
2601 		return (BE_ERR_ACCESS);
2602 	case ECANCELED:
2603 		return (BE_ERR_CANCELED);
2604 	case EINTR:
2605 		return (BE_ERR_INTR);
2606 	case ENOENT:
2607 		return (BE_ERR_NOENT);
2608 	case ENOSPC:
2609 	case EDQUOT:
2610 		return (BE_ERR_NOSPC);
2611 	case EEXIST:
2612 		return (BE_ERR_BE_EXISTS);
2613 	case EBUSY:
2614 		return (BE_ERR_BUSY);
2615 	case EROFS:
2616 		return (BE_ERR_ROFS);
2617 	case ENAMETOOLONG:
2618 		return (BE_ERR_NAMETOOLONG);
2619 	case ENXIO:
2620 		return (BE_ERR_NXIO);
2621 	case EINVAL:
2622 		return (BE_ERR_INVAL);
2623 	case EFAULT:
2624 		return (BE_ERR_FAULT);
2625 	default:
2626 		return (BE_ERR_UNKNOWN);
2627 	}
2628 }
2629 
2630 /*
2631  * Function:	be_err_to_str
2632  * Description:	This function takes a be_errno_t and maps it to a message.
2633  *		If there are no matching be_errno_t's then NULL is returned.
2634  * Paramters:
2635  *		be_errno_t - The be_errno_t we're mapping.
2636  * Returns:
2637  *		string or NULL if the error code is not known.
2638  * Scope:
2639  *		Semi-private (library wide use only)
2640  */
2641 char *
2642 be_err_to_str(int err)
2643 {
2644 	switch (err) {
2645 	case BE_ERR_ACCESS:
2646 		return (gettext("Permission denied."));
2647 	case BE_ERR_ACTIVATE_CURR:
2648 		return (gettext("Activation of current BE failed."));
2649 	case BE_ERR_AUTONAME:
2650 		return (gettext("Auto naming failed."));
2651 	case BE_ERR_BE_NOENT:
2652 		return (gettext("No such BE."));
2653 	case BE_ERR_BUSY:
2654 		return (gettext("Mount busy."));
2655 	case BE_ERR_DEV_BUSY:
2656 		return (gettext("Device busy."));
2657 	case BE_ERR_CANCELED:
2658 		return (gettext("Operation canceled."));
2659 	case BE_ERR_CLONE:
2660 		return (gettext("BE clone failed."));
2661 	case BE_ERR_COPY:
2662 		return (gettext("BE copy failed."));
2663 	case BE_ERR_CREATDS:
2664 		return (gettext("Dataset creation failed."));
2665 	case BE_ERR_CURR_BE_NOT_FOUND:
2666 		return (gettext("Can't find current BE."));
2667 	case BE_ERR_DESTROY:
2668 		return (gettext("Failed to destroy BE or snapshot."));
2669 	case BE_ERR_DESTROY_CURR_BE:
2670 		return (gettext("Cannot destroy current BE."));
2671 	case BE_ERR_DEMOTE:
2672 		return (gettext("BE demotion failed."));
2673 	case BE_ERR_DSTYPE:
2674 		return (gettext("Invalid dataset type."));
2675 	case BE_ERR_BE_EXISTS:
2676 		return (gettext("BE exists."));
2677 	case BE_ERR_INIT:
2678 		return (gettext("be_zfs_init failed."));
2679 	case BE_ERR_INTR:
2680 		return (gettext("Interupted system call."));
2681 	case BE_ERR_INVAL:
2682 		return (gettext("Invalid argument."));
2683 	case BE_ERR_INVALPROP:
2684 		return (gettext("Invalid property for dataset."));
2685 	case BE_ERR_INVALMOUNTPOINT:
2686 		return (gettext("Unexpected mountpoint."));
2687 	case BE_ERR_MOUNT:
2688 		return (gettext("Mount failed."));
2689 	case BE_ERR_MOUNTED:
2690 		return (gettext("Already mounted."));
2691 	case BE_ERR_NAMETOOLONG:
2692 		return (gettext("name > BUFSIZ."));
2693 	case BE_ERR_NOENT:
2694 		return (gettext("Doesn't exist."));
2695 	case BE_ERR_POOL_NOENT:
2696 		return (gettext("No such pool."));
2697 	case BE_ERR_NODEV:
2698 		return (gettext("No such device."));
2699 	case BE_ERR_NOTMOUNTED:
2700 		return (gettext("File system not mounted."));
2701 	case BE_ERR_NOMEM:
2702 		return (gettext("Not enough memory."));
2703 	case BE_ERR_NONINHERIT:
2704 		return (gettext(
2705 		    "Property is not inheritable for the BE dataset."));
2706 	case BE_ERR_NXIO:
2707 		return (gettext("No such device or address."));
2708 	case BE_ERR_NOSPC:
2709 		return (gettext("No space on device."));
2710 	case BE_ERR_NOTSUP:
2711 		return (gettext("Operation not supported."));
2712 	case BE_ERR_OPEN:
2713 		return (gettext("Open failed."));
2714 	case BE_ERR_PERM:
2715 		return (gettext("Not owner."));
2716 	case BE_ERR_UNAVAIL:
2717 		return (gettext("The BE is currently unavailable."));
2718 	case BE_ERR_PROMOTE:
2719 		return (gettext("BE promotion failed."));
2720 	case BE_ERR_ROFS:
2721 		return (gettext("Read only file system."));
2722 	case BE_ERR_READONLYDS:
2723 		return (gettext("Read only dataset."));
2724 	case BE_ERR_READONLYPROP:
2725 		return (gettext("Read only property."));
2726 	case BE_ERR_RENAME_ACTIVE:
2727 		return (gettext("Renaming the active BE is not supported."));
2728 	case BE_ERR_SS_EXISTS:
2729 		return (gettext("Snapshot exists."));
2730 	case BE_ERR_SS_NOENT:
2731 		return (gettext("No such snapshot."));
2732 	case BE_ERR_UMOUNT:
2733 		return (gettext("Unmount failed."));
2734 	case BE_ERR_UMOUNT_CURR_BE:
2735 		return (gettext("Can't unmount the current BE."));
2736 	case BE_ERR_UMOUNT_SHARED:
2737 		return (gettext("Unmount of a shared File System failed."));
2738 	case BE_ERR_FAULT:
2739 		return (gettext("Bad address."));
2740 	case BE_ERR_UNKNOWN:
2741 		return (gettext("Unknown error."));
2742 	case BE_ERR_ZFS:
2743 		return (gettext("ZFS returned an error."));
2744 	case BE_ERR_GEN_UUID:
2745 		return (gettext("Failed to generate uuid."));
2746 	case BE_ERR_PARSE_UUID:
2747 		return (gettext("Failed to parse uuid."));
2748 	case BE_ERR_NO_UUID:
2749 		return (gettext("No uuid"));
2750 	case BE_ERR_ZONE_NO_PARENTBE:
2751 		return (gettext("No parent uuid"));
2752 	case BE_ERR_ZONE_MULTIPLE_ACTIVE:
2753 		return (gettext("Multiple active zone roots"));
2754 	case BE_ERR_ZONE_NO_ACTIVE_ROOT:
2755 		return (gettext("No active zone root"));
2756 	case BE_ERR_ZONE_ROOT_NOT_LEGACY:
2757 		return (gettext("Zone root not legacy"));
2758 	case BE_ERR_MOUNT_ZONEROOT:
2759 		return (gettext("Failed to mount a zone root."));
2760 	case BE_ERR_UMOUNT_ZONEROOT:
2761 		return (gettext("Failed to unmount a zone root."));
2762 	case BE_ERR_NO_MOUNTED_ZONE:
2763 		return (gettext("Zone is not mounted"));
2764 	case BE_ERR_ZONES_UNMOUNT:
2765 		return (gettext("Unable to unmount a zone BE."));
2766 	case BE_ERR_NO_MENU:
2767 		return (gettext("Missing boot menu file."));
2768 	case BE_ERR_BAD_MENU_PATH:
2769 		return (gettext("Invalid path for menu.lst file"));
2770 	case BE_ERR_ZONE_SS_EXISTS:
2771 		return (gettext("Zone snapshot exists."));
2772 	case BE_ERR_ADD_SPLASH_ICT:
2773 		return (gettext("Add_spash_image ICT failed."));
2774 	case BE_ERR_BOOTFILE_INST:
2775 		return (gettext("Error installing boot files."));
2776 	case BE_ERR_EXTCMD:
2777 		return (gettext("Error running an external command."));
2778 	default:
2779 		return (NULL);
2780 	}
2781 }
2782 
2783 /*
2784  * Function:    be_has_grub
2785  * Description: Boolean function indicating whether the current system
2786  *		uses grub.
2787  * Return:      B_FALSE - the system does not have grub
2788  *              B_TRUE - the system does have grub.
2789  * Scope:
2790  *		Semi-private (library wide use only)
2791  */
2792 boolean_t
2793 be_has_grub(void)
2794 {
2795 	/*
2796 	 * TODO: This will need to be expanded to check for the existence of
2797 	 * grub if and when there is grub support for SPARC.
2798 	 */
2799 	return (be_is_isa("i386"));
2800 }
2801 
2802 /*
2803  * Function:    be_is_isa
2804  * Description: Boolean function indicating whether the instruction set
2805  *              architecture of the executing system matches the name provided.
2806  *              The string must match a system defined architecture (e.g.
2807  *              "i386", "sparc") and is case sensitive.
2808  * Parameters:  name - string representing the name of instruction set
2809  *			architecture being tested
2810  * Returns:     B_FALSE - the system instruction set architecture is different
2811  *			from the one specified
2812  *              B_TRUE - the system instruction set architecture is the same
2813  *			as the one specified
2814  * Scope:
2815  *		Semi-private (library wide use only)
2816  */
2817 boolean_t
2818 be_is_isa(char *name)
2819 {
2820 	return ((strcmp((char *)be_get_default_isa(), name) == 0));
2821 }
2822 
2823 /*
2824  * Function: be_get_default_isa
2825  * Description:
2826  *      Returns the default instruction set architecture of the
2827  *      machine it is executed on. (eg. sparc, i386, ...)
2828  *      NOTE:   SYS_INST environment variable may override default
2829  *              return value
2830  * Parameters:
2831  *		none
2832  * Returns:
2833  *		NULL - the architecture returned by sysinfo() was too
2834  *			long for local variables
2835  *		char * - pointer to a string containing the default
2836  *			implementation
2837  * Scope:
2838  *		Semi-private (library wide use only)
2839  */
2840 char *
2841 be_get_default_isa(void)
2842 {
2843 	int	i;
2844 	char	*envp;
2845 	static char	default_inst[ARCH_LENGTH] = "";
2846 
2847 	if (default_inst[0] == '\0') {
2848 		if ((envp = getenv("SYS_INST")) != NULL) {
2849 			if ((int)strlen(envp) >= ARCH_LENGTH)
2850 				return (NULL);
2851 			else
2852 				(void) strcpy(default_inst, envp);
2853 		} else  {
2854 			i = sysinfo(SI_ARCHITECTURE, default_inst, ARCH_LENGTH);
2855 			if (i < 0 || i > ARCH_LENGTH)
2856 				return (NULL);
2857 		}
2858 	}
2859 	return (default_inst);
2860 }
2861 
2862 /*
2863  * Function: be_run_cmd
2864  * Description:
2865  *	Runs a command in a separate subprocess.  Splits out stdout from stderr
2866  *	and sends each to its own buffer.  Buffers must be pre-allocated and
2867  *	passed in as arguments.  Buffer sizes are also passed in as arguments.
2868  *
2869  *	Notes / caveats:
2870  *	- Command being run is assumed to not have any stdout or stderr
2871  *		redirection.
2872  *	- Commands which emit total stderr output of greater than PIPE_BUF
2873  *		bytes can hang.  For such commands, a different implementation
2874  *		which uses poll(2) must be used.
2875  *	- stdout_buf can be NULL.  In this case, stdout_bufsize is ignored, and
2876  *		the stream which would have gone to it is sent to the bit
2877  *		bucket.
2878  *	- stderr_buf cannot be NULL.
2879  *	- Only subprocess errors are appended to the stderr_buf.  Errors
2880  *		running the command are reported through be_print_err().
2881  *	- Data which would overflow its respective buffer is sent to the bit
2882  *		bucket.
2883  *
2884  * Parameters:
2885  *		command: command to run.  Assumed not to have embedded stdout
2886  *			or stderr redirection.  May have stdin redirection,
2887  *			however.
2888  *		stderr_buf: buffer returning subprocess stderr data.  Errors
2889  *			reported by this function are reported through
2890  *			be_print_err().
2891  *		stderr_bufsize: size of stderr_buf
2892  *		stdout_buf: buffer returning subprocess stdout data.
2893  *		stdout_bufsize: size of stdout_buf
2894  * Returns:
2895  *		BE_SUCCESS - The command ran successfully without returning
2896  *			errors.
2897  *		BE_ERR_EXTCMD
2898  *			- The command could not be run.
2899  *			- The command terminated with error status.
2900  *			- There were errors extracting or returning subprocess
2901  *				data.
2902  *		BE_ERR_NOMEM - The command exceeds the command buffer size.
2903  *		BE_ERR_INVAL - An invalid argument was specified.
2904  * Scope:
2905  *		Semi-private (library wide use only)
2906  */
2907 int
2908 be_run_cmd(char *command, char *stderr_buf, int stderr_bufsize,
2909     char *stdout_buf, int stdout_bufsize)
2910 {
2911 	char *temp_filename = strdup(tmpnam(NULL));
2912 	FILE *stdout_str = NULL;
2913 	FILE *stderr_str = NULL;
2914 	char cmdline[BUFSIZ];
2915 	char oneline[BUFSIZ];
2916 	int exit_status;
2917 	int rval = BE_SUCCESS;
2918 
2919 	if ((command == NULL) || (stderr_buf == NULL) ||
2920 	    (stderr_bufsize <= 0) || (stdout_bufsize <  0) ||
2921 	    ((stdout_buf != NULL) ^ (stdout_bufsize != 0))) {
2922 		return (BE_ERR_INVAL);
2923 }
2924 
2925 	/* Set up command so popen returns stderr, not stdout */
2926 	if (snprintf(cmdline, BUFSIZ, "%s 2> %s", command,
2927 	    temp_filename) >= BUFSIZ) {
2928 		rval = BE_ERR_NOMEM;
2929 		goto cleanup;
2930 	}
2931 
2932 	/* Set up the fifo that will make stderr available. */
2933 	if (mkfifo(temp_filename, 0600) != 0) {
2934 		(void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"),
2935 		    strerror(errno));
2936 		rval = BE_ERR_EXTCMD;
2937 		goto cleanup;
2938 	}
2939 
2940 	if ((stdout_str = popen(cmdline, "r")) == NULL) {
2941 		(void) be_print_err(gettext("be_run_cmd: popen: %s\n"),
2942 		    strerror(errno));
2943 		rval = BE_ERR_EXTCMD;
2944 		goto cleanup;
2945 	}
2946 
2947 	if ((stderr_str = fopen(temp_filename, "r")) == NULL) {
2948 		(void) be_print_err(gettext("be_run_cmd: fopen: %s\n"),
2949 		    strerror(errno));
2950 		(void) pclose(stdout_str);
2951 		rval = BE_ERR_EXTCMD;
2952 		goto cleanup;
2953 	}
2954 
2955 	/* Read stdout first, as it usually outputs more than stderr. */
2956 	oneline[BUFSIZ-1] = '\0';
2957 	while (fgets(oneline, BUFSIZ-1, stdout_str) != NULL) {
2958 		if (stdout_str != NULL) {
2959 			(void) strlcat(stdout_buf, oneline, stdout_bufsize);
2960 		}
2961 	}
2962 
2963 	while (fgets(oneline, BUFSIZ-1, stderr_str) != NULL) {
2964 		(void) strlcat(stderr_buf, oneline, stderr_bufsize);
2965 	}
2966 
2967 	/* Close pipe, get exit status. */
2968 	if ((exit_status = pclose(stdout_str)) == -1) {
2969 		(void) be_print_err(gettext("be_run_cmd: pclose: %s\n"),
2970 		    strerror(errno));
2971 		rval = BE_ERR_EXTCMD;
2972 	} else if (WIFEXITED(exit_status)) {
2973 		exit_status = (int)((char)WEXITSTATUS(exit_status));
2974 		if (exit_status != 0) {
2975 			(void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: "
2976 			    "command terminated with error status: %d\n"),
2977 			    exit_status);
2978 			(void) strlcat(stderr_buf, oneline, stderr_bufsize);
2979 			rval = BE_ERR_EXTCMD;
2980 		}
2981 	} else {
2982 		(void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: command "
2983 		    "terminated on signal: %s\n"),
2984 		    strsignal(WTERMSIG(exit_status)));
2985 		(void) strlcat(stderr_buf, oneline, stderr_bufsize);
2986 		rval = BE_ERR_EXTCMD;
2987 	}
2988 
2989 cleanup:
2990 	(void) unlink(temp_filename);
2991 	(void) free(temp_filename);
2992 
2993 	return (rval);
2994 }
2995 
2996 /* ********************************************************************	*/
2997 /*			Private Functions				*/
2998 /* ******************************************************************** */
2999 
3000 /*
3001  * Function:	update_dataset
3002  * Description:	This function takes a dataset name and replaces the zpool
3003  *		and be_name components of the dataset with the new be_name
3004  *		zpool passed in.
3005  * Parameters:
3006  *		dataset - name of dataset
3007  *		dataset_len - lenth of buffer in which dataset is passed in.
3008  *		be_name - name of new BE name to update to.
3009  *		old_rc_loc - dataset under which the root container dataset
3010  *			for the old BE lives.
3011  *		new_rc_loc - dataset under which the root container dataset
3012  *			for the new BE lives.
3013  * Returns:
3014  *		BE_SUCCESS - Success
3015  *		be_errno_t - Failure
3016  * Scope:
3017  *		Private
3018  */
3019 static int
3020 update_dataset(char *dataset, int dataset_len, char *be_name,
3021     char *old_rc_loc, char *new_rc_loc)
3022 {
3023 	char	*ds = NULL;
3024 	char	*sub_ds = NULL;
3025 
3026 	/* Tear off the BE container dataset */
3027 	if ((ds = be_make_name_from_ds(dataset, old_rc_loc)) == NULL) {
3028 		return (BE_ERR_INVAL);
3029 	}
3030 
3031 	/* Get dataset name relative to BE root, if there is one */
3032 	sub_ds = strchr(ds, '/');
3033 
3034 	/* Generate the BE root dataset name */
3035 	be_make_root_ds(new_rc_loc, be_name, dataset, dataset_len);
3036 
3037 	/* If a subordinate dataset name was found, append it */
3038 	if (sub_ds != NULL)
3039 		(void) strlcat(dataset, sub_ds, dataset_len);
3040 
3041 	free(ds);
3042 	return (BE_SUCCESS);
3043 }
3044 
3045 /*
3046  * Function:	_update_vfstab
3047  * Description:	This function updates a vfstab file to reflect the new
3048  *		root container dataset location and be_name for all
3049  *		entries listed in the be_fs_list_data_t structure passed in.
3050  * Parameters:
3051  *		vfstab - vfstab file to modify
3052  *		be_name - name of BE to update.
3053  *		old_rc_loc - dataset under which the root container dataset
3054  *			of the old BE resides in.
3055  *		new_rc_loc - dataset under which the root container dataset
3056  *			of the new BE resides in.
3057  *		fld - be_fs_list_data_t pointer providing the list of
3058  *			file systems to look for in vfstab.
3059  * Returns:
3060  *		BE_SUCCESS - Success
3061  *		be_errno_t - Failure
3062  * Scope:
3063  *		Private
3064  */
3065 static int
3066 _update_vfstab(char *vfstab, char *be_name, char *old_rc_loc,
3067     char *new_rc_loc, be_fs_list_data_t *fld)
3068 {
3069 	struct vfstab	vp;
3070 	char		*tmp_vfstab = NULL;
3071 	char		comments_buf[BUFSIZ];
3072 	FILE		*comments = NULL;
3073 	FILE		*vfs_ents = NULL;
3074 	FILE		*tfile = NULL;
3075 	struct stat	sb;
3076 	char		dev[MAXPATHLEN];
3077 	char		*c;
3078 	int		fd;
3079 	int		ret = BE_SUCCESS, err = 0;
3080 	int		i;
3081 	int		tmp_vfstab_len = 0;
3082 
3083 	errno = 0;
3084 
3085 	/*
3086 	 * Open vfstab for reading twice.  First is for comments,
3087 	 * second is for actual entries.
3088 	 */
3089 	if ((comments = fopen(vfstab, "r")) == NULL ||
3090 	    (vfs_ents = fopen(vfstab, "r")) == NULL) {
3091 		err = errno;
3092 		be_print_err(gettext("_update_vfstab: "
3093 		    "failed to open vfstab (%s): %s\n"), vfstab,
3094 		    strerror(err));
3095 		ret = errno_to_be_err(err);
3096 		goto cleanup;
3097 	}
3098 
3099 	/* Grab the stats of the original vfstab file */
3100 	if (stat(vfstab, &sb) != 0) {
3101 		err = errno;
3102 		be_print_err(gettext("_update_vfstab: "
3103 		    "failed to stat file %s: %s\n"), vfstab,
3104 		    strerror(err));
3105 		ret = errno_to_be_err(err);
3106 		goto cleanup;
3107 	}
3108 
3109 	/* Create tmp file for modified vfstab */
3110 	if ((tmp_vfstab = (char *)malloc(strlen(vfstab) + 7))
3111 	    == NULL) {
3112 		be_print_err(gettext("_update_vfstab: "
3113 		    "malloc failed\n"));
3114 		ret = BE_ERR_NOMEM;
3115 		goto cleanup;
3116 	}
3117 	tmp_vfstab_len = strlen(vfstab) + 7;
3118 	(void) memset(tmp_vfstab, 0, tmp_vfstab_len);
3119 	(void) strlcpy(tmp_vfstab, vfstab, tmp_vfstab_len);
3120 	(void) strlcat(tmp_vfstab, "XXXXXX", tmp_vfstab_len);
3121 	if ((fd = mkstemp(tmp_vfstab)) == -1) {
3122 		err = errno;
3123 		be_print_err(gettext("_update_vfstab: "
3124 		    "mkstemp failed: %s\n"), strerror(err));
3125 		ret = errno_to_be_err(err);
3126 		goto cleanup;
3127 	}
3128 	if ((tfile = fdopen(fd, "w")) == NULL) {
3129 		err = errno;
3130 		be_print_err(gettext("_update_vfstab: "
3131 		    "could not open file for write\n"));
3132 		(void) close(fd);
3133 		ret = errno_to_be_err(err);
3134 		goto cleanup;
3135 	}
3136 
3137 	while (fgets(comments_buf, BUFSIZ, comments)) {
3138 		for (c = comments_buf; *c != '\0' && isspace(*c); c++)
3139 			;
3140 		if (*c == '\0') {
3141 			continue;
3142 		} else if (*c == '#') {
3143 			/*
3144 			 * If line is a comment line, just put
3145 			 * it through to the tmp vfstab.
3146 			 */
3147 			(void) fputs(comments_buf, tfile);
3148 		} else {
3149 			/*
3150 			 * Else line is a vfstab entry, grab it
3151 			 * into a vfstab struct.
3152 			 */
3153 			if (getvfsent(vfs_ents, &vp) != 0) {
3154 				err = errno;
3155 				be_print_err(gettext("_update_vfstab: "
3156 				    "getvfsent failed: %s\n"), strerror(err));
3157 				ret = errno_to_be_err(err);
3158 				goto cleanup;
3159 			}
3160 
3161 			if (vp.vfs_special == NULL || vp.vfs_mountp == NULL) {
3162 				(void) putvfsent(tfile, &vp);
3163 				continue;
3164 			}
3165 
3166 			/*
3167 			 * If the entry is one of the entries in the list
3168 			 * of file systems to update, modify it's device
3169 			 * field to be correct for this BE.
3170 			 */
3171 			for (i = 0; i < fld->fs_num; i++) {
3172 				if (strcmp(vp.vfs_special, fld->fs_list[i])
3173 				    == 0) {
3174 					/*
3175 					 * Found entry that needs an update.
3176 					 * Replace the root container dataset
3177 					 * location and be_name in the
3178 					 * entry's device.
3179 					 */
3180 					(void) strlcpy(dev, vp.vfs_special,
3181 					    sizeof (dev));
3182 
3183 					if ((ret = update_dataset(dev,
3184 					    sizeof (dev), be_name, old_rc_loc,
3185 					    new_rc_loc)) != 0) {
3186 						be_print_err(
3187 						    gettext("_update_vfstab: "
3188 						    "Failed to update device "
3189 						    "field for vfstab entry "
3190 						    "%s\n"), fld->fs_list[i]);
3191 						goto cleanup;
3192 					}
3193 
3194 					vp.vfs_special = dev;
3195 					break;
3196 				}
3197 			}
3198 
3199 			/* Put entry through to tmp vfstab */
3200 			(void) putvfsent(tfile, &vp);
3201 		}
3202 	}
3203 
3204 	(void) fclose(comments);
3205 	comments = NULL;
3206 	(void) fclose(vfs_ents);
3207 	vfs_ents = NULL;
3208 	(void) fclose(tfile);
3209 	tfile = NULL;
3210 
3211 	/* Copy tmp vfstab into place */
3212 	if (rename(tmp_vfstab, vfstab) != 0) {
3213 		err = errno;
3214 		be_print_err(gettext("_update_vfstab: "
3215 		    "failed to rename file %s to %s: %s\n"), tmp_vfstab,
3216 		    vfstab, strerror(err));
3217 		ret = errno_to_be_err(err);
3218 		goto cleanup;
3219 	}
3220 
3221 	/* Set the perms and ownership of the updated file */
3222 	if (chmod(vfstab, sb.st_mode) != 0) {
3223 		err = errno;
3224 		be_print_err(gettext("_update_vfstab: "
3225 		    "failed to chmod %s: %s\n"), vfstab, strerror(err));
3226 		ret = errno_to_be_err(err);
3227 		goto cleanup;
3228 	}
3229 	if (chown(vfstab, sb.st_uid, sb.st_gid) != 0) {
3230 		err = errno;
3231 		be_print_err(gettext("_update_vfstab: "
3232 		    "failed to chown %s: %s\n"), vfstab, strerror(err));
3233 		ret = errno_to_be_err(err);
3234 		goto cleanup;
3235 	}
3236 
3237 cleanup:
3238 	if (comments != NULL)
3239 		(void) fclose(comments);
3240 	if (vfs_ents != NULL)
3241 		(void) fclose(vfs_ents);
3242 	(void) unlink(tmp_vfstab);
3243 	(void) free(tmp_vfstab);
3244 	if (tfile != NULL)
3245 		(void) fclose(tfile);
3246 
3247 	return (ret);
3248 }
3249 
3250 
3251 /*
3252  * Function:	be_get_auto_name
3253  * Description:	Generate an auto name constructed based on the BE name
3254  *		of the original BE or zone BE being cloned.
3255  * Parameters:
3256  *		obe_name - name of the original BE or zone BE being cloned.
3257  *              container_ds - container dataset for the zone.
3258  *                             Note: if zone_be is false this should be
3259  *                                  NULL.
3260  *		zone_be - flag that indicates if we are operating on a zone BE.
3261  * Returns:
3262  *		Success - pointer to auto generated BE name.  The name
3263  *			is allocated in heap storage so the caller is
3264  *			responsible for free'ing the name.
3265  *		Failure - NULL
3266  * Scope:
3267  *		Private
3268  */
3269 static char *
3270 be_get_auto_name(char *obe_name, char *be_container_ds, boolean_t zone_be)
3271 {
3272 	be_node_list_t	*be_nodes = NULL;
3273 	be_node_list_t	*cur_be = NULL;
3274 	char		auto_be_name[MAXPATHLEN];
3275 	char		base_be_name[MAXPATHLEN];
3276 	char		cur_be_name[MAXPATHLEN];
3277 	char		*num_str = NULL;
3278 	char		*c = NULL;
3279 	int		num = 0;
3280 	int		cur_num = 0;
3281 
3282 	errno = 0;
3283 
3284 	/*
3285 	 * Check if obe_name is already in an auto BE name format.
3286 	 * If it is, then strip off the increment number to get the
3287 	 * base name.
3288 	 */
3289 	(void) strlcpy(base_be_name, obe_name, sizeof (base_be_name));
3290 
3291 	if ((num_str = strrchr(base_be_name, BE_AUTO_NAME_DELIM))
3292 	    != NULL) {
3293 		/* Make sure remaining string is all digits */
3294 		c = num_str + 1;
3295 		while (c[0] != '\0' && isdigit(c[0]))
3296 			c++;
3297 		/*
3298 		 * If we're now at the end of the string strip off the
3299 		 * increment number.
3300 		 */
3301 		if (c[0] == '\0')
3302 			num_str[0] = '\0';
3303 	}
3304 
3305 	if (zone_be) {
3306 		if (be_container_ds == NULL)
3307 			return (NULL);
3308 		if (be_get_zone_be_list(obe_name, be_container_ds,
3309 		    &be_nodes) != BE_SUCCESS) {
3310 			be_print_err(gettext("be_get_auto_name: "
3311 			    "be_get_zone_be_list failed\n"));
3312 			return (NULL);
3313 		}
3314 	} else if (_be_list(NULL, &be_nodes) != BE_SUCCESS) {
3315 		be_print_err(gettext("be_get_auto_name: be_list failed\n"));
3316 		return (NULL);
3317 	}
3318 
3319 	for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
3320 		(void) strlcpy(cur_be_name, cur_be->be_node_name,
3321 		    sizeof (cur_be_name));
3322 
3323 		/* If cur_be_name doesn't match at least base be name, skip. */
3324 		if (strncmp(cur_be_name, base_be_name, strlen(base_be_name))
3325 		    != 0)
3326 			continue;
3327 
3328 		/* Get the string following the base be name */
3329 		num_str = cur_be_name + strlen(base_be_name);
3330 
3331 		/*
3332 		 * If nothing follows the base be name, this cur_be_name
3333 		 * is the BE named with the base be name, skip.
3334 		 */
3335 		if (num_str == NULL || num_str[0] == '\0')
3336 			continue;
3337 
3338 		/*
3339 		 * Remove the name delimiter.  If its not there,
3340 		 * cur_be_name isn't part of this BE name stream, skip.
3341 		 */
3342 		if (num_str[0] == BE_AUTO_NAME_DELIM)
3343 			num_str++;
3344 		else
3345 			continue;
3346 
3347 		/* Make sure remaining string is all digits */
3348 		c = num_str;
3349 		while (c[0] != '\0' && isdigit(c[0]))
3350 			c++;
3351 		if (c[0] != '\0')
3352 			continue;
3353 
3354 		/* Convert the number string to an int */
3355 		cur_num = atoi(num_str);
3356 
3357 		/*
3358 		 * If failed to convert the string, skip it.  If its too
3359 		 * long to be converted to an int, we wouldn't auto generate
3360 		 * this number anyway so there couldn't be a conflict.
3361 		 * We treat it as a manually created BE name.
3362 		 */
3363 		if (cur_num == 0 && errno == EINVAL)
3364 			continue;
3365 
3366 		/*
3367 		 * Compare current number to current max number,
3368 		 * take higher of the two.
3369 		 */
3370 		if (cur_num > num)
3371 			num = cur_num;
3372 	}
3373 
3374 	/*
3375 	 * Store off a copy of 'num' incase we need it later.  If incrementing
3376 	 * 'num' causes it to roll over, this means 'num' is the largest
3377 	 * positive int possible; we'll need it later in the loop to determine
3378 	 * if we've exhausted all possible increment numbers.  We store it in
3379 	 * 'cur_num'.
3380 	 */
3381 	cur_num = num;
3382 
3383 	/* Increment 'num' to get new auto BE name number */
3384 	if (++num <= 0) {
3385 		int ret = 0;
3386 
3387 		/*
3388 		 * Since incrementing 'num' caused it to rollover, start
3389 		 * over at 0 and find the first available number.
3390 		 */
3391 		for (num = 0; num < cur_num; num++) {
3392 
3393 			(void) snprintf(cur_be_name, sizeof (cur_be_name),
3394 			    "%s%c%d", base_be_name, BE_AUTO_NAME_DELIM, num);
3395 
3396 			ret = zpool_iter(g_zfs, be_exists_callback,
3397 			    cur_be_name);
3398 
3399 			if (ret == 0) {
3400 				/*
3401 				 * BE name doesn't exist, break out
3402 				 * to use 'num'.
3403 				 */
3404 				break;
3405 			} else if (ret == 1) {
3406 				/* BE name exists, continue looking */
3407 				continue;
3408 			} else {
3409 				be_print_err(gettext("be_get_auto_name: "
3410 				    "zpool_iter failed: %s\n"),
3411 				    libzfs_error_description(g_zfs));
3412 				be_free_list(be_nodes);
3413 				return (NULL);
3414 			}
3415 		}
3416 
3417 		/*
3418 		 * If 'num' equals 'cur_num', we've exhausted all possible
3419 		 * auto BE names for this base BE name.
3420 		 */
3421 		if (num == cur_num) {
3422 			be_print_err(gettext("be_get_auto_name: "
3423 			    "No more available auto BE names for base "
3424 			    "BE name %s\n"), base_be_name);
3425 			be_free_list(be_nodes);
3426 			return (NULL);
3427 		}
3428 	}
3429 
3430 	be_free_list(be_nodes);
3431 
3432 	/*
3433 	 * Generate string for auto BE name.
3434 	 */
3435 	(void) snprintf(auto_be_name, sizeof (auto_be_name), "%s%c%d",
3436 	    base_be_name, BE_AUTO_NAME_DELIM, num);
3437 
3438 	if ((c = strdup(auto_be_name)) == NULL) {
3439 		be_print_err(gettext("be_get_auto_name: "
3440 		    "memory allocation failed\n"));
3441 		return (NULL);
3442 	}
3443 
3444 	return (c);
3445 }
3446 
3447 /*
3448  * Function:	be_create_menu
3449  * Description:
3450  *		This function is used if no menu.lst file exists. In
3451  *		this case a new file is created and if needed default
3452  *		lines are added to the file.
3453  * Parameters:
3454  *		pool - The name of the pool the menu.lst file is on
3455  *		pool_mntpt - The mountpoint for the pool we're using.
3456  *		menu_file - The name of the file we're creating.
3457  *		menu_fp - A pointer to the file pointer of the file we
3458  *			  created. This is also used to pass back the file
3459  *			  pointer to the newly created file.
3460  *		mode - the original mode used for the failed attempt to
3461  *		       non-existent file.
3462  * Returns:
3463  *		BE_SUCCESS - Success
3464  *		be_errno_t - Failure
3465  * Scope:
3466  *		Private
3467  */
3468 static int
3469 be_create_menu(
3470 	char *pool,
3471 	char *pool_mntpt,
3472 	char *menu_file,
3473 	FILE **menu_fp,
3474 	char *mode)
3475 {
3476 	be_node_list_t	*be_nodes = NULL;
3477 	char add_default_cmd[BUFSIZ];
3478 	char *menu_path = NULL;
3479 	char *be_rpool = NULL;
3480 	char *be_name = NULL;
3481 
3482 	errno = 0;
3483 
3484 	if (menu_file == NULL || menu_fp == NULL || mode == NULL)
3485 		return (BE_ERR_INVAL);
3486 
3487 	menu_path = strdup(menu_file);
3488 	if (menu_path == NULL)
3489 		return (BE_ERR_NOMEM);
3490 
3491 	(void) dirname(menu_path);
3492 	if (*menu_path == '.') {
3493 		free(menu_path);
3494 		return (BE_ERR_BAD_MENU_PATH);
3495 	}
3496 	if (mkdirp(menu_path,
3497 	    S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
3498 	    errno != EEXIST) {
3499 		free(menu_path);
3500 		be_print_err(gettext("be_create_menu: Failed to create the %s "
3501 		    "directory: %s\n"), menu_path, strerror(errno));
3502 		return (errno_to_be_err(errno));
3503 	}
3504 	free(menu_path);
3505 
3506 	/*
3507 	 * Check to see if this system supports grub
3508 	 */
3509 	if (be_has_grub()) {
3510 		char be_run_cmd_errbuf[BUFSIZ];
3511 		/*
3512 		 * The grub menu is missing so we need to create it
3513 		 * and fill in the first few lines.
3514 		 */
3515 		(void) snprintf(add_default_cmd, sizeof (add_default_cmd),
3516 		    "%s add_splash_image_to_grub_menu %s",
3517 		    INST_ICT, pool_mntpt);
3518 		if (be_run_cmd(add_default_cmd, be_run_cmd_errbuf, BUFSIZ,
3519 		    NULL, 0) != BE_SUCCESS) {
3520 			be_print_err(gettext("be_create_menu: "
3521 			    "add_splash_image_to_grub_menu ICT failed.\n"));
3522 			be_print_err(gettext("  Command: \"%s\"\n"),
3523 			    add_default_cmd);
3524 			be_print_err(be_run_cmd_errbuf);
3525 			return (BE_ERR_ADD_SPLASH_ICT);
3526 		}
3527 	} else {
3528 		/*
3529 		 * The menu file doesn't exist so we need to create a
3530 		 * blank file.
3531 		 */
3532 		FILE *temp_fp = fopen(menu_file, "w+");
3533 		if (temp_fp == NULL) {
3534 			*menu_fp = NULL;
3535 			return (errno_to_be_err(errno));
3536 		}
3537 		(void) fclose(temp_fp);
3538 	}
3539 
3540 	/*
3541 	 * Now we need to add all the BE's back into the the file.
3542 	 */
3543 	if (_be_list(NULL, &be_nodes) == BE_SUCCESS) {
3544 		while (be_nodes != NULL) {
3545 			if (strcmp(pool, be_nodes->be_rpool) == 0) {
3546 				(void) be_append_menu(be_nodes->be_node_name,
3547 				    be_nodes->be_rpool, NULL, NULL, NULL);
3548 			}
3549 			if (be_nodes->be_active_on_boot) {
3550 				be_rpool = strdup(be_nodes->be_rpool);
3551 				be_name = strdup(be_nodes->be_node_name);
3552 			}
3553 
3554 			be_nodes = be_nodes->be_next_node;
3555 		}
3556 	}
3557 	be_free_list(be_nodes);
3558 
3559 	/*
3560 	 * Check to see if this system supports grub
3561 	 */
3562 	if (be_has_grub()) {
3563 		int err = be_change_grub_default(be_name, be_rpool);
3564 		if (err != BE_SUCCESS)
3565 			return (err);
3566 	}
3567 	*menu_fp = fopen(menu_file, mode);
3568 	if (*menu_fp == NULL)
3569 		return (errno_to_be_err(errno));
3570 
3571 	return (BE_SUCCESS);
3572 }
3573 
3574 /*
3575  * Function:	be_open_menu
3576  * Description:
3577  *		This function is used it open the menu.lst file. If this
3578  *              file does not exist be_create_menu is called to create it
3579  *              and the open file pointer is returned. If the file does
3580  *              exist it is simply opened using the mode passed in.
3581  * Parameters:
3582  *		pool - The name of the pool the menu.lst file is on
3583  *		pool_mntpt - The mountpoint for the pool we're using.
3584  *			     The mountpoint is used since the mountpoint
3585  *			     name can differ from the pool name.
3586  *		menu_file - The name of the file we're opening.
3587  *		menu_fp - A pointer to the file pointer of the file we're
3588  *			  opening. This is also used to pass back the file
3589  *			  pointer.
3590  *		mode - the original mode to be used for opening the menu.lst
3591  *                     file.
3592  *              create_menu - If this is true and the menu.lst file does not
3593  *                            exist we will attempt to re-create it. However
3594  *                            if it's false the error returned from the fopen
3595  *                            will be returned.
3596  * Returns:
3597  *		BE_SUCCESS - Success
3598  *		be_errno_t - Failure
3599  * Scope:
3600  *		Private
3601  */
3602 static int
3603 be_open_menu(
3604 	char *pool,
3605 	char *pool_mntpt,
3606 	char *menu_file,
3607 	FILE **menu_fp,
3608 	char *mode,
3609 	boolean_t create_menu)
3610 {
3611 	int	err = 0;
3612 	boolean_t	set_print = B_FALSE;
3613 
3614 	*menu_fp = fopen(menu_file, mode);
3615 	err = errno;
3616 	if (*menu_fp == NULL) {
3617 		if (err == ENOENT && create_menu) {
3618 			be_print_err(gettext("be_open_menu: menu.lst "
3619 			    "file %s does not exist,\n"), menu_file);
3620 			if (!do_print) {
3621 				set_print = B_TRUE;
3622 				do_print = B_TRUE;
3623 			}
3624 			be_print_err(gettext("WARNING: menu.lst "
3625 			    "file %s does not exist,\n         generating "
3626 			    "a new menu.lst file\n"), menu_file);
3627 			if (set_print)
3628 				do_print = B_FALSE;
3629 			err = 0;
3630 			if ((err = be_create_menu(pool, pool_mntpt, menu_file,
3631 			    menu_fp, mode)) == ENOENT)
3632 				return (BE_ERR_NO_MENU);
3633 			else if (err != BE_SUCCESS)
3634 				return (err);
3635 			else if (*menu_fp == NULL)
3636 				return (BE_ERR_NO_MENU);
3637 		} else {
3638 			be_print_err(gettext("be_open_menu: failed "
3639 			    "to open menu.lst file %s\n"), menu_file);
3640 			if (err == ENOENT)
3641 				return (BE_ERR_NO_MENU);
3642 			else
3643 				return (errno_to_be_err(err));
3644 		}
3645 	}
3646 	return (BE_SUCCESS);
3647 }
3648