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