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