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