xref: /onnv-gate/usr/src/lib/libbe/common/be_utils.c (revision 13049:bda0decf867b)
113013Sglenn.lagasse@oracle.com /*
213013Sglenn.lagasse@oracle.com  * CDDL HEADER START
313013Sglenn.lagasse@oracle.com  *
413013Sglenn.lagasse@oracle.com  * The contents of this file are subject to the terms of the
513013Sglenn.lagasse@oracle.com  * Common Development and Distribution License (the "License").
613013Sglenn.lagasse@oracle.com  * You may not use this file except in compliance with the License.
713013Sglenn.lagasse@oracle.com  *
813013Sglenn.lagasse@oracle.com  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
913013Sglenn.lagasse@oracle.com  * or http://www.opensolaris.org/os/licensing.
1013013Sglenn.lagasse@oracle.com  * See the License for the specific language governing permissions
1113013Sglenn.lagasse@oracle.com  * and limitations under the License.
1213013Sglenn.lagasse@oracle.com  *
1313013Sglenn.lagasse@oracle.com  * When distributing Covered Code, include this CDDL HEADER in each
1413013Sglenn.lagasse@oracle.com  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1513013Sglenn.lagasse@oracle.com  * If applicable, add the following below this CDDL HEADER, with the
1613013Sglenn.lagasse@oracle.com  * fields enclosed by brackets "[]" replaced with your own identifying
1713013Sglenn.lagasse@oracle.com  * information: Portions Copyright [yyyy] [name of copyright owner]
1813013Sglenn.lagasse@oracle.com  *
1913013Sglenn.lagasse@oracle.com  * CDDL HEADER END
2013013Sglenn.lagasse@oracle.com  */
2113013Sglenn.lagasse@oracle.com 
2213013Sglenn.lagasse@oracle.com /*
2313013Sglenn.lagasse@oracle.com  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2413013Sglenn.lagasse@oracle.com  */
2513013Sglenn.lagasse@oracle.com 
2613013Sglenn.lagasse@oracle.com /*
2713013Sglenn.lagasse@oracle.com  * System includes
2813013Sglenn.lagasse@oracle.com  */
2913013Sglenn.lagasse@oracle.com #include <assert.h>
3013013Sglenn.lagasse@oracle.com #include <errno.h>
3113013Sglenn.lagasse@oracle.com #include <libgen.h>
3213013Sglenn.lagasse@oracle.com #include <libintl.h>
3313013Sglenn.lagasse@oracle.com #include <libnvpair.h>
3413013Sglenn.lagasse@oracle.com #include <libzfs.h>
3513013Sglenn.lagasse@oracle.com #include <libgen.h>
3613013Sglenn.lagasse@oracle.com #include <stdio.h>
3713013Sglenn.lagasse@oracle.com #include <stdlib.h>
3813013Sglenn.lagasse@oracle.com #include <string.h>
3913013Sglenn.lagasse@oracle.com #include <sys/stat.h>
4013013Sglenn.lagasse@oracle.com #include <sys/types.h>
4113013Sglenn.lagasse@oracle.com #include <sys/vfstab.h>
4213013Sglenn.lagasse@oracle.com #include <sys/param.h>
4313013Sglenn.lagasse@oracle.com #include <sys/systeminfo.h>
4413013Sglenn.lagasse@oracle.com #include <ctype.h>
4513013Sglenn.lagasse@oracle.com #include <time.h>
4613013Sglenn.lagasse@oracle.com #include <unistd.h>
4713013Sglenn.lagasse@oracle.com #include <fcntl.h>
4813013Sglenn.lagasse@oracle.com #include <wait.h>
4913013Sglenn.lagasse@oracle.com 
5013013Sglenn.lagasse@oracle.com #include <libbe.h>
5113013Sglenn.lagasse@oracle.com #include <libbe_priv.h>
5213013Sglenn.lagasse@oracle.com 
5313013Sglenn.lagasse@oracle.com #define	INST_ICT "/usr/lib/python2.6/vendor-packages/osol_install/ict.py"
5413013Sglenn.lagasse@oracle.com 
5513013Sglenn.lagasse@oracle.com /* Private function prototypes */
5613013Sglenn.lagasse@oracle.com static int update_dataset(char *, int, char *, char *, char *);
5713013Sglenn.lagasse@oracle.com static int _update_vfstab(char *, char *, char *, char *, be_fs_list_data_t *);
5813013Sglenn.lagasse@oracle.com static int be_open_menu(char *, char *, char *, FILE **, char *, boolean_t);
5913013Sglenn.lagasse@oracle.com static int be_create_menu(char *, char *, char *, FILE **, char *);
6013013Sglenn.lagasse@oracle.com static char *be_get_auto_name(char *, char *, boolean_t);
6113013Sglenn.lagasse@oracle.com 
6213013Sglenn.lagasse@oracle.com /*
6313013Sglenn.lagasse@oracle.com  * Global error printing
6413013Sglenn.lagasse@oracle.com  */
6513013Sglenn.lagasse@oracle.com boolean_t do_print = B_FALSE;
6613013Sglenn.lagasse@oracle.com 
6713013Sglenn.lagasse@oracle.com /*
6813013Sglenn.lagasse@oracle.com  * Private datatypes
6913013Sglenn.lagasse@oracle.com  */
7013013Sglenn.lagasse@oracle.com typedef struct zone_be_name_cb_data {
7113013Sglenn.lagasse@oracle.com 	char *base_be_name;
7213013Sglenn.lagasse@oracle.com 	int num;
7313013Sglenn.lagasse@oracle.com } zone_be_name_cb_data_t;
7413013Sglenn.lagasse@oracle.com 
7513013Sglenn.lagasse@oracle.com /* ********************************************************************	*/
7613013Sglenn.lagasse@oracle.com /*			Public Functions				*/
7713013Sglenn.lagasse@oracle.com /* ******************************************************************** */
7813013Sglenn.lagasse@oracle.com 
7913013Sglenn.lagasse@oracle.com /*
8013013Sglenn.lagasse@oracle.com  * Function:	be_max_avail
8113013Sglenn.lagasse@oracle.com  * Description:	Returns the available size for the zfs dataset passed in.
8213013Sglenn.lagasse@oracle.com  * Parameters:
8313013Sglenn.lagasse@oracle.com  *		dataset - The dataset we want to get the available space for.
8413013Sglenn.lagasse@oracle.com  *		ret - The available size will be returned in this.
8513013Sglenn.lagasse@oracle.com  * Returns:
8613013Sglenn.lagasse@oracle.com  *		The error returned by the zfs get property function.
8713013Sglenn.lagasse@oracle.com  * Scope:
8813013Sglenn.lagasse@oracle.com  *		Public
8913013Sglenn.lagasse@oracle.com  */
9013013Sglenn.lagasse@oracle.com int
be_max_avail(char * dataset,uint64_t * ret)9113013Sglenn.lagasse@oracle.com be_max_avail(char *dataset, uint64_t *ret)
9213013Sglenn.lagasse@oracle.com {
9313013Sglenn.lagasse@oracle.com 	zfs_handle_t *zhp;
9413013Sglenn.lagasse@oracle.com 	int err = 0;
9513013Sglenn.lagasse@oracle.com 
9613013Sglenn.lagasse@oracle.com 	/* Initialize libzfs handle */
9713013Sglenn.lagasse@oracle.com 	if (!be_zfs_init())
9813013Sglenn.lagasse@oracle.com 		return (BE_ERR_INIT);
9913013Sglenn.lagasse@oracle.com 
10013013Sglenn.lagasse@oracle.com 	zhp = zfs_open(g_zfs, dataset, ZFS_TYPE_DATASET);
10113013Sglenn.lagasse@oracle.com 	if (zhp == NULL) {
10213013Sglenn.lagasse@oracle.com 		/*
10313013Sglenn.lagasse@oracle.com 		 * The zfs_open failed return an error
10413013Sglenn.lagasse@oracle.com 		 */
10513013Sglenn.lagasse@oracle.com 		err = zfs_err_to_be_err(g_zfs);
10613013Sglenn.lagasse@oracle.com 	} else {
10713013Sglenn.lagasse@oracle.com 		err = be_maxsize_avail(zhp, ret);
10813013Sglenn.lagasse@oracle.com 	}
10913013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
11013013Sglenn.lagasse@oracle.com 	be_zfs_fini();
11113013Sglenn.lagasse@oracle.com 	return (err);
11213013Sglenn.lagasse@oracle.com }
11313013Sglenn.lagasse@oracle.com 
11413013Sglenn.lagasse@oracle.com /*
11513013Sglenn.lagasse@oracle.com  * Function:	libbe_print_errors
11613013Sglenn.lagasse@oracle.com  * Description:	Turns on/off error output for the library.
11713013Sglenn.lagasse@oracle.com  * Parameter:
11813013Sglenn.lagasse@oracle.com  *		set_do_print - Boolean that turns library error
11913013Sglenn.lagasse@oracle.com  *			       printing on or off.
12013013Sglenn.lagasse@oracle.com  * Returns:
12113013Sglenn.lagasse@oracle.com  *		None
12213013Sglenn.lagasse@oracle.com  * Scope:
12313013Sglenn.lagasse@oracle.com  *		Public;
12413013Sglenn.lagasse@oracle.com  */
12513013Sglenn.lagasse@oracle.com void
libbe_print_errors(boolean_t set_do_print)12613013Sglenn.lagasse@oracle.com libbe_print_errors(boolean_t set_do_print)
12713013Sglenn.lagasse@oracle.com {
12813013Sglenn.lagasse@oracle.com 	do_print = set_do_print;
12913013Sglenn.lagasse@oracle.com }
13013013Sglenn.lagasse@oracle.com 
13113013Sglenn.lagasse@oracle.com /* ********************************************************************	*/
13213013Sglenn.lagasse@oracle.com /*			Semi-Private Functions				*/
13313013Sglenn.lagasse@oracle.com /* ******************************************************************** */
13413013Sglenn.lagasse@oracle.com 
13513013Sglenn.lagasse@oracle.com /*
13613013Sglenn.lagasse@oracle.com  * Function:	be_zfs_init
13713013Sglenn.lagasse@oracle.com  * Description:	Initializes the libary global libzfs handle.
13813013Sglenn.lagasse@oracle.com  * Parameters:
13913013Sglenn.lagasse@oracle.com  *		None
14013013Sglenn.lagasse@oracle.com  * Returns:
14113013Sglenn.lagasse@oracle.com  *		B_TRUE - Success
14213013Sglenn.lagasse@oracle.com  *		B_FALSE - Failure
14313013Sglenn.lagasse@oracle.com  * Scope:
14413013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
14513013Sglenn.lagasse@oracle.com  */
14613013Sglenn.lagasse@oracle.com boolean_t
be_zfs_init(void)14713013Sglenn.lagasse@oracle.com be_zfs_init(void)
14813013Sglenn.lagasse@oracle.com {
14913013Sglenn.lagasse@oracle.com 	be_zfs_fini();
15013013Sglenn.lagasse@oracle.com 
15113013Sglenn.lagasse@oracle.com 	if ((g_zfs = libzfs_init()) == NULL) {
15213013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_zfs_init: failed to initialize ZFS "
15313013Sglenn.lagasse@oracle.com 		    "library\n"));
15413013Sglenn.lagasse@oracle.com 		return (B_FALSE);
15513013Sglenn.lagasse@oracle.com 	}
15613013Sglenn.lagasse@oracle.com 
15713013Sglenn.lagasse@oracle.com 	return (B_TRUE);
15813013Sglenn.lagasse@oracle.com }
15913013Sglenn.lagasse@oracle.com 
16013013Sglenn.lagasse@oracle.com /*
16113013Sglenn.lagasse@oracle.com  * Function:	be_zfs_fini
16213013Sglenn.lagasse@oracle.com  * Description:	Closes the library global libzfs handle if it currently open.
16313013Sglenn.lagasse@oracle.com  * Parameter:
16413013Sglenn.lagasse@oracle.com  *		None
16513013Sglenn.lagasse@oracle.com  * Returns:
16613013Sglenn.lagasse@oracle.com  *		None
16713013Sglenn.lagasse@oracle.com  * Scope:
16813013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
16913013Sglenn.lagasse@oracle.com  */
17013013Sglenn.lagasse@oracle.com void
be_zfs_fini(void)17113013Sglenn.lagasse@oracle.com be_zfs_fini(void)
17213013Sglenn.lagasse@oracle.com {
17313013Sglenn.lagasse@oracle.com 	if (g_zfs)
17413013Sglenn.lagasse@oracle.com 		libzfs_fini(g_zfs);
17513013Sglenn.lagasse@oracle.com 
17613013Sglenn.lagasse@oracle.com 	g_zfs = NULL;
17713013Sglenn.lagasse@oracle.com }
17813013Sglenn.lagasse@oracle.com 
17913013Sglenn.lagasse@oracle.com /*
18013013Sglenn.lagasse@oracle.com  * Function:	be_make_root_ds
18113013Sglenn.lagasse@oracle.com  * Description:	Generate string for BE's root dataset given the pool
18213013Sglenn.lagasse@oracle.com  *		it lives in and the BE name.
18313013Sglenn.lagasse@oracle.com  * Parameters:
18413013Sglenn.lagasse@oracle.com  *		zpool - pointer zpool name.
18513013Sglenn.lagasse@oracle.com  *		be_name - pointer to BE name.
18613013Sglenn.lagasse@oracle.com  *		be_root_ds - pointer to buffer to return BE root dataset in.
18713013Sglenn.lagasse@oracle.com  *		be_root_ds_size - size of be_root_ds
18813013Sglenn.lagasse@oracle.com  * Returns:
18913013Sglenn.lagasse@oracle.com  *		None
19013013Sglenn.lagasse@oracle.com  * Scope:
19113013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
19213013Sglenn.lagasse@oracle.com  */
19313013Sglenn.lagasse@oracle.com void
be_make_root_ds(const char * zpool,const char * be_name,char * be_root_ds,int be_root_ds_size)19413013Sglenn.lagasse@oracle.com be_make_root_ds(const char *zpool, const char *be_name, char *be_root_ds,
19513013Sglenn.lagasse@oracle.com     int be_root_ds_size)
19613013Sglenn.lagasse@oracle.com {
19713013Sglenn.lagasse@oracle.com 	(void) snprintf(be_root_ds, be_root_ds_size, "%s/%s/%s", zpool,
19813013Sglenn.lagasse@oracle.com 	    BE_CONTAINER_DS_NAME, be_name);
19913013Sglenn.lagasse@oracle.com }
20013013Sglenn.lagasse@oracle.com 
20113013Sglenn.lagasse@oracle.com /*
20213013Sglenn.lagasse@oracle.com  * Function:	be_make_container_ds
20313013Sglenn.lagasse@oracle.com  * Description:	Generate string for the BE container dataset given a pool name.
20413013Sglenn.lagasse@oracle.com  * Parameters:
20513013Sglenn.lagasse@oracle.com  *		zpool - pointer zpool name.
20613013Sglenn.lagasse@oracle.com  *		container_ds - pointer to buffer to return BE container
20713013Sglenn.lagasse@oracle.com  *			dataset in.
20813013Sglenn.lagasse@oracle.com  *		container_ds_size - size of container_ds
20913013Sglenn.lagasse@oracle.com  * Returns:
21013013Sglenn.lagasse@oracle.com  *		None
21113013Sglenn.lagasse@oracle.com  * Scope:
21213013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
21313013Sglenn.lagasse@oracle.com  */
21413013Sglenn.lagasse@oracle.com void
be_make_container_ds(const char * zpool,char * container_ds,int container_ds_size)21513013Sglenn.lagasse@oracle.com be_make_container_ds(const char *zpool,  char *container_ds,
21613013Sglenn.lagasse@oracle.com     int container_ds_size)
21713013Sglenn.lagasse@oracle.com {
21813013Sglenn.lagasse@oracle.com 	(void) snprintf(container_ds, container_ds_size, "%s/%s", zpool,
21913013Sglenn.lagasse@oracle.com 	    BE_CONTAINER_DS_NAME);
22013013Sglenn.lagasse@oracle.com }
22113013Sglenn.lagasse@oracle.com 
22213013Sglenn.lagasse@oracle.com /*
22313013Sglenn.lagasse@oracle.com  * Function:	be_make_name_from_ds
22413013Sglenn.lagasse@oracle.com  * Description:	This function takes a dataset name and strips off the
22513013Sglenn.lagasse@oracle.com  *		BE container dataset portion from the beginning.  The
22613013Sglenn.lagasse@oracle.com  *		returned name is allocated in heap storage, so the caller
22713013Sglenn.lagasse@oracle.com  *		is responsible for freeing it.
22813013Sglenn.lagasse@oracle.com  * Parameters:
22913013Sglenn.lagasse@oracle.com  *		dataset - dataset to get name from.
23013013Sglenn.lagasse@oracle.com  *		rc_loc - dataset underwhich the root container dataset lives.
23113013Sglenn.lagasse@oracle.com  * Returns:
23213013Sglenn.lagasse@oracle.com  *		name of dataset relative to BE container dataset.
23313013Sglenn.lagasse@oracle.com  *		NULL if dataset is not under a BE root dataset.
23413013Sglenn.lagasse@oracle.com  * Scope:
23513013Sglenn.lagasse@oracle.com  *		Semi-primate (library wide use only)
23613013Sglenn.lagasse@oracle.com  */
23713013Sglenn.lagasse@oracle.com char *
be_make_name_from_ds(const char * dataset,char * rc_loc)23813013Sglenn.lagasse@oracle.com be_make_name_from_ds(const char *dataset, char *rc_loc)
23913013Sglenn.lagasse@oracle.com {
24013013Sglenn.lagasse@oracle.com 	char	ds[ZFS_MAXNAMELEN];
24113013Sglenn.lagasse@oracle.com 	char	*tok = NULL;
24213013Sglenn.lagasse@oracle.com 	char	*name = NULL;
24313013Sglenn.lagasse@oracle.com 
24413013Sglenn.lagasse@oracle.com 	/*
24513013Sglenn.lagasse@oracle.com 	 * First token is the location of where the root container dataset
24613013Sglenn.lagasse@oracle.com 	 * lives; it must match rc_loc.
24713013Sglenn.lagasse@oracle.com 	 */
24813013Sglenn.lagasse@oracle.com 	if (strncmp(dataset, rc_loc, strlen(rc_loc)) == 0 &&
24913013Sglenn.lagasse@oracle.com 	    dataset[strlen(rc_loc)] == '/') {
25013013Sglenn.lagasse@oracle.com 		(void) strlcpy(ds, dataset + strlen(rc_loc) + 1, sizeof (ds));
25113013Sglenn.lagasse@oracle.com 	} else {
25213013Sglenn.lagasse@oracle.com 		return (NULL);
25313013Sglenn.lagasse@oracle.com 	}
25413013Sglenn.lagasse@oracle.com 
25513013Sglenn.lagasse@oracle.com 	/* Second token must be BE container dataset name */
25613013Sglenn.lagasse@oracle.com 	if ((tok = strtok(ds, "/")) == NULL ||
25713013Sglenn.lagasse@oracle.com 	    strcmp(tok, BE_CONTAINER_DS_NAME) != 0)
25813013Sglenn.lagasse@oracle.com 		return (NULL);
25913013Sglenn.lagasse@oracle.com 
26013013Sglenn.lagasse@oracle.com 	/* Return the remaining token if one exists */
26113013Sglenn.lagasse@oracle.com 	if ((tok = strtok(NULL, "")) == NULL)
26213013Sglenn.lagasse@oracle.com 		return (NULL);
26313013Sglenn.lagasse@oracle.com 
26413013Sglenn.lagasse@oracle.com 	if ((name = strdup(tok)) == NULL) {
26513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_make_name_from_ds: "
26613013Sglenn.lagasse@oracle.com 		    "memory allocation failed\n"));
26713013Sglenn.lagasse@oracle.com 		return (NULL);
26813013Sglenn.lagasse@oracle.com 	}
26913013Sglenn.lagasse@oracle.com 
27013013Sglenn.lagasse@oracle.com 	return (name);
27113013Sglenn.lagasse@oracle.com }
27213013Sglenn.lagasse@oracle.com 
27313013Sglenn.lagasse@oracle.com /*
27413013Sglenn.lagasse@oracle.com  * Function:	be_maxsize_avail
27513013Sglenn.lagasse@oracle.com  * Description:	Returns the available size for the zfs handle passed in.
27613013Sglenn.lagasse@oracle.com  * Parameters:
27713013Sglenn.lagasse@oracle.com  *		zhp - A pointer to the open zfs handle.
27813013Sglenn.lagasse@oracle.com  *		ret - The available size will be returned in this.
27913013Sglenn.lagasse@oracle.com  * Returns:
28013013Sglenn.lagasse@oracle.com  *		The error returned by the zfs get property function.
28113013Sglenn.lagasse@oracle.com  * Scope:
28213013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
28313013Sglenn.lagasse@oracle.com  */
28413013Sglenn.lagasse@oracle.com int
be_maxsize_avail(zfs_handle_t * zhp,uint64_t * ret)28513013Sglenn.lagasse@oracle.com be_maxsize_avail(zfs_handle_t *zhp, uint64_t *ret)
28613013Sglenn.lagasse@oracle.com {
28713013Sglenn.lagasse@oracle.com 	return ((*ret = zfs_prop_get_int(zhp, ZFS_PROP_AVAILABLE)));
28813013Sglenn.lagasse@oracle.com }
28913013Sglenn.lagasse@oracle.com 
29013013Sglenn.lagasse@oracle.com /*
29113013Sglenn.lagasse@oracle.com  * Function:	be_append_menu
29213013Sglenn.lagasse@oracle.com  * Description:	Appends an entry for a BE into the menu.lst.
29313013Sglenn.lagasse@oracle.com  * Parameters:
29413013Sglenn.lagasse@oracle.com  *		be_name - pointer to name of BE to add boot menu entry for.
29513013Sglenn.lagasse@oracle.com  *		be_root_pool - pointer to name of pool BE lives in.
29613013Sglenn.lagasse@oracle.com  *		boot_pool - Used if the pool containing the grub menu is
29713013Sglenn.lagasse@oracle.com  *			    different than the one contaiing the BE. This
29813013Sglenn.lagasse@oracle.com  *			    will normally be NULL.
29913013Sglenn.lagasse@oracle.com  *		be_orig_root_ds - The root dataset for the BE. This is
30013013Sglenn.lagasse@oracle.com  *			used to check to see if an entry already exists
30113013Sglenn.lagasse@oracle.com  *			for this BE.
30213013Sglenn.lagasse@oracle.com  *		description - pointer to description of BE to be added in
30313013Sglenn.lagasse@oracle.com  *			the title line for this BEs entry.
30413013Sglenn.lagasse@oracle.com  * Returns:
30513013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
30613013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
30713013Sglenn.lagasse@oracle.com  * Scope:
30813013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
30913013Sglenn.lagasse@oracle.com  */
31013013Sglenn.lagasse@oracle.com int
be_append_menu(char * be_name,char * be_root_pool,char * boot_pool,char * be_orig_root_ds,char * description)31113013Sglenn.lagasse@oracle.com be_append_menu(char *be_name, char *be_root_pool, char *boot_pool,
31213013Sglenn.lagasse@oracle.com     char *be_orig_root_ds, char *description)
31313013Sglenn.lagasse@oracle.com {
31413013Sglenn.lagasse@oracle.com 	zfs_handle_t *zhp = NULL;
31513013Sglenn.lagasse@oracle.com 	char menu_file[MAXPATHLEN];
31613013Sglenn.lagasse@oracle.com 	char be_root_ds[MAXPATHLEN];
31713013Sglenn.lagasse@oracle.com 	char line[BUFSIZ];
31813013Sglenn.lagasse@oracle.com 	char temp_line[BUFSIZ];
31913013Sglenn.lagasse@oracle.com 	char title[MAXPATHLEN];
32013013Sglenn.lagasse@oracle.com 	char *entries[BUFSIZ];
32113013Sglenn.lagasse@oracle.com 	char *tmp_entries[BUFSIZ];
32213013Sglenn.lagasse@oracle.com 	char *pool_mntpnt = NULL;
32313013Sglenn.lagasse@oracle.com 	char *ptmp_mntpnt = NULL;
32413013Sglenn.lagasse@oracle.com 	char *orig_mntpnt = NULL;
32513013Sglenn.lagasse@oracle.com 	boolean_t found_be = B_FALSE;
32613013Sglenn.lagasse@oracle.com 	boolean_t found_orig_be = B_FALSE;
32713013Sglenn.lagasse@oracle.com 	boolean_t found_title = B_FALSE;
32813013Sglenn.lagasse@oracle.com 	boolean_t pool_mounted = B_FALSE;
32913013Sglenn.lagasse@oracle.com 	boolean_t collect_lines = B_FALSE;
33013013Sglenn.lagasse@oracle.com 	FILE *menu_fp = NULL;
33113013Sglenn.lagasse@oracle.com 	int err = 0, ret = BE_SUCCESS;
33213013Sglenn.lagasse@oracle.com 	int i, num_tmp_lines = 0, num_lines = 0;
33313013Sglenn.lagasse@oracle.com 
33413013Sglenn.lagasse@oracle.com 	if (be_name == NULL || be_root_pool == NULL)
33513013Sglenn.lagasse@oracle.com 		return (BE_ERR_INVAL);
33613013Sglenn.lagasse@oracle.com 
33713013Sglenn.lagasse@oracle.com 	if (boot_pool == NULL)
33813013Sglenn.lagasse@oracle.com 		boot_pool = be_root_pool;
33913013Sglenn.lagasse@oracle.com 
34013013Sglenn.lagasse@oracle.com 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
34113013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_append_menu: failed to open "
34213013Sglenn.lagasse@oracle.com 		    "pool dataset for %s: %s\n"), be_root_pool,
34313013Sglenn.lagasse@oracle.com 		    libzfs_error_description(g_zfs));
34413013Sglenn.lagasse@oracle.com 		return (zfs_err_to_be_err(g_zfs));
34513013Sglenn.lagasse@oracle.com 	}
34613013Sglenn.lagasse@oracle.com 
34713013Sglenn.lagasse@oracle.com 	/*
34813013Sglenn.lagasse@oracle.com 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
34913013Sglenn.lagasse@oracle.com 	 * attempt to mount it.
35013013Sglenn.lagasse@oracle.com 	 */
35113013Sglenn.lagasse@oracle.com 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
35213013Sglenn.lagasse@oracle.com 	    &pool_mounted)) != BE_SUCCESS) {
35313013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_append_menu: pool dataset "
35413013Sglenn.lagasse@oracle.com 		    "(%s) could not be mounted\n"), be_root_pool);
35513013Sglenn.lagasse@oracle.com 		ZFS_CLOSE(zhp);
35613013Sglenn.lagasse@oracle.com 		return (ret);
35713013Sglenn.lagasse@oracle.com 	}
35813013Sglenn.lagasse@oracle.com 
35913013Sglenn.lagasse@oracle.com 	/*
36013013Sglenn.lagasse@oracle.com 	 * Get the mountpoint for the root pool dataset.
36113013Sglenn.lagasse@oracle.com 	 */
36213013Sglenn.lagasse@oracle.com 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
36313013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_append_menu: pool "
36413013Sglenn.lagasse@oracle.com 		    "dataset (%s) is not mounted. Can't set "
36513013Sglenn.lagasse@oracle.com 		    "the default BE in the grub menu.\n"), be_root_pool);
36613013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
36713013Sglenn.lagasse@oracle.com 		goto cleanup;
36813013Sglenn.lagasse@oracle.com 	}
36913013Sglenn.lagasse@oracle.com 
37013013Sglenn.lagasse@oracle.com 	/*
37113013Sglenn.lagasse@oracle.com 	 * Check to see if this system supports grub
37213013Sglenn.lagasse@oracle.com 	 */
37313013Sglenn.lagasse@oracle.com 	if (be_has_grub()) {
37413013Sglenn.lagasse@oracle.com 		(void) snprintf(menu_file, sizeof (menu_file),
37513013Sglenn.lagasse@oracle.com 		    "%s%s", pool_mntpnt, BE_GRUB_MENU);
37613013Sglenn.lagasse@oracle.com 	} else {
37713013Sglenn.lagasse@oracle.com 		(void) snprintf(menu_file, sizeof (menu_file),
37813013Sglenn.lagasse@oracle.com 		    "%s%s", pool_mntpnt, BE_SPARC_MENU);
37913013Sglenn.lagasse@oracle.com 	}
38013013Sglenn.lagasse@oracle.com 
38113013Sglenn.lagasse@oracle.com 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
38213013Sglenn.lagasse@oracle.com 
38313013Sglenn.lagasse@oracle.com 	/*
38413013Sglenn.lagasse@oracle.com 	 * Iterate through menu first to make sure the BE doesn't already
38513013Sglenn.lagasse@oracle.com 	 * have an entry in the menu.
38613013Sglenn.lagasse@oracle.com 	 *
38713013Sglenn.lagasse@oracle.com 	 * Additionally while iterating through the menu, if we have an
38813013Sglenn.lagasse@oracle.com 	 * original root dataset for a BE we're cloning from, we need to keep
38913013Sglenn.lagasse@oracle.com 	 * track of that BE's menu entry. We will then use the lines from
39013013Sglenn.lagasse@oracle.com 	 * that entry to create the entry for the new BE.
39113013Sglenn.lagasse@oracle.com 	 */
39213013Sglenn.lagasse@oracle.com 	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu_file,
39313013Sglenn.lagasse@oracle.com 	    &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
39413013Sglenn.lagasse@oracle.com 		goto cleanup;
39513013Sglenn.lagasse@oracle.com 	} else if (menu_fp == NULL) {
39613013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
39713013Sglenn.lagasse@oracle.com 		goto cleanup;
39813013Sglenn.lagasse@oracle.com 	}
39913013Sglenn.lagasse@oracle.com 
40013013Sglenn.lagasse@oracle.com 	free(pool_mntpnt);
40113013Sglenn.lagasse@oracle.com 	pool_mntpnt = NULL;
40213013Sglenn.lagasse@oracle.com 
40313013Sglenn.lagasse@oracle.com 	while (fgets(line, BUFSIZ, menu_fp)) {
40413013Sglenn.lagasse@oracle.com 		char *tok = NULL;
40513013Sglenn.lagasse@oracle.com 
40613013Sglenn.lagasse@oracle.com 		(void) strlcpy(temp_line, line, BUFSIZ);
40713013Sglenn.lagasse@oracle.com 		tok = strtok(line, BE_WHITE_SPACE);
40813013Sglenn.lagasse@oracle.com 
40913013Sglenn.lagasse@oracle.com 		if (tok == NULL || tok[0] == '#') {
41013013Sglenn.lagasse@oracle.com 			continue;
41113013Sglenn.lagasse@oracle.com 		} else if (strcmp(tok, "title") == 0) {
41213013Sglenn.lagasse@oracle.com 			collect_lines = B_FALSE;
41313013Sglenn.lagasse@oracle.com 			if ((tok = strtok(NULL, "\n")) == NULL)
41413013Sglenn.lagasse@oracle.com 				(void) strlcpy(title, "", sizeof (title));
41513013Sglenn.lagasse@oracle.com 			else
41613013Sglenn.lagasse@oracle.com 				(void) strlcpy(title, tok, sizeof (title));
41713013Sglenn.lagasse@oracle.com 			found_title = B_TRUE;
41813013Sglenn.lagasse@oracle.com 
41913013Sglenn.lagasse@oracle.com 			if (num_tmp_lines != 0) {
42013013Sglenn.lagasse@oracle.com 				for (i = 0; i < num_tmp_lines; i++) {
42113013Sglenn.lagasse@oracle.com 					free(tmp_entries[i]);
42213013Sglenn.lagasse@oracle.com 					tmp_entries[i] = NULL;
42313013Sglenn.lagasse@oracle.com 				}
42413013Sglenn.lagasse@oracle.com 				num_tmp_lines = 0;
42513013Sglenn.lagasse@oracle.com 			}
42613013Sglenn.lagasse@oracle.com 		} else if (strcmp(tok, "bootfs") == 0) {
42713013Sglenn.lagasse@oracle.com 			char *bootfs = strtok(NULL, BE_WHITE_SPACE);
42813013Sglenn.lagasse@oracle.com 			found_title = B_FALSE;
42913013Sglenn.lagasse@oracle.com 			if (bootfs == NULL)
43013013Sglenn.lagasse@oracle.com 				continue;
43113013Sglenn.lagasse@oracle.com 
43213013Sglenn.lagasse@oracle.com 			if (strcmp(bootfs, be_root_ds) == 0) {
43313013Sglenn.lagasse@oracle.com 				found_be = B_TRUE;
43413013Sglenn.lagasse@oracle.com 				break;
43513013Sglenn.lagasse@oracle.com 			}
43613013Sglenn.lagasse@oracle.com 
43713013Sglenn.lagasse@oracle.com 			if (be_orig_root_ds != NULL &&
43813013Sglenn.lagasse@oracle.com 			    strcmp(bootfs, be_orig_root_ds) == 0 &&
43913013Sglenn.lagasse@oracle.com 			    !found_orig_be) {
44013013Sglenn.lagasse@oracle.com 				char str[BUFSIZ];
44113013Sglenn.lagasse@oracle.com 				found_orig_be = B_TRUE;
44213013Sglenn.lagasse@oracle.com 				num_lines = 0;
44313013Sglenn.lagasse@oracle.com 				/*
44413013Sglenn.lagasse@oracle.com 				 * Store the new title line
44513013Sglenn.lagasse@oracle.com 				 */
44613013Sglenn.lagasse@oracle.com 				(void) snprintf(str, BUFSIZ, "title %s\n",
44713013Sglenn.lagasse@oracle.com 				    description ? description : be_name);
44813013Sglenn.lagasse@oracle.com 				entries[num_lines] = strdup(str);
44913013Sglenn.lagasse@oracle.com 				num_lines++;
45013013Sglenn.lagasse@oracle.com 				/*
45113013Sglenn.lagasse@oracle.com 				 * If there are any lines between the title
45213013Sglenn.lagasse@oracle.com 				 * and the bootfs line store these. Also
45313013Sglenn.lagasse@oracle.com 				 * free the temporary lines.
45413013Sglenn.lagasse@oracle.com 				 */
45513013Sglenn.lagasse@oracle.com 				for (i = 0; i < num_tmp_lines; i++) {
45613013Sglenn.lagasse@oracle.com 					entries[num_lines] = tmp_entries[i];
45713013Sglenn.lagasse@oracle.com 					tmp_entries[i] = NULL;
45813013Sglenn.lagasse@oracle.com 					num_lines++;
45913013Sglenn.lagasse@oracle.com 				}
46013013Sglenn.lagasse@oracle.com 				num_tmp_lines = 0;
46113013Sglenn.lagasse@oracle.com 				/*
46213013Sglenn.lagasse@oracle.com 				 * Store the new bootfs line.
46313013Sglenn.lagasse@oracle.com 				 */
46413013Sglenn.lagasse@oracle.com 				(void) snprintf(str, BUFSIZ, "bootfs %s\n",
46513013Sglenn.lagasse@oracle.com 				    be_root_ds);
46613013Sglenn.lagasse@oracle.com 				entries[num_lines] = strdup(str);
46713013Sglenn.lagasse@oracle.com 				num_lines++;
46813013Sglenn.lagasse@oracle.com 				collect_lines = B_TRUE;
46913013Sglenn.lagasse@oracle.com 			}
47013013Sglenn.lagasse@oracle.com 		} else if (found_orig_be && collect_lines) {
47113013Sglenn.lagasse@oracle.com 			/*
47213013Sglenn.lagasse@oracle.com 			 * get the rest of the lines for the original BE and
47313013Sglenn.lagasse@oracle.com 			 * store them.
47413013Sglenn.lagasse@oracle.com 			 */
47513013Sglenn.lagasse@oracle.com 			if (strstr(line, BE_GRUB_COMMENT) != NULL ||
47613013Sglenn.lagasse@oracle.com 			    strstr(line, "BOOTADM") != NULL)
47713013Sglenn.lagasse@oracle.com 				continue;
47813013Sglenn.lagasse@oracle.com 			entries[num_lines] = strdup(temp_line);
47913013Sglenn.lagasse@oracle.com 			num_lines++;
48013013Sglenn.lagasse@oracle.com 		} else if (found_title && !found_orig_be) {
48113013Sglenn.lagasse@oracle.com 			tmp_entries[num_tmp_lines] = strdup(temp_line);
48213013Sglenn.lagasse@oracle.com 			num_tmp_lines++;
48313013Sglenn.lagasse@oracle.com 		}
48413013Sglenn.lagasse@oracle.com 	}
48513013Sglenn.lagasse@oracle.com 
48613013Sglenn.lagasse@oracle.com 	(void) fclose(menu_fp);
48713013Sglenn.lagasse@oracle.com 
48813013Sglenn.lagasse@oracle.com 	if (found_be) {
48913013Sglenn.lagasse@oracle.com 		/*
49013013Sglenn.lagasse@oracle.com 		 * If an entry for this BE was already in the menu, then if
49113013Sglenn.lagasse@oracle.com 		 * that entry's title matches what we would have put in
49213013Sglenn.lagasse@oracle.com 		 * return success.  Otherwise return failure.
49313013Sglenn.lagasse@oracle.com 		 */
49413013Sglenn.lagasse@oracle.com 		char *new_title = description ? description : be_name;
49513013Sglenn.lagasse@oracle.com 
49613013Sglenn.lagasse@oracle.com 		if (strcmp(title, new_title) == 0) {
49713013Sglenn.lagasse@oracle.com 			ret = BE_SUCCESS;
49813013Sglenn.lagasse@oracle.com 			goto cleanup;
49913013Sglenn.lagasse@oracle.com 		} else {
50013013Sglenn.lagasse@oracle.com 			if (be_remove_menu(be_name, be_root_pool,
50113013Sglenn.lagasse@oracle.com 			    boot_pool) != BE_SUCCESS) {
50213013Sglenn.lagasse@oracle.com 				be_print_err(gettext("be_append_menu: "
50313013Sglenn.lagasse@oracle.com 				    "Failed to remove existing unusable "
50413013Sglenn.lagasse@oracle.com 				    "entry '%s' in boot menu.\n"), be_name);
50513013Sglenn.lagasse@oracle.com 				ret = BE_ERR_BE_EXISTS;
50613013Sglenn.lagasse@oracle.com 				goto cleanup;
50713013Sglenn.lagasse@oracle.com 			}
50813013Sglenn.lagasse@oracle.com 		}
50913013Sglenn.lagasse@oracle.com 	}
51013013Sglenn.lagasse@oracle.com 
51113013Sglenn.lagasse@oracle.com 	/* Append BE entry to the end of the file */
51213013Sglenn.lagasse@oracle.com 	menu_fp = fopen(menu_file, "a+");
51313013Sglenn.lagasse@oracle.com 	err = errno;
51413013Sglenn.lagasse@oracle.com 	if (menu_fp == NULL) {
51513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_append_menu: failed "
51613013Sglenn.lagasse@oracle.com 		    "to open menu.lst file %s\n"), menu_file);
51713013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
51813013Sglenn.lagasse@oracle.com 		goto cleanup;
51913013Sglenn.lagasse@oracle.com 	}
52013013Sglenn.lagasse@oracle.com 
52113013Sglenn.lagasse@oracle.com 	if (found_orig_be) {
52213013Sglenn.lagasse@oracle.com 		/*
52313013Sglenn.lagasse@oracle.com 		 * write out all the stored lines
52413013Sglenn.lagasse@oracle.com 		 */
52513013Sglenn.lagasse@oracle.com 		for (i = 0; i < num_lines; i++) {
52613013Sglenn.lagasse@oracle.com 			(void) fprintf(menu_fp, "%s", entries[i]);
52713013Sglenn.lagasse@oracle.com 			free(entries[i]);
52813013Sglenn.lagasse@oracle.com 		}
52913013Sglenn.lagasse@oracle.com 		num_lines = 0;
53013013Sglenn.lagasse@oracle.com 
53113013Sglenn.lagasse@oracle.com 		/*
53213013Sglenn.lagasse@oracle.com 		 * Check to see if this system supports grub
53313013Sglenn.lagasse@oracle.com 		 */
53413013Sglenn.lagasse@oracle.com 		if (be_has_grub())
53513013Sglenn.lagasse@oracle.com 			(void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
53613013Sglenn.lagasse@oracle.com 		ret = BE_SUCCESS;
53713013Sglenn.lagasse@oracle.com 	} else {
53813013Sglenn.lagasse@oracle.com 		(void) fprintf(menu_fp, "title %s\n",
53913013Sglenn.lagasse@oracle.com 		    description ? description : be_name);
54013013Sglenn.lagasse@oracle.com 		(void) fprintf(menu_fp, "bootfs %s\n", be_root_ds);
54113013Sglenn.lagasse@oracle.com 
54213013Sglenn.lagasse@oracle.com 		/*
54313013Sglenn.lagasse@oracle.com 		 * Check to see if this system supports grub
54413013Sglenn.lagasse@oracle.com 		 */
54513013Sglenn.lagasse@oracle.com 		if (be_has_grub()) {
54613013Sglenn.lagasse@oracle.com 			(void) fprintf(menu_fp, "kernel$ "
54713013Sglenn.lagasse@oracle.com 			    "/platform/i86pc/kernel/$ISADIR/unix -B "
54813013Sglenn.lagasse@oracle.com 			    "$ZFS-BOOTFS\n");
54913013Sglenn.lagasse@oracle.com 			(void) fprintf(menu_fp, "module$ "
55013013Sglenn.lagasse@oracle.com 			    "/platform/i86pc/$ISADIR/boot_archive\n");
55113013Sglenn.lagasse@oracle.com 			(void) fprintf(menu_fp, "%s\n", BE_GRUB_COMMENT);
55213013Sglenn.lagasse@oracle.com 		}
55313013Sglenn.lagasse@oracle.com 		ret = BE_SUCCESS;
55413013Sglenn.lagasse@oracle.com 	}
55513013Sglenn.lagasse@oracle.com 	(void) fclose(menu_fp);
55613013Sglenn.lagasse@oracle.com cleanup:
55713013Sglenn.lagasse@oracle.com 	if (pool_mounted) {
55813013Sglenn.lagasse@oracle.com 		int err = BE_SUCCESS;
55913013Sglenn.lagasse@oracle.com 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
56013013Sglenn.lagasse@oracle.com 		if (ret == BE_SUCCESS)
56113013Sglenn.lagasse@oracle.com 			ret = err;
56213013Sglenn.lagasse@oracle.com 		free(orig_mntpnt);
56313013Sglenn.lagasse@oracle.com 		free(ptmp_mntpnt);
56413013Sglenn.lagasse@oracle.com 	}
56513013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
56613013Sglenn.lagasse@oracle.com 	if (num_tmp_lines > 0) {
56713013Sglenn.lagasse@oracle.com 		for (i = 0; i < num_tmp_lines; i++) {
56813013Sglenn.lagasse@oracle.com 			free(tmp_entries[i]);
56913013Sglenn.lagasse@oracle.com 			tmp_entries[i] = NULL;
57013013Sglenn.lagasse@oracle.com 		}
57113013Sglenn.lagasse@oracle.com 	}
57213013Sglenn.lagasse@oracle.com 	if (num_lines > 0) {
57313013Sglenn.lagasse@oracle.com 		for (i = 0; i < num_lines; i++) {
57413013Sglenn.lagasse@oracle.com 			free(entries[i]);
57513013Sglenn.lagasse@oracle.com 			entries[i] = NULL;
57613013Sglenn.lagasse@oracle.com 		}
57713013Sglenn.lagasse@oracle.com 	}
57813013Sglenn.lagasse@oracle.com 	return (ret);
57913013Sglenn.lagasse@oracle.com }
58013013Sglenn.lagasse@oracle.com 
58113013Sglenn.lagasse@oracle.com /*
58213013Sglenn.lagasse@oracle.com  * Function:	be_remove_menu
58313013Sglenn.lagasse@oracle.com  * Description:	Removes a BE's entry from a menu.lst file.
58413013Sglenn.lagasse@oracle.com  * Parameters:
58513013Sglenn.lagasse@oracle.com  *		be_name - the name of BE whose entry is to be removed from
58613013Sglenn.lagasse@oracle.com  *			the menu.lst file.
58713013Sglenn.lagasse@oracle.com  *		be_root_pool - the pool that be_name lives in.
58813013Sglenn.lagasse@oracle.com  *		boot_pool - the pool where the BE is, if different than
58913013Sglenn.lagasse@oracle.com  *			the pool containing the boot menu.  If this is
59013013Sglenn.lagasse@oracle.com  *			NULL it will be set to be_root_pool.
59113013Sglenn.lagasse@oracle.com  * Returns:
59213013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
59313013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
59413013Sglenn.lagasse@oracle.com  * Scope:
59513013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
59613013Sglenn.lagasse@oracle.com  */
59713013Sglenn.lagasse@oracle.com int
be_remove_menu(char * be_name,char * be_root_pool,char * boot_pool)59813013Sglenn.lagasse@oracle.com be_remove_menu(char *be_name, char *be_root_pool, char *boot_pool)
59913013Sglenn.lagasse@oracle.com {
60013013Sglenn.lagasse@oracle.com 	zfs_handle_t	*zhp = NULL;
60113013Sglenn.lagasse@oracle.com 	char		be_root_ds[MAXPATHLEN];
60213013Sglenn.lagasse@oracle.com 	char		**buffer = NULL;
60313013Sglenn.lagasse@oracle.com 	char		menu_buf[BUFSIZ];
60413013Sglenn.lagasse@oracle.com 	char		menu[MAXPATHLEN];
60513013Sglenn.lagasse@oracle.com 	char		*pool_mntpnt = NULL;
60613013Sglenn.lagasse@oracle.com 	char		*ptmp_mntpnt = NULL;
60713013Sglenn.lagasse@oracle.com 	char		*orig_mntpnt = NULL;
60813013Sglenn.lagasse@oracle.com 	char		*tmp_menu = NULL;
60913013Sglenn.lagasse@oracle.com 	FILE		*menu_fp = NULL;
61013013Sglenn.lagasse@oracle.com 	FILE		*tmp_menu_fp = NULL;
61113013Sglenn.lagasse@oracle.com 	struct stat	sb;
61213013Sglenn.lagasse@oracle.com 	int		ret = BE_SUCCESS;
61313013Sglenn.lagasse@oracle.com 	int		i;
61413013Sglenn.lagasse@oracle.com 	int		fd;
61513013Sglenn.lagasse@oracle.com 	int		err = 0;
61613013Sglenn.lagasse@oracle.com 	int		nlines = 0;
61713013Sglenn.lagasse@oracle.com 	int		default_entry = 0;
61813013Sglenn.lagasse@oracle.com 	int		entry_cnt = 0;
61913013Sglenn.lagasse@oracle.com 	int		entry_del = 0;
62013013Sglenn.lagasse@oracle.com 	int		num_entry_del = 0;
62113013Sglenn.lagasse@oracle.com 	int		tmp_menu_len = 0;
62213013Sglenn.lagasse@oracle.com 	boolean_t	write = B_TRUE;
62313013Sglenn.lagasse@oracle.com 	boolean_t	do_buffer = B_FALSE;
62413013Sglenn.lagasse@oracle.com 	boolean_t	pool_mounted = B_FALSE;
62513013Sglenn.lagasse@oracle.com 
62613013Sglenn.lagasse@oracle.com 	if (boot_pool == NULL)
62713013Sglenn.lagasse@oracle.com 		boot_pool = be_root_pool;
62813013Sglenn.lagasse@oracle.com 
62913013Sglenn.lagasse@oracle.com 	/* Get name of BE's root dataset */
63013013Sglenn.lagasse@oracle.com 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
63113013Sglenn.lagasse@oracle.com 
63213013Sglenn.lagasse@oracle.com 	/* Get handle to pool dataset */
63313013Sglenn.lagasse@oracle.com 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
63413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: "
63513013Sglenn.lagasse@oracle.com 		    "failed to open pool dataset for %s: %s"),
63613013Sglenn.lagasse@oracle.com 		    be_root_pool, libzfs_error_description(g_zfs));
63713013Sglenn.lagasse@oracle.com 		return (zfs_err_to_be_err(g_zfs));
63813013Sglenn.lagasse@oracle.com 	}
63913013Sglenn.lagasse@oracle.com 
64013013Sglenn.lagasse@oracle.com 	/*
64113013Sglenn.lagasse@oracle.com 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
64213013Sglenn.lagasse@oracle.com 	 * attempt to mount it.
64313013Sglenn.lagasse@oracle.com 	 */
64413013Sglenn.lagasse@oracle.com 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
64513013Sglenn.lagasse@oracle.com 	    &pool_mounted)) != BE_SUCCESS) {
64613013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: pool dataset "
64713013Sglenn.lagasse@oracle.com 		    "(%s) could not be mounted\n"), be_root_pool);
64813013Sglenn.lagasse@oracle.com 		ZFS_CLOSE(zhp);
64913013Sglenn.lagasse@oracle.com 		return (ret);
65013013Sglenn.lagasse@oracle.com 	}
65113013Sglenn.lagasse@oracle.com 
65213013Sglenn.lagasse@oracle.com 	/*
65313013Sglenn.lagasse@oracle.com 	 * Get the mountpoint for the root pool dataset.
65413013Sglenn.lagasse@oracle.com 	 */
65513013Sglenn.lagasse@oracle.com 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
65613013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: pool "
65713013Sglenn.lagasse@oracle.com 		    "dataset (%s) is not mounted. Can't set "
65813013Sglenn.lagasse@oracle.com 		    "the default BE in the grub menu.\n"), be_root_pool);
65913013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
66013013Sglenn.lagasse@oracle.com 		goto cleanup;
66113013Sglenn.lagasse@oracle.com 	}
66213013Sglenn.lagasse@oracle.com 
66313013Sglenn.lagasse@oracle.com 	/* Get path to boot menu */
66413013Sglenn.lagasse@oracle.com 	(void) strlcpy(menu, pool_mntpnt, sizeof (menu));
66513013Sglenn.lagasse@oracle.com 
66613013Sglenn.lagasse@oracle.com 	/*
66713013Sglenn.lagasse@oracle.com 	 * Check to see if this system supports grub
66813013Sglenn.lagasse@oracle.com 	 */
66913013Sglenn.lagasse@oracle.com 	if (be_has_grub())
67013013Sglenn.lagasse@oracle.com 		(void) strlcat(menu, BE_GRUB_MENU, sizeof (menu));
67113013Sglenn.lagasse@oracle.com 	else
67213013Sglenn.lagasse@oracle.com 		(void) strlcat(menu, BE_SPARC_MENU, sizeof (menu));
67313013Sglenn.lagasse@oracle.com 
67413013Sglenn.lagasse@oracle.com 	/* Get handle to boot menu file */
67513013Sglenn.lagasse@oracle.com 	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu, &menu_fp, "r",
67613013Sglenn.lagasse@oracle.com 	    B_TRUE)) != BE_SUCCESS) {
67713013Sglenn.lagasse@oracle.com 		goto cleanup;
67813013Sglenn.lagasse@oracle.com 	} else if (menu_fp == NULL) {
67913013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
68013013Sglenn.lagasse@oracle.com 		goto cleanup;
68113013Sglenn.lagasse@oracle.com 	}
68213013Sglenn.lagasse@oracle.com 
68313013Sglenn.lagasse@oracle.com 	free(pool_mntpnt);
68413013Sglenn.lagasse@oracle.com 	pool_mntpnt = NULL;
68513013Sglenn.lagasse@oracle.com 
68613013Sglenn.lagasse@oracle.com 	/* Grab the stats of the original menu file */
68713013Sglenn.lagasse@oracle.com 	if (stat(menu, &sb) != 0) {
68813013Sglenn.lagasse@oracle.com 		err = errno;
68913013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: "
69013013Sglenn.lagasse@oracle.com 		    "failed to stat file %s: %s\n"), menu, strerror(err));
69113013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
69213013Sglenn.lagasse@oracle.com 		goto cleanup;
69313013Sglenn.lagasse@oracle.com 	}
69413013Sglenn.lagasse@oracle.com 
69513013Sglenn.lagasse@oracle.com 	/* Create a tmp file for the modified menu.lst */
69613013Sglenn.lagasse@oracle.com 	tmp_menu_len = strlen(menu) + 7;
69713013Sglenn.lagasse@oracle.com 	if ((tmp_menu = (char *)malloc(tmp_menu_len)) == NULL) {
69813013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: malloc failed\n"));
69913013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NOMEM;
70013013Sglenn.lagasse@oracle.com 		goto cleanup;
70113013Sglenn.lagasse@oracle.com 	}
70213013Sglenn.lagasse@oracle.com 	(void) memset(tmp_menu, 0, tmp_menu_len);
70313013Sglenn.lagasse@oracle.com 	(void) strlcpy(tmp_menu, menu, tmp_menu_len);
70413013Sglenn.lagasse@oracle.com 	(void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
70513013Sglenn.lagasse@oracle.com 	if ((fd = mkstemp(tmp_menu)) == -1) {
70613013Sglenn.lagasse@oracle.com 		err = errno;
70713013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: mkstemp failed\n"));
70813013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
70913013Sglenn.lagasse@oracle.com 		free(tmp_menu);
71013013Sglenn.lagasse@oracle.com 		tmp_menu = NULL;
71113013Sglenn.lagasse@oracle.com 		goto cleanup;
71213013Sglenn.lagasse@oracle.com 	}
71313013Sglenn.lagasse@oracle.com 	if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
71413013Sglenn.lagasse@oracle.com 		err = errno;
71513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: "
71613013Sglenn.lagasse@oracle.com 		    "could not open tmp file for write: %s\n"), strerror(err));
71713013Sglenn.lagasse@oracle.com 		(void) close(fd);
71813013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
71913013Sglenn.lagasse@oracle.com 		goto cleanup;
72013013Sglenn.lagasse@oracle.com 	}
72113013Sglenn.lagasse@oracle.com 
72213013Sglenn.lagasse@oracle.com 	while (fgets(menu_buf, BUFSIZ, menu_fp)) {
72313013Sglenn.lagasse@oracle.com 		char tline [BUFSIZ];
72413013Sglenn.lagasse@oracle.com 		char *tok = NULL;
72513013Sglenn.lagasse@oracle.com 
72613013Sglenn.lagasse@oracle.com 		(void) strlcpy(tline, menu_buf, sizeof (tline));
72713013Sglenn.lagasse@oracle.com 
72813013Sglenn.lagasse@oracle.com 		/* Tokenize line */
72913013Sglenn.lagasse@oracle.com 		tok = strtok(tline, BE_WHITE_SPACE);
73013013Sglenn.lagasse@oracle.com 
73113013Sglenn.lagasse@oracle.com 		if (tok == NULL || tok[0] == '#') {
73213013Sglenn.lagasse@oracle.com 			/* Found empty line or comment line */
73313013Sglenn.lagasse@oracle.com 			if (do_buffer) {
73413013Sglenn.lagasse@oracle.com 				/* Buffer this line */
73513013Sglenn.lagasse@oracle.com 				if ((buffer = (char **)realloc(buffer,
73613013Sglenn.lagasse@oracle.com 				    sizeof (char *)*(nlines + 1))) == NULL) {
73713013Sglenn.lagasse@oracle.com 					ret = BE_ERR_NOMEM;
73813013Sglenn.lagasse@oracle.com 					goto cleanup;
73913013Sglenn.lagasse@oracle.com 				}
74013013Sglenn.lagasse@oracle.com 				if ((buffer[nlines++] = strdup(menu_buf))
74113013Sglenn.lagasse@oracle.com 				    == NULL) {
74213013Sglenn.lagasse@oracle.com 					ret = BE_ERR_NOMEM;
74313013Sglenn.lagasse@oracle.com 					goto cleanup;
74413013Sglenn.lagasse@oracle.com 				}
74513013Sglenn.lagasse@oracle.com 
74613013Sglenn.lagasse@oracle.com 			} else if (write || strncmp(menu_buf, BE_GRUB_COMMENT,
74713013Sglenn.lagasse@oracle.com 			    strlen(BE_GRUB_COMMENT)) != 0) {
74813013Sglenn.lagasse@oracle.com 				/* Write this line out */
74913013Sglenn.lagasse@oracle.com 				(void) fputs(menu_buf, tmp_menu_fp);
75013013Sglenn.lagasse@oracle.com 			}
75113013Sglenn.lagasse@oracle.com 		} else if (strcmp(tok, "default") == 0) {
75213013Sglenn.lagasse@oracle.com 			/*
75313013Sglenn.lagasse@oracle.com 			 * Record what 'default' is set to because we might
75413013Sglenn.lagasse@oracle.com 			 * need to adjust this upon deleting an entry.
75513013Sglenn.lagasse@oracle.com 			 */
75613013Sglenn.lagasse@oracle.com 			tok = strtok(NULL, BE_WHITE_SPACE);
75713013Sglenn.lagasse@oracle.com 
75813013Sglenn.lagasse@oracle.com 			if (tok != NULL) {
75913013Sglenn.lagasse@oracle.com 				default_entry = atoi(tok);
76013013Sglenn.lagasse@oracle.com 			}
76113013Sglenn.lagasse@oracle.com 
76213013Sglenn.lagasse@oracle.com 			(void) fputs(menu_buf, tmp_menu_fp);
76313013Sglenn.lagasse@oracle.com 		} else if (strcmp(tok, "title") == 0) {
76413013Sglenn.lagasse@oracle.com 			/*
76513013Sglenn.lagasse@oracle.com 			 * If we've reached a 'title' line and do_buffer is
76613013Sglenn.lagasse@oracle.com 			 * is true, that means we've just buffered an entire
76713013Sglenn.lagasse@oracle.com 			 * entry without finding a 'bootfs' directive.  We
76813013Sglenn.lagasse@oracle.com 			 * need to write that entry out and keep searching.
76913013Sglenn.lagasse@oracle.com 			 */
77013013Sglenn.lagasse@oracle.com 			if (do_buffer) {
77113013Sglenn.lagasse@oracle.com 				for (i = 0; i < nlines; i++) {
77213013Sglenn.lagasse@oracle.com 					(void) fputs(buffer[i], tmp_menu_fp);
77313013Sglenn.lagasse@oracle.com 					free(buffer[i]);
77413013Sglenn.lagasse@oracle.com 				}
77513013Sglenn.lagasse@oracle.com 				free(buffer);
77613013Sglenn.lagasse@oracle.com 				buffer = NULL;
77713013Sglenn.lagasse@oracle.com 				nlines = 0;
77813013Sglenn.lagasse@oracle.com 			}
77913013Sglenn.lagasse@oracle.com 
78013013Sglenn.lagasse@oracle.com 			/*
78113013Sglenn.lagasse@oracle.com 			 * Turn writing off and buffering on, and increment
78213013Sglenn.lagasse@oracle.com 			 * our entry counter.
78313013Sglenn.lagasse@oracle.com 			 */
78413013Sglenn.lagasse@oracle.com 			write = B_FALSE;
78513013Sglenn.lagasse@oracle.com 			do_buffer = B_TRUE;
78613013Sglenn.lagasse@oracle.com 			entry_cnt++;
78713013Sglenn.lagasse@oracle.com 
78813013Sglenn.lagasse@oracle.com 			/* Buffer this 'title' line */
78913013Sglenn.lagasse@oracle.com 			if ((buffer = (char **)realloc(buffer,
79013013Sglenn.lagasse@oracle.com 			    sizeof (char *)*(nlines + 1))) == NULL) {
79113013Sglenn.lagasse@oracle.com 				ret = BE_ERR_NOMEM;
79213013Sglenn.lagasse@oracle.com 				goto cleanup;
79313013Sglenn.lagasse@oracle.com 			}
79413013Sglenn.lagasse@oracle.com 			if ((buffer[nlines++] = strdup(menu_buf)) == NULL) {
79513013Sglenn.lagasse@oracle.com 				ret = BE_ERR_NOMEM;
79613013Sglenn.lagasse@oracle.com 				goto cleanup;
79713013Sglenn.lagasse@oracle.com 			}
79813013Sglenn.lagasse@oracle.com 
79913013Sglenn.lagasse@oracle.com 		} else if (strcmp(tok, "bootfs") == 0) {
80013013Sglenn.lagasse@oracle.com 			char *bootfs = NULL;
80113013Sglenn.lagasse@oracle.com 
80213013Sglenn.lagasse@oracle.com 			/*
80313013Sglenn.lagasse@oracle.com 			 * Found a 'bootfs' line.  See if it matches the
80413013Sglenn.lagasse@oracle.com 			 * BE we're looking for.
80513013Sglenn.lagasse@oracle.com 			 */
80613013Sglenn.lagasse@oracle.com 			if ((bootfs = strtok(NULL, BE_WHITE_SPACE)) == NULL ||
80713013Sglenn.lagasse@oracle.com 			    strcmp(bootfs, be_root_ds) != 0) {
80813013Sglenn.lagasse@oracle.com 				/*
80913013Sglenn.lagasse@oracle.com 				 * Either there's nothing after the 'bootfs'
81013013Sglenn.lagasse@oracle.com 				 * or this is not the BE we're looking for,
81113013Sglenn.lagasse@oracle.com 				 * write out the line(s) we've buffered since
81213013Sglenn.lagasse@oracle.com 				 * finding the title.
81313013Sglenn.lagasse@oracle.com 				 */
81413013Sglenn.lagasse@oracle.com 				for (i = 0; i < nlines; i++) {
81513013Sglenn.lagasse@oracle.com 					(void) fputs(buffer[i], tmp_menu_fp);
81613013Sglenn.lagasse@oracle.com 					free(buffer[i]);
81713013Sglenn.lagasse@oracle.com 				}
81813013Sglenn.lagasse@oracle.com 				free(buffer);
81913013Sglenn.lagasse@oracle.com 				buffer = NULL;
82013013Sglenn.lagasse@oracle.com 				nlines = 0;
82113013Sglenn.lagasse@oracle.com 
82213013Sglenn.lagasse@oracle.com 				/*
82313013Sglenn.lagasse@oracle.com 				 * Turn writing back on, and turn off buffering
82413013Sglenn.lagasse@oracle.com 				 * since this isn't the entry we're looking
82513013Sglenn.lagasse@oracle.com 				 * for.
82613013Sglenn.lagasse@oracle.com 				 */
82713013Sglenn.lagasse@oracle.com 				write = B_TRUE;
82813013Sglenn.lagasse@oracle.com 				do_buffer = B_FALSE;
82913013Sglenn.lagasse@oracle.com 
83013013Sglenn.lagasse@oracle.com 				/* Write this 'bootfs' line out. */
83113013Sglenn.lagasse@oracle.com 				(void) fputs(menu_buf, tmp_menu_fp);
83213013Sglenn.lagasse@oracle.com 			} else {
83313013Sglenn.lagasse@oracle.com 				/*
83413013Sglenn.lagasse@oracle.com 				 * Found the entry we're looking for.
83513013Sglenn.lagasse@oracle.com 				 * Record its entry number, increment the
83613013Sglenn.lagasse@oracle.com 				 * number of entries we've deleted, and turn
83713013Sglenn.lagasse@oracle.com 				 * writing off.  Also, throw away the lines
83813013Sglenn.lagasse@oracle.com 				 * we've buffered for this entry so far, we
83913013Sglenn.lagasse@oracle.com 				 * don't need them.
84013013Sglenn.lagasse@oracle.com 				 */
84113013Sglenn.lagasse@oracle.com 				entry_del = entry_cnt - 1;
84213013Sglenn.lagasse@oracle.com 				num_entry_del++;
84313013Sglenn.lagasse@oracle.com 				write = B_FALSE;
84413013Sglenn.lagasse@oracle.com 				do_buffer = B_FALSE;
84513013Sglenn.lagasse@oracle.com 
84613013Sglenn.lagasse@oracle.com 				for (i = 0; i < nlines; i++) {
84713013Sglenn.lagasse@oracle.com 					free(buffer[i]);
84813013Sglenn.lagasse@oracle.com 				}
84913013Sglenn.lagasse@oracle.com 				free(buffer);
85013013Sglenn.lagasse@oracle.com 				buffer = NULL;
85113013Sglenn.lagasse@oracle.com 				nlines = 0;
85213013Sglenn.lagasse@oracle.com 			}
85313013Sglenn.lagasse@oracle.com 		} else {
85413013Sglenn.lagasse@oracle.com 			if (do_buffer) {
85513013Sglenn.lagasse@oracle.com 				/* Buffer this line */
85613013Sglenn.lagasse@oracle.com 				if ((buffer = (char **)realloc(buffer,
85713013Sglenn.lagasse@oracle.com 				    sizeof (char *)*(nlines + 1))) == NULL) {
85813013Sglenn.lagasse@oracle.com 					ret = BE_ERR_NOMEM;
85913013Sglenn.lagasse@oracle.com 					goto cleanup;
86013013Sglenn.lagasse@oracle.com 				}
86113013Sglenn.lagasse@oracle.com 				if ((buffer[nlines++] = strdup(menu_buf))
86213013Sglenn.lagasse@oracle.com 				    == NULL) {
86313013Sglenn.lagasse@oracle.com 					ret = BE_ERR_NOMEM;
86413013Sglenn.lagasse@oracle.com 					goto cleanup;
86513013Sglenn.lagasse@oracle.com 				}
86613013Sglenn.lagasse@oracle.com 			} else if (write) {
86713013Sglenn.lagasse@oracle.com 				/* Write this line out */
86813013Sglenn.lagasse@oracle.com 				(void) fputs(menu_buf, tmp_menu_fp);
86913013Sglenn.lagasse@oracle.com 			}
87013013Sglenn.lagasse@oracle.com 		}
87113013Sglenn.lagasse@oracle.com 	}
87213013Sglenn.lagasse@oracle.com 
87313013Sglenn.lagasse@oracle.com 	(void) fclose(menu_fp);
87413013Sglenn.lagasse@oracle.com 	menu_fp = NULL;
87513013Sglenn.lagasse@oracle.com 	(void) fclose(tmp_menu_fp);
87613013Sglenn.lagasse@oracle.com 	tmp_menu_fp = NULL;
87713013Sglenn.lagasse@oracle.com 
87813013Sglenn.lagasse@oracle.com 	/* Copy the modified menu.lst into place */
87913013Sglenn.lagasse@oracle.com 	if (rename(tmp_menu, menu) != 0) {
88013013Sglenn.lagasse@oracle.com 		err = errno;
88113013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: "
88213013Sglenn.lagasse@oracle.com 		    "failed to rename file %s to %s: %s\n"),
88313013Sglenn.lagasse@oracle.com 		    tmp_menu, menu, strerror(err));
88413013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
88513013Sglenn.lagasse@oracle.com 		goto cleanup;
88613013Sglenn.lagasse@oracle.com 	}
88713013Sglenn.lagasse@oracle.com 	free(tmp_menu);
88813013Sglenn.lagasse@oracle.com 	tmp_menu = NULL;
88913013Sglenn.lagasse@oracle.com 
89013013Sglenn.lagasse@oracle.com 	/*
89113013Sglenn.lagasse@oracle.com 	 * If we've removed an entry, see if we need to
89213013Sglenn.lagasse@oracle.com 	 * adjust the default value in the menu.lst.  If the
89313013Sglenn.lagasse@oracle.com 	 * entry we've deleted comes before the default entry
89413013Sglenn.lagasse@oracle.com 	 * we need to adjust the default value accordingly.
89513013Sglenn.lagasse@oracle.com 	 *
89613013Sglenn.lagasse@oracle.com 	 * be_has_grub is used here to check to see if this system
89713013Sglenn.lagasse@oracle.com 	 * supports grub.
89813013Sglenn.lagasse@oracle.com 	 */
89913013Sglenn.lagasse@oracle.com 	if (be_has_grub() && num_entry_del > 0) {
90013013Sglenn.lagasse@oracle.com 		if (entry_del <= default_entry) {
90113013Sglenn.lagasse@oracle.com 			default_entry = default_entry - num_entry_del;
90213013Sglenn.lagasse@oracle.com 			if (default_entry < 0)
90313013Sglenn.lagasse@oracle.com 				default_entry = 0;
90413013Sglenn.lagasse@oracle.com 
90513013Sglenn.lagasse@oracle.com 			/*
90613013Sglenn.lagasse@oracle.com 			 * Adjust the default value by rewriting the
90713013Sglenn.lagasse@oracle.com 			 * menu.lst file.  This may be overkill, but to
90813013Sglenn.lagasse@oracle.com 			 * preserve the location of the 'default' entry
90913013Sglenn.lagasse@oracle.com 			 * in the file, we need to do this.
91013013Sglenn.lagasse@oracle.com 			 */
91113013Sglenn.lagasse@oracle.com 
91213013Sglenn.lagasse@oracle.com 			/* Get handle to boot menu file */
91313013Sglenn.lagasse@oracle.com 			if ((menu_fp = fopen(menu, "r")) == NULL) {
91413013Sglenn.lagasse@oracle.com 				err = errno;
91513013Sglenn.lagasse@oracle.com 				be_print_err(gettext("be_remove_menu: "
91613013Sglenn.lagasse@oracle.com 				    "failed to open menu.lst (%s): %s\n"),
91713013Sglenn.lagasse@oracle.com 				    menu, strerror(err));
91813013Sglenn.lagasse@oracle.com 				ret = errno_to_be_err(err);
91913013Sglenn.lagasse@oracle.com 				goto cleanup;
92013013Sglenn.lagasse@oracle.com 			}
92113013Sglenn.lagasse@oracle.com 
92213013Sglenn.lagasse@oracle.com 			/* Create a tmp file for the modified menu.lst */
92313013Sglenn.lagasse@oracle.com 			tmp_menu_len = strlen(menu) + 7;
92413013Sglenn.lagasse@oracle.com 			if ((tmp_menu = (char *)malloc(tmp_menu_len))
92513013Sglenn.lagasse@oracle.com 			    == NULL) {
92613013Sglenn.lagasse@oracle.com 				be_print_err(gettext("be_remove_menu: "
92713013Sglenn.lagasse@oracle.com 				    "malloc failed\n"));
92813013Sglenn.lagasse@oracle.com 				ret = BE_ERR_NOMEM;
92913013Sglenn.lagasse@oracle.com 				goto cleanup;
93013013Sglenn.lagasse@oracle.com 			}
93113013Sglenn.lagasse@oracle.com 			(void) memset(tmp_menu, 0, tmp_menu_len);
93213013Sglenn.lagasse@oracle.com 			(void) strlcpy(tmp_menu, menu, tmp_menu_len);
93313013Sglenn.lagasse@oracle.com 			(void) strlcat(tmp_menu, "XXXXXX", tmp_menu_len);
93413013Sglenn.lagasse@oracle.com 			if ((fd = mkstemp(tmp_menu)) == -1) {
93513013Sglenn.lagasse@oracle.com 				err = errno;
93613013Sglenn.lagasse@oracle.com 				be_print_err(gettext("be_remove_menu: "
93713013Sglenn.lagasse@oracle.com 				    "mkstemp failed: %s\n"), strerror(err));
93813013Sglenn.lagasse@oracle.com 				ret = errno_to_be_err(err);
93913013Sglenn.lagasse@oracle.com 				free(tmp_menu);
94013013Sglenn.lagasse@oracle.com 				tmp_menu = NULL;
94113013Sglenn.lagasse@oracle.com 				goto cleanup;
94213013Sglenn.lagasse@oracle.com 			}
94313013Sglenn.lagasse@oracle.com 			if ((tmp_menu_fp = fdopen(fd, "w")) == NULL) {
94413013Sglenn.lagasse@oracle.com 				err = errno;
94513013Sglenn.lagasse@oracle.com 				be_print_err(gettext("be_remove_menu: "
94613013Sglenn.lagasse@oracle.com 				    "could not open tmp file for write: %s\n"),
94713013Sglenn.lagasse@oracle.com 				    strerror(err));
94813013Sglenn.lagasse@oracle.com 				(void) close(fd);
94913013Sglenn.lagasse@oracle.com 				ret = errno_to_be_err(err);
95013013Sglenn.lagasse@oracle.com 				goto cleanup;
95113013Sglenn.lagasse@oracle.com 			}
95213013Sglenn.lagasse@oracle.com 
95313013Sglenn.lagasse@oracle.com 			while (fgets(menu_buf, BUFSIZ, menu_fp)) {
95413013Sglenn.lagasse@oracle.com 				char tline [BUFSIZ];
95513013Sglenn.lagasse@oracle.com 				char *tok = NULL;
95613013Sglenn.lagasse@oracle.com 
95713013Sglenn.lagasse@oracle.com 				(void) strlcpy(tline, menu_buf, sizeof (tline));
95813013Sglenn.lagasse@oracle.com 
95913013Sglenn.lagasse@oracle.com 				/* Tokenize line */
96013013Sglenn.lagasse@oracle.com 				tok = strtok(tline, BE_WHITE_SPACE);
96113013Sglenn.lagasse@oracle.com 
96213013Sglenn.lagasse@oracle.com 				if (tok == NULL) {
96313013Sglenn.lagasse@oracle.com 					/* Found empty line, write it out */
96413013Sglenn.lagasse@oracle.com 					(void) fputs(menu_buf, tmp_menu_fp);
96513013Sglenn.lagasse@oracle.com 				} else if (strcmp(tok, "default") == 0) {
96613013Sglenn.lagasse@oracle.com 					/* Found the default line, adjust it */
96713013Sglenn.lagasse@oracle.com 					(void) snprintf(tline, sizeof (tline),
96813013Sglenn.lagasse@oracle.com 					    "default %d\n", default_entry);
96913013Sglenn.lagasse@oracle.com 
97013013Sglenn.lagasse@oracle.com 					(void) fputs(tline, tmp_menu_fp);
97113013Sglenn.lagasse@oracle.com 				} else {
97213013Sglenn.lagasse@oracle.com 					/* Pass through all other lines */
97313013Sglenn.lagasse@oracle.com 					(void) fputs(menu_buf, tmp_menu_fp);
97413013Sglenn.lagasse@oracle.com 				}
97513013Sglenn.lagasse@oracle.com 			}
97613013Sglenn.lagasse@oracle.com 
97713013Sglenn.lagasse@oracle.com 			(void) fclose(menu_fp);
97813013Sglenn.lagasse@oracle.com 			menu_fp = NULL;
97913013Sglenn.lagasse@oracle.com 			(void) fclose(tmp_menu_fp);
98013013Sglenn.lagasse@oracle.com 			tmp_menu_fp = NULL;
98113013Sglenn.lagasse@oracle.com 
98213013Sglenn.lagasse@oracle.com 			/* Copy the modified menu.lst into place */
98313013Sglenn.lagasse@oracle.com 			if (rename(tmp_menu, menu) != 0) {
98413013Sglenn.lagasse@oracle.com 				err = errno;
98513013Sglenn.lagasse@oracle.com 				be_print_err(gettext("be_remove_menu: "
98613013Sglenn.lagasse@oracle.com 				    "failed to rename file %s to %s: %s\n"),
98713013Sglenn.lagasse@oracle.com 				    tmp_menu, menu, strerror(err));
98813013Sglenn.lagasse@oracle.com 				ret = errno_to_be_err(err);
98913013Sglenn.lagasse@oracle.com 				goto cleanup;
99013013Sglenn.lagasse@oracle.com 			}
99113013Sglenn.lagasse@oracle.com 
99213013Sglenn.lagasse@oracle.com 			free(tmp_menu);
99313013Sglenn.lagasse@oracle.com 			tmp_menu = NULL;
99413013Sglenn.lagasse@oracle.com 		}
99513013Sglenn.lagasse@oracle.com 	}
99613013Sglenn.lagasse@oracle.com 
99713013Sglenn.lagasse@oracle.com 	/* Set the perms and ownership of the updated file */
99813013Sglenn.lagasse@oracle.com 	if (chmod(menu, sb.st_mode) != 0) {
99913013Sglenn.lagasse@oracle.com 		err = errno;
100013013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: "
100113013Sglenn.lagasse@oracle.com 		    "failed to chmod %s: %s\n"), menu, strerror(err));
100213013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
100313013Sglenn.lagasse@oracle.com 		goto cleanup;
100413013Sglenn.lagasse@oracle.com 	}
100513013Sglenn.lagasse@oracle.com 	if (chown(menu, sb.st_uid, sb.st_gid) != 0) {
100613013Sglenn.lagasse@oracle.com 		err = errno;
100713013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_remove_menu: "
100813013Sglenn.lagasse@oracle.com 		    "failed to chown %s: %s\n"), menu, strerror(err));
100913013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
101013013Sglenn.lagasse@oracle.com 		goto cleanup;
101113013Sglenn.lagasse@oracle.com 	}
101213013Sglenn.lagasse@oracle.com 
101313013Sglenn.lagasse@oracle.com cleanup:
101413013Sglenn.lagasse@oracle.com 	if (pool_mounted) {
101513013Sglenn.lagasse@oracle.com 		int err = BE_SUCCESS;
101613013Sglenn.lagasse@oracle.com 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
101713013Sglenn.lagasse@oracle.com 		if (ret == BE_SUCCESS)
101813013Sglenn.lagasse@oracle.com 			ret = err;
101913013Sglenn.lagasse@oracle.com 		free(orig_mntpnt);
102013013Sglenn.lagasse@oracle.com 		free(ptmp_mntpnt);
102113013Sglenn.lagasse@oracle.com 	}
102213013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
102313013Sglenn.lagasse@oracle.com 
102413013Sglenn.lagasse@oracle.com 	free(buffer);
102513013Sglenn.lagasse@oracle.com 	if (menu_fp != NULL)
102613013Sglenn.lagasse@oracle.com 		(void) fclose(menu_fp);
102713013Sglenn.lagasse@oracle.com 	if (tmp_menu_fp != NULL)
102813013Sglenn.lagasse@oracle.com 		(void) fclose(tmp_menu_fp);
102913013Sglenn.lagasse@oracle.com 	if (tmp_menu != NULL) {
103013013Sglenn.lagasse@oracle.com 		(void) unlink(tmp_menu);
103113013Sglenn.lagasse@oracle.com 		free(tmp_menu);
103213013Sglenn.lagasse@oracle.com 	}
103313013Sglenn.lagasse@oracle.com 
103413013Sglenn.lagasse@oracle.com 	return (ret);
103513013Sglenn.lagasse@oracle.com }
103613013Sglenn.lagasse@oracle.com 
103713013Sglenn.lagasse@oracle.com /*
103813013Sglenn.lagasse@oracle.com  * Function:	be_default_grub_bootfs
103913013Sglenn.lagasse@oracle.com  * Description:	This function returns the dataset in the default entry of
104013013Sglenn.lagasse@oracle.com  *		the grub menu. If no default entry is found with a valid bootfs
104113013Sglenn.lagasse@oracle.com  *		entry NULL is returned.
104213013Sglenn.lagasse@oracle.com  * Parameters:
104313013Sglenn.lagasse@oracle.com  *		be_root_pool - This is the name of the root pool where the
104413013Sglenn.lagasse@oracle.com  *			       grub menu can be found.
104513013Sglenn.lagasse@oracle.com  *              def_bootfs - This is used to pass back the bootfs string. On
104613013Sglenn.lagasse@oracle.com  *				error NULL is returned here.
104713013Sglenn.lagasse@oracle.com  * Returns:
104813013Sglenn.lagasse@oracle.com  *		Success - BE_SUCCESS is returned.
104913013Sglenn.lagasse@oracle.com  *		Failure - a be_errno_t is returned.
105013013Sglenn.lagasse@oracle.com  * Scope:
105113013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
105213013Sglenn.lagasse@oracle.com  */
105313013Sglenn.lagasse@oracle.com int
be_default_grub_bootfs(const char * be_root_pool,char ** def_bootfs)105413013Sglenn.lagasse@oracle.com be_default_grub_bootfs(const char *be_root_pool, char **def_bootfs)
105513013Sglenn.lagasse@oracle.com {
105613013Sglenn.lagasse@oracle.com 	zfs_handle_t	*zhp = NULL;
105713013Sglenn.lagasse@oracle.com 	char		grub_file[MAXPATHLEN];
105813013Sglenn.lagasse@oracle.com 	FILE		*menu_fp;
105913013Sglenn.lagasse@oracle.com 	char		line[BUFSIZ];
106013013Sglenn.lagasse@oracle.com 	char		*pool_mntpnt = NULL;
106113013Sglenn.lagasse@oracle.com 	char		*ptmp_mntpnt = NULL;
106213013Sglenn.lagasse@oracle.com 	char		*orig_mntpnt = NULL;
106313013Sglenn.lagasse@oracle.com 	int		default_entry = 0, entries = 0;
106413013Sglenn.lagasse@oracle.com 	int		found_default = 0;
106513013Sglenn.lagasse@oracle.com 	int		ret = BE_SUCCESS;
106613013Sglenn.lagasse@oracle.com 	boolean_t	pool_mounted = B_FALSE;
106713013Sglenn.lagasse@oracle.com 
106813013Sglenn.lagasse@oracle.com 	errno = 0;
106913013Sglenn.lagasse@oracle.com 
107013013Sglenn.lagasse@oracle.com 	/*
107113013Sglenn.lagasse@oracle.com 	 * Check to see if this system supports grub
107213013Sglenn.lagasse@oracle.com 	 */
107313013Sglenn.lagasse@oracle.com 	if (!be_has_grub()) {
107413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_default_grub_bootfs: operation "
107513013Sglenn.lagasse@oracle.com 		    "not supported on this architecture\n"));
107613013Sglenn.lagasse@oracle.com 		return (BE_ERR_NOTSUP);
107713013Sglenn.lagasse@oracle.com 	}
107813013Sglenn.lagasse@oracle.com 
107913013Sglenn.lagasse@oracle.com 	*def_bootfs = NULL;
108013013Sglenn.lagasse@oracle.com 
108113013Sglenn.lagasse@oracle.com 	/* Get handle to pool dataset */
108213013Sglenn.lagasse@oracle.com 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
108313013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_default_grub_bootfs: "
108413013Sglenn.lagasse@oracle.com 		    "failed to open pool dataset for %s: %s"),
108513013Sglenn.lagasse@oracle.com 		    be_root_pool, libzfs_error_description(g_zfs));
108613013Sglenn.lagasse@oracle.com 		return (zfs_err_to_be_err(g_zfs));
108713013Sglenn.lagasse@oracle.com 	}
108813013Sglenn.lagasse@oracle.com 
108913013Sglenn.lagasse@oracle.com 	/*
109013013Sglenn.lagasse@oracle.com 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
109113013Sglenn.lagasse@oracle.com 	 * attempt to mount it.
109213013Sglenn.lagasse@oracle.com 	 */
109313013Sglenn.lagasse@oracle.com 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
109413013Sglenn.lagasse@oracle.com 	    &pool_mounted)) != BE_SUCCESS) {
109513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_default_grub_bootfs: pool dataset "
109613013Sglenn.lagasse@oracle.com 		    "(%s) could not be mounted\n"), be_root_pool);
109713013Sglenn.lagasse@oracle.com 		ZFS_CLOSE(zhp);
109813013Sglenn.lagasse@oracle.com 		return (ret);
109913013Sglenn.lagasse@oracle.com 	}
110013013Sglenn.lagasse@oracle.com 
110113013Sglenn.lagasse@oracle.com 	/*
110213013Sglenn.lagasse@oracle.com 	 * Get the mountpoint for the root pool dataset.
110313013Sglenn.lagasse@oracle.com 	 */
110413013Sglenn.lagasse@oracle.com 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
110513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_default_grub_bootfs: failed "
110613013Sglenn.lagasse@oracle.com 		    "to get mount point for the root pool. Can't set "
110713013Sglenn.lagasse@oracle.com 		    "the default BE in the grub menu.\n"));
110813013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
110913013Sglenn.lagasse@oracle.com 		goto cleanup;
111013013Sglenn.lagasse@oracle.com 	}
111113013Sglenn.lagasse@oracle.com 
111213013Sglenn.lagasse@oracle.com 	(void) snprintf(grub_file, MAXPATHLEN, "%s%s",
111313013Sglenn.lagasse@oracle.com 	    pool_mntpnt, BE_GRUB_MENU);
111413013Sglenn.lagasse@oracle.com 
111513013Sglenn.lagasse@oracle.com 	if ((ret = be_open_menu((char *)be_root_pool, pool_mntpnt, grub_file,
111613013Sglenn.lagasse@oracle.com 	    &menu_fp, "r", B_FALSE)) != BE_SUCCESS) {
111713013Sglenn.lagasse@oracle.com 		goto cleanup;
111813013Sglenn.lagasse@oracle.com 	} else if (menu_fp == NULL) {
111913013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
112013013Sglenn.lagasse@oracle.com 		goto cleanup;
112113013Sglenn.lagasse@oracle.com 	}
112213013Sglenn.lagasse@oracle.com 
112313013Sglenn.lagasse@oracle.com 	free(pool_mntpnt);
112413013Sglenn.lagasse@oracle.com 	pool_mntpnt = NULL;
112513013Sglenn.lagasse@oracle.com 
112613013Sglenn.lagasse@oracle.com 	while (fgets(line, BUFSIZ, menu_fp)) {
112713013Sglenn.lagasse@oracle.com 		char *tok = strtok(line, BE_WHITE_SPACE);
112813013Sglenn.lagasse@oracle.com 
112913013Sglenn.lagasse@oracle.com 		if (tok != NULL && tok[0] != '#') {
113013013Sglenn.lagasse@oracle.com 			if (!found_default) {
113113013Sglenn.lagasse@oracle.com 				if (strcmp(tok, "default") == 0) {
113213013Sglenn.lagasse@oracle.com 					tok = strtok(NULL, BE_WHITE_SPACE);
113313013Sglenn.lagasse@oracle.com 					if (tok != NULL) {
113413013Sglenn.lagasse@oracle.com 						default_entry = atoi(tok);
113513013Sglenn.lagasse@oracle.com 						rewind(menu_fp);
113613013Sglenn.lagasse@oracle.com 						found_default = 1;
113713013Sglenn.lagasse@oracle.com 					}
113813013Sglenn.lagasse@oracle.com 				}
113913013Sglenn.lagasse@oracle.com 				continue;
114013013Sglenn.lagasse@oracle.com 			}
114113013Sglenn.lagasse@oracle.com 			if (strcmp(tok, "title") == 0) {
114213013Sglenn.lagasse@oracle.com 				entries++;
114313013Sglenn.lagasse@oracle.com 			} else if (default_entry == entries - 1) {
114413013Sglenn.lagasse@oracle.com 				if (strcmp(tok, "bootfs") == 0) {
114513013Sglenn.lagasse@oracle.com 					tok = strtok(NULL, BE_WHITE_SPACE);
114613013Sglenn.lagasse@oracle.com 					(void) fclose(menu_fp);
114713013Sglenn.lagasse@oracle.com 
114813013Sglenn.lagasse@oracle.com 					if (tok == NULL) {
114913013Sglenn.lagasse@oracle.com 						ret = BE_SUCCESS;
115013013Sglenn.lagasse@oracle.com 						goto cleanup;
115113013Sglenn.lagasse@oracle.com 					}
115213013Sglenn.lagasse@oracle.com 
115313013Sglenn.lagasse@oracle.com 					if ((*def_bootfs = strdup(tok)) !=
115413013Sglenn.lagasse@oracle.com 					    NULL) {
115513013Sglenn.lagasse@oracle.com 						ret = BE_SUCCESS;
115613013Sglenn.lagasse@oracle.com 						goto cleanup;
115713013Sglenn.lagasse@oracle.com 					}
115813013Sglenn.lagasse@oracle.com 					be_print_err(gettext(
115913013Sglenn.lagasse@oracle.com 					    "be_default_grub_bootfs: "
116013013Sglenn.lagasse@oracle.com 					    "memory allocation failed\n"));
116113013Sglenn.lagasse@oracle.com 					ret = BE_ERR_NOMEM;
116213013Sglenn.lagasse@oracle.com 					goto cleanup;
116313013Sglenn.lagasse@oracle.com 				}
116413013Sglenn.lagasse@oracle.com 			} else if (default_entry < entries - 1) {
116513013Sglenn.lagasse@oracle.com 				/*
116613013Sglenn.lagasse@oracle.com 				 * no bootfs entry for the default entry.
116713013Sglenn.lagasse@oracle.com 				 */
116813013Sglenn.lagasse@oracle.com 				break;
116913013Sglenn.lagasse@oracle.com 			}
117013013Sglenn.lagasse@oracle.com 		}
117113013Sglenn.lagasse@oracle.com 	}
117213013Sglenn.lagasse@oracle.com 	(void) fclose(menu_fp);
117313013Sglenn.lagasse@oracle.com 
117413013Sglenn.lagasse@oracle.com cleanup:
117513013Sglenn.lagasse@oracle.com 	if (pool_mounted) {
117613013Sglenn.lagasse@oracle.com 		int err = BE_SUCCESS;
117713013Sglenn.lagasse@oracle.com 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
117813013Sglenn.lagasse@oracle.com 		if (ret == BE_SUCCESS)
117913013Sglenn.lagasse@oracle.com 			ret = err;
118013013Sglenn.lagasse@oracle.com 		free(orig_mntpnt);
118113013Sglenn.lagasse@oracle.com 		free(ptmp_mntpnt);
118213013Sglenn.lagasse@oracle.com 	}
118313013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
118413013Sglenn.lagasse@oracle.com 	return (ret);
118513013Sglenn.lagasse@oracle.com }
118613013Sglenn.lagasse@oracle.com 
118713013Sglenn.lagasse@oracle.com /*
118813013Sglenn.lagasse@oracle.com  * Function:	be_change_grub_default
118913013Sglenn.lagasse@oracle.com  * Description:	This function takes two parameters. These are the name of
119013013Sglenn.lagasse@oracle.com  *		the BE we want to have as the default booted in the grub
119113013Sglenn.lagasse@oracle.com  *		menu and the root pool where the path to the grub menu exists.
119213013Sglenn.lagasse@oracle.com  *		The code takes this and finds the BE's entry in the grub menu
119313013Sglenn.lagasse@oracle.com  *		and changes the default entry to point to that entry in the
119413013Sglenn.lagasse@oracle.com  *		list.
119513013Sglenn.lagasse@oracle.com  * Parameters:
119613013Sglenn.lagasse@oracle.com  *		be_name - This is the name of the BE wanted as the default
119713013Sglenn.lagasse@oracle.com  *			for the next boot.
119813013Sglenn.lagasse@oracle.com  *		be_root_pool - This is the name of the root pool where the
119913013Sglenn.lagasse@oracle.com  *			grub menu can be found.
120013013Sglenn.lagasse@oracle.com  * Returns:
120113013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
120213013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
120313013Sglenn.lagasse@oracle.com  * Scope:
120413013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
120513013Sglenn.lagasse@oracle.com  */
120613013Sglenn.lagasse@oracle.com int
be_change_grub_default(char * be_name,char * be_root_pool)120713013Sglenn.lagasse@oracle.com be_change_grub_default(char *be_name, char *be_root_pool)
120813013Sglenn.lagasse@oracle.com {
120913013Sglenn.lagasse@oracle.com 	zfs_handle_t	*zhp = NULL;
121013013Sglenn.lagasse@oracle.com 	char	grub_file[MAXPATHLEN];
121113013Sglenn.lagasse@oracle.com 	char	*temp_grub;
121213013Sglenn.lagasse@oracle.com 	char	*pool_mntpnt = NULL;
121313013Sglenn.lagasse@oracle.com 	char	*ptmp_mntpnt = NULL;
121413013Sglenn.lagasse@oracle.com 	char	*orig_mntpnt = NULL;
121513013Sglenn.lagasse@oracle.com 	char	line[BUFSIZ];
121613013Sglenn.lagasse@oracle.com 	char	temp_line[BUFSIZ];
121713013Sglenn.lagasse@oracle.com 	char	be_root_ds[MAXPATHLEN];
121813013Sglenn.lagasse@oracle.com 	FILE	*grub_fp = NULL;
121913013Sglenn.lagasse@oracle.com 	FILE	*temp_fp = NULL;
122013013Sglenn.lagasse@oracle.com 	struct stat	sb;
122113013Sglenn.lagasse@oracle.com 	int	temp_grub_len = 0;
122213013Sglenn.lagasse@oracle.com 	int	fd, entries = 0;
122313013Sglenn.lagasse@oracle.com 	int	err = 0;
122413013Sglenn.lagasse@oracle.com 	int	ret = BE_SUCCESS;
122513013Sglenn.lagasse@oracle.com 	boolean_t	found_default = B_FALSE;
122613013Sglenn.lagasse@oracle.com 	boolean_t	pool_mounted = B_FALSE;
122713013Sglenn.lagasse@oracle.com 
122813013Sglenn.lagasse@oracle.com 	errno = 0;
122913013Sglenn.lagasse@oracle.com 
123013013Sglenn.lagasse@oracle.com 	/*
123113013Sglenn.lagasse@oracle.com 	 * Check to see if this system supports grub
123213013Sglenn.lagasse@oracle.com 	 */
123313013Sglenn.lagasse@oracle.com 	if (!be_has_grub()) {
123413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: operation "
123513013Sglenn.lagasse@oracle.com 		    "not supported on this architecture\n"));
123613013Sglenn.lagasse@oracle.com 		return (BE_ERR_NOTSUP);
123713013Sglenn.lagasse@oracle.com 	}
123813013Sglenn.lagasse@oracle.com 
123913013Sglenn.lagasse@oracle.com 	/* Generate string for BE's root dataset */
124013013Sglenn.lagasse@oracle.com 	be_make_root_ds(be_root_pool, be_name, be_root_ds, sizeof (be_root_ds));
124113013Sglenn.lagasse@oracle.com 
124213013Sglenn.lagasse@oracle.com 	/* Get handle to pool dataset */
124313013Sglenn.lagasse@oracle.com 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
124413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: "
124513013Sglenn.lagasse@oracle.com 		    "failed to open pool dataset for %s: %s"),
124613013Sglenn.lagasse@oracle.com 		    be_root_pool, libzfs_error_description(g_zfs));
124713013Sglenn.lagasse@oracle.com 		return (zfs_err_to_be_err(g_zfs));
124813013Sglenn.lagasse@oracle.com 	}
124913013Sglenn.lagasse@oracle.com 
125013013Sglenn.lagasse@oracle.com 	/*
125113013Sglenn.lagasse@oracle.com 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
125213013Sglenn.lagasse@oracle.com 	 * attempt to mount it.
125313013Sglenn.lagasse@oracle.com 	 */
125413013Sglenn.lagasse@oracle.com 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
125513013Sglenn.lagasse@oracle.com 	    &pool_mounted)) != BE_SUCCESS) {
125613013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: pool dataset "
125713013Sglenn.lagasse@oracle.com 		    "(%s) could not be mounted\n"), be_root_pool);
125813013Sglenn.lagasse@oracle.com 		ZFS_CLOSE(zhp);
125913013Sglenn.lagasse@oracle.com 		return (ret);
126013013Sglenn.lagasse@oracle.com 	}
126113013Sglenn.lagasse@oracle.com 
126213013Sglenn.lagasse@oracle.com 	/*
126313013Sglenn.lagasse@oracle.com 	 * Get the mountpoint for the root pool dataset.
126413013Sglenn.lagasse@oracle.com 	 */
126513013Sglenn.lagasse@oracle.com 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
126613013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: pool "
126713013Sglenn.lagasse@oracle.com 		    "dataset (%s) is not mounted. Can't set "
126813013Sglenn.lagasse@oracle.com 		    "the default BE in the grub menu.\n"), be_root_pool);
126913013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
127013013Sglenn.lagasse@oracle.com 		goto cleanup;
127113013Sglenn.lagasse@oracle.com 	}
127213013Sglenn.lagasse@oracle.com 
127313013Sglenn.lagasse@oracle.com 	(void) snprintf(grub_file, MAXPATHLEN, "%s%s",
127413013Sglenn.lagasse@oracle.com 	    pool_mntpnt, BE_GRUB_MENU);
127513013Sglenn.lagasse@oracle.com 
127613013Sglenn.lagasse@oracle.com 	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, grub_file,
127713013Sglenn.lagasse@oracle.com 	    &grub_fp, "r+", B_TRUE)) != BE_SUCCESS) {
127813013Sglenn.lagasse@oracle.com 		goto cleanup;
127913013Sglenn.lagasse@oracle.com 	} else if (grub_fp == NULL) {
128013013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
128113013Sglenn.lagasse@oracle.com 		goto cleanup;
128213013Sglenn.lagasse@oracle.com 	}
128313013Sglenn.lagasse@oracle.com 
128413013Sglenn.lagasse@oracle.com 	free(pool_mntpnt);
128513013Sglenn.lagasse@oracle.com 	pool_mntpnt = NULL;
128613013Sglenn.lagasse@oracle.com 
128713013Sglenn.lagasse@oracle.com 	/* Grab the stats of the original menu file */
128813013Sglenn.lagasse@oracle.com 	if (stat(grub_file, &sb) != 0) {
128913013Sglenn.lagasse@oracle.com 		err = errno;
129013013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: "
129113013Sglenn.lagasse@oracle.com 		    "failed to stat file %s: %s\n"), grub_file, strerror(err));
129213013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
129313013Sglenn.lagasse@oracle.com 		goto cleanup;
129413013Sglenn.lagasse@oracle.com 	}
129513013Sglenn.lagasse@oracle.com 
129613013Sglenn.lagasse@oracle.com 	/* Create a tmp file for the modified menu.lst */
129713013Sglenn.lagasse@oracle.com 	temp_grub_len = strlen(grub_file) + 7;
129813013Sglenn.lagasse@oracle.com 	if ((temp_grub = (char *)malloc(temp_grub_len)) == NULL) {
129913013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: "
130013013Sglenn.lagasse@oracle.com 		    "malloc failed\n"));
130113013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NOMEM;
130213013Sglenn.lagasse@oracle.com 		goto cleanup;
130313013Sglenn.lagasse@oracle.com 	}
130413013Sglenn.lagasse@oracle.com 	(void) memset(temp_grub, 0, temp_grub_len);
130513013Sglenn.lagasse@oracle.com 	(void) strlcpy(temp_grub, grub_file, temp_grub_len);
130613013Sglenn.lagasse@oracle.com 	(void) strlcat(temp_grub, "XXXXXX", temp_grub_len);
130713013Sglenn.lagasse@oracle.com 	if ((fd = mkstemp(temp_grub)) == -1) {
130813013Sglenn.lagasse@oracle.com 		err = errno;
130913013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: "
131013013Sglenn.lagasse@oracle.com 		    "mkstemp failed: %s\n"), strerror(err));
131113013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
131213013Sglenn.lagasse@oracle.com 		free(temp_grub);
131313013Sglenn.lagasse@oracle.com 		temp_grub = NULL;
131413013Sglenn.lagasse@oracle.com 		goto cleanup;
131513013Sglenn.lagasse@oracle.com 	}
131613013Sglenn.lagasse@oracle.com 	if ((temp_fp = fdopen(fd, "w")) == NULL) {
131713013Sglenn.lagasse@oracle.com 		err = errno;
131813013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: "
131913013Sglenn.lagasse@oracle.com 		    "failed to open %s file: %s\n"),
132013013Sglenn.lagasse@oracle.com 		    temp_grub, strerror(err));
132113013Sglenn.lagasse@oracle.com 		(void) close(fd);
132213013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
132313013Sglenn.lagasse@oracle.com 		goto cleanup;
132413013Sglenn.lagasse@oracle.com 	}
132513013Sglenn.lagasse@oracle.com 
132613013Sglenn.lagasse@oracle.com 	while (fgets(line, BUFSIZ, grub_fp)) {
132713013Sglenn.lagasse@oracle.com 		char *tok = strtok(line, BE_WHITE_SPACE);
132813013Sglenn.lagasse@oracle.com 
132913013Sglenn.lagasse@oracle.com 		if (tok == NULL || tok[0] == '#') {
133013013Sglenn.lagasse@oracle.com 			continue;
133113013Sglenn.lagasse@oracle.com 		} else if (strcmp(tok, "title") == 0) {
133213013Sglenn.lagasse@oracle.com 			entries++;
133313013Sglenn.lagasse@oracle.com 			continue;
133413013Sglenn.lagasse@oracle.com 		} else if (strcmp(tok, "bootfs") == 0) {
133513013Sglenn.lagasse@oracle.com 			char *bootfs = strtok(NULL, BE_WHITE_SPACE);
133613013Sglenn.lagasse@oracle.com 			if (bootfs == NULL)
133713013Sglenn.lagasse@oracle.com 				continue;
133813013Sglenn.lagasse@oracle.com 
133913013Sglenn.lagasse@oracle.com 			if (strcmp(bootfs, be_root_ds) == 0) {
134013013Sglenn.lagasse@oracle.com 				found_default = B_TRUE;
134113013Sglenn.lagasse@oracle.com 				break;
134213013Sglenn.lagasse@oracle.com 			}
134313013Sglenn.lagasse@oracle.com 		}
134413013Sglenn.lagasse@oracle.com 	}
134513013Sglenn.lagasse@oracle.com 
134613013Sglenn.lagasse@oracle.com 	if (!found_default) {
134713013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: failed "
134813013Sglenn.lagasse@oracle.com 		    "to find entry for %s in the grub menu\n"),
134913013Sglenn.lagasse@oracle.com 		    be_name);
135013013Sglenn.lagasse@oracle.com 		ret = BE_ERR_BE_NOENT;
135113013Sglenn.lagasse@oracle.com 		goto cleanup;
135213013Sglenn.lagasse@oracle.com 	}
135313013Sglenn.lagasse@oracle.com 
135413013Sglenn.lagasse@oracle.com 	rewind(grub_fp);
135513013Sglenn.lagasse@oracle.com 
135613013Sglenn.lagasse@oracle.com 	while (fgets(line, BUFSIZ, grub_fp)) {
135713013Sglenn.lagasse@oracle.com 		char *tok = NULL;
135813013Sglenn.lagasse@oracle.com 
135913013Sglenn.lagasse@oracle.com 		(void) strncpy(temp_line, line, BUFSIZ);
136013013Sglenn.lagasse@oracle.com 
136113013Sglenn.lagasse@oracle.com 		if ((tok = strtok(temp_line, BE_WHITE_SPACE)) != NULL &&
136213013Sglenn.lagasse@oracle.com 		    strcmp(tok, "default") == 0) {
136313013Sglenn.lagasse@oracle.com 			(void) snprintf(temp_line, BUFSIZ, "default %d\n",
136413013Sglenn.lagasse@oracle.com 			    entries - 1 >= 0 ? entries - 1 : 0);
136513013Sglenn.lagasse@oracle.com 			(void) fputs(temp_line, temp_fp);
136613013Sglenn.lagasse@oracle.com 		} else {
136713013Sglenn.lagasse@oracle.com 			(void) fputs(line, temp_fp);
136813013Sglenn.lagasse@oracle.com 		}
136913013Sglenn.lagasse@oracle.com 	}
137013013Sglenn.lagasse@oracle.com 
137113013Sglenn.lagasse@oracle.com 	(void) fclose(grub_fp);
137213013Sglenn.lagasse@oracle.com 	grub_fp = NULL;
137313013Sglenn.lagasse@oracle.com 	(void) fclose(temp_fp);
137413013Sglenn.lagasse@oracle.com 	temp_fp = NULL;
137513013Sglenn.lagasse@oracle.com 
137613013Sglenn.lagasse@oracle.com 	if (rename(temp_grub, grub_file) != 0) {
137713013Sglenn.lagasse@oracle.com 		err = errno;
137813013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: "
137913013Sglenn.lagasse@oracle.com 		    "failed to rename file %s to %s: %s\n"),
138013013Sglenn.lagasse@oracle.com 		    temp_grub, grub_file, strerror(err));
138113013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
138213013Sglenn.lagasse@oracle.com 		goto cleanup;
138313013Sglenn.lagasse@oracle.com 	}
138413013Sglenn.lagasse@oracle.com 	free(temp_grub);
138513013Sglenn.lagasse@oracle.com 	temp_grub = NULL;
138613013Sglenn.lagasse@oracle.com 
138713013Sglenn.lagasse@oracle.com 	/* Set the perms and ownership of the updated file */
138813013Sglenn.lagasse@oracle.com 	if (chmod(grub_file, sb.st_mode) != 0) {
138913013Sglenn.lagasse@oracle.com 		err = errno;
139013013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: "
139113013Sglenn.lagasse@oracle.com 		    "failed to chmod %s: %s\n"), grub_file, strerror(err));
139213013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
139313013Sglenn.lagasse@oracle.com 		goto cleanup;
139413013Sglenn.lagasse@oracle.com 	}
139513013Sglenn.lagasse@oracle.com 	if (chown(grub_file, sb.st_uid, sb.st_gid) != 0) {
139613013Sglenn.lagasse@oracle.com 		err = errno;
139713013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_change_grub_default: "
139813013Sglenn.lagasse@oracle.com 		    "failed to chown %s: %s\n"), grub_file, strerror(err));
139913013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
140013013Sglenn.lagasse@oracle.com 	}
140113013Sglenn.lagasse@oracle.com 
140213013Sglenn.lagasse@oracle.com cleanup:
140313013Sglenn.lagasse@oracle.com 	if (pool_mounted) {
140413013Sglenn.lagasse@oracle.com 		int err = BE_SUCCESS;
140513013Sglenn.lagasse@oracle.com 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
140613013Sglenn.lagasse@oracle.com 		if (ret == BE_SUCCESS)
140713013Sglenn.lagasse@oracle.com 			ret = err;
140813013Sglenn.lagasse@oracle.com 		free(orig_mntpnt);
140913013Sglenn.lagasse@oracle.com 		free(ptmp_mntpnt);
141013013Sglenn.lagasse@oracle.com 	}
141113013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
141213013Sglenn.lagasse@oracle.com 	if (grub_fp != NULL)
141313013Sglenn.lagasse@oracle.com 		(void) fclose(grub_fp);
141413013Sglenn.lagasse@oracle.com 	if (temp_fp != NULL)
141513013Sglenn.lagasse@oracle.com 		(void) fclose(temp_fp);
141613013Sglenn.lagasse@oracle.com 	if (temp_grub != NULL) {
141713013Sglenn.lagasse@oracle.com 		(void) unlink(temp_grub);
141813013Sglenn.lagasse@oracle.com 		free(temp_grub);
141913013Sglenn.lagasse@oracle.com 	}
142013013Sglenn.lagasse@oracle.com 
142113013Sglenn.lagasse@oracle.com 	return (ret);
142213013Sglenn.lagasse@oracle.com }
142313013Sglenn.lagasse@oracle.com 
142413013Sglenn.lagasse@oracle.com /*
142513013Sglenn.lagasse@oracle.com  * Function:	be_update_menu
142613013Sglenn.lagasse@oracle.com  * Description:	This function is used by be_rename to change the BE name in
142713013Sglenn.lagasse@oracle.com  *		an existing entry in the grub menu to the new name of the BE.
142813013Sglenn.lagasse@oracle.com  * Parameters:
142913013Sglenn.lagasse@oracle.com  *		be_orig_name - the original name of the BE
143013013Sglenn.lagasse@oracle.com  *		be_new_name - the new name the BE is being renameed to.
143113013Sglenn.lagasse@oracle.com  *		be_root_pool - The pool which contains the grub menu
143213013Sglenn.lagasse@oracle.com  *		boot_pool - the pool where the BE is, if different than
143313013Sglenn.lagasse@oracle.com  *			the pool containing the boot menu.  If this is
143413013Sglenn.lagasse@oracle.com  *			NULL it will be set to be_root_pool.
143513013Sglenn.lagasse@oracle.com  * Returns:
143613013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
143713013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
143813013Sglenn.lagasse@oracle.com  * Scope:
143913013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
144013013Sglenn.lagasse@oracle.com  */
144113013Sglenn.lagasse@oracle.com int
be_update_menu(char * be_orig_name,char * be_new_name,char * be_root_pool,char * boot_pool)144213013Sglenn.lagasse@oracle.com be_update_menu(char *be_orig_name, char *be_new_name, char *be_root_pool,
144313013Sglenn.lagasse@oracle.com     char *boot_pool)
144413013Sglenn.lagasse@oracle.com {
144513013Sglenn.lagasse@oracle.com 	zfs_handle_t *zhp = NULL;
144613013Sglenn.lagasse@oracle.com 	char menu_file[MAXPATHLEN];
144713013Sglenn.lagasse@oracle.com 	char be_root_ds[MAXPATHLEN];
144813013Sglenn.lagasse@oracle.com 	char be_new_root_ds[MAXPATHLEN];
144913013Sglenn.lagasse@oracle.com 	char line[BUFSIZ];
145013013Sglenn.lagasse@oracle.com 	char *pool_mntpnt = NULL;
145113013Sglenn.lagasse@oracle.com 	char *ptmp_mntpnt = NULL;
145213013Sglenn.lagasse@oracle.com 	char *orig_mntpnt = NULL;
145313013Sglenn.lagasse@oracle.com 	char *temp_menu = NULL;
145413013Sglenn.lagasse@oracle.com 	FILE *menu_fp = NULL;
145513013Sglenn.lagasse@oracle.com 	FILE *new_fp = NULL;
145613013Sglenn.lagasse@oracle.com 	struct stat sb;
145713013Sglenn.lagasse@oracle.com 	int temp_menu_len = 0;
145813013Sglenn.lagasse@oracle.com 	int tmp_fd;
145913013Sglenn.lagasse@oracle.com 	int ret = BE_SUCCESS;
146013013Sglenn.lagasse@oracle.com 	int err = 0;
146113013Sglenn.lagasse@oracle.com 	boolean_t pool_mounted = B_FALSE;
146213013Sglenn.lagasse@oracle.com 
146313013Sglenn.lagasse@oracle.com 	errno = 0;
146413013Sglenn.lagasse@oracle.com 
146513013Sglenn.lagasse@oracle.com 	if (boot_pool == NULL)
146613013Sglenn.lagasse@oracle.com 		boot_pool = be_root_pool;
146713013Sglenn.lagasse@oracle.com 
146813013Sglenn.lagasse@oracle.com 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
146913013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: failed to open "
147013013Sglenn.lagasse@oracle.com 		    "pool dataset for %s: %s\n"), be_root_pool,
147113013Sglenn.lagasse@oracle.com 		    libzfs_error_description(g_zfs));
147213013Sglenn.lagasse@oracle.com 		return (zfs_err_to_be_err(g_zfs));
147313013Sglenn.lagasse@oracle.com 	}
147413013Sglenn.lagasse@oracle.com 
147513013Sglenn.lagasse@oracle.com 	/*
147613013Sglenn.lagasse@oracle.com 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
147713013Sglenn.lagasse@oracle.com 	 * attempt to mount it.
147813013Sglenn.lagasse@oracle.com 	 */
147913013Sglenn.lagasse@oracle.com 	if ((ret = be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
148013013Sglenn.lagasse@oracle.com 	    &pool_mounted)) != BE_SUCCESS) {
148113013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: pool dataset "
148213013Sglenn.lagasse@oracle.com 		    "(%s) could not be mounted\n"), be_root_pool);
148313013Sglenn.lagasse@oracle.com 		ZFS_CLOSE(zhp);
148413013Sglenn.lagasse@oracle.com 		return (ret);
148513013Sglenn.lagasse@oracle.com 	}
148613013Sglenn.lagasse@oracle.com 
148713013Sglenn.lagasse@oracle.com 	/*
148813013Sglenn.lagasse@oracle.com 	 * Get the mountpoint for the root pool dataset.
148913013Sglenn.lagasse@oracle.com 	 */
149013013Sglenn.lagasse@oracle.com 	if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
149113013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: failed "
149213013Sglenn.lagasse@oracle.com 		    "to get mount point for the root pool. Can't set "
149313013Sglenn.lagasse@oracle.com 		    "the default BE in the grub menu.\n"));
149413013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
149513013Sglenn.lagasse@oracle.com 		goto cleanup;
149613013Sglenn.lagasse@oracle.com 	}
149713013Sglenn.lagasse@oracle.com 
149813013Sglenn.lagasse@oracle.com 	/*
149913013Sglenn.lagasse@oracle.com 	 * Check to see if this system supports grub
150013013Sglenn.lagasse@oracle.com 	 */
150113013Sglenn.lagasse@oracle.com 	if (be_has_grub()) {
150213013Sglenn.lagasse@oracle.com 		(void) snprintf(menu_file, sizeof (menu_file),
150313013Sglenn.lagasse@oracle.com 		    "%s%s", pool_mntpnt, BE_GRUB_MENU);
150413013Sglenn.lagasse@oracle.com 	} else {
150513013Sglenn.lagasse@oracle.com 		(void) snprintf(menu_file, sizeof (menu_file),
150613013Sglenn.lagasse@oracle.com 		    "%s%s", pool_mntpnt, BE_SPARC_MENU);
150713013Sglenn.lagasse@oracle.com 	}
150813013Sglenn.lagasse@oracle.com 
150913013Sglenn.lagasse@oracle.com 	be_make_root_ds(be_root_pool, be_orig_name, be_root_ds,
151013013Sglenn.lagasse@oracle.com 	    sizeof (be_root_ds));
151113013Sglenn.lagasse@oracle.com 	be_make_root_ds(be_root_pool, be_new_name, be_new_root_ds,
151213013Sglenn.lagasse@oracle.com 	    sizeof (be_new_root_ds));
151313013Sglenn.lagasse@oracle.com 
151413013Sglenn.lagasse@oracle.com 	if ((ret = be_open_menu(be_root_pool, pool_mntpnt, menu_file,
151513013Sglenn.lagasse@oracle.com 	    &menu_fp, "r", B_TRUE)) != BE_SUCCESS) {
151613013Sglenn.lagasse@oracle.com 		goto cleanup;
151713013Sglenn.lagasse@oracle.com 	} else if (menu_fp == NULL) {
151813013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NO_MENU;
151913013Sglenn.lagasse@oracle.com 		goto cleanup;
152013013Sglenn.lagasse@oracle.com 	}
152113013Sglenn.lagasse@oracle.com 
152213013Sglenn.lagasse@oracle.com 	free(pool_mntpnt);
152313013Sglenn.lagasse@oracle.com 	pool_mntpnt = NULL;
152413013Sglenn.lagasse@oracle.com 
152513013Sglenn.lagasse@oracle.com 	/* Grab the stat of the original menu file */
152613013Sglenn.lagasse@oracle.com 	if (stat(menu_file, &sb) != 0) {
152713013Sglenn.lagasse@oracle.com 		err = errno;
152813013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: "
152913013Sglenn.lagasse@oracle.com 		    "failed to stat file %s: %s\n"), menu_file, strerror(err));
153013013Sglenn.lagasse@oracle.com 		(void) fclose(menu_fp);
153113013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
153213013Sglenn.lagasse@oracle.com 		goto cleanup;
153313013Sglenn.lagasse@oracle.com 	}
153413013Sglenn.lagasse@oracle.com 
153513013Sglenn.lagasse@oracle.com 	/* Create tmp file for modified menu.lst */
153613013Sglenn.lagasse@oracle.com 	temp_menu_len = strlen(menu_file) + 7;
153713013Sglenn.lagasse@oracle.com 	if ((temp_menu = (char *)malloc(temp_menu_len))
153813013Sglenn.lagasse@oracle.com 	    == NULL) {
153913013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: "
154013013Sglenn.lagasse@oracle.com 		    "malloc failed\n"));
154113013Sglenn.lagasse@oracle.com 		(void) fclose(menu_fp);
154213013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NOMEM;
154313013Sglenn.lagasse@oracle.com 		goto cleanup;
154413013Sglenn.lagasse@oracle.com 	}
154513013Sglenn.lagasse@oracle.com 	(void) memset(temp_menu, 0, temp_menu_len);
154613013Sglenn.lagasse@oracle.com 	(void) strlcpy(temp_menu, menu_file, temp_menu_len);
154713013Sglenn.lagasse@oracle.com 	(void) strlcat(temp_menu, "XXXXXX", temp_menu_len);
154813013Sglenn.lagasse@oracle.com 	if ((tmp_fd = mkstemp(temp_menu)) == -1) {
154913013Sglenn.lagasse@oracle.com 		err = errno;
155013013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: "
155113013Sglenn.lagasse@oracle.com 		    "mkstemp failed: %s\n"), strerror(err));
155213013Sglenn.lagasse@oracle.com 		(void) fclose(menu_fp);
155313013Sglenn.lagasse@oracle.com 		free(temp_menu);
155413013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
155513013Sglenn.lagasse@oracle.com 		goto cleanup;
155613013Sglenn.lagasse@oracle.com 	}
155713013Sglenn.lagasse@oracle.com 	if ((new_fp = fdopen(tmp_fd, "w")) == NULL) {
155813013Sglenn.lagasse@oracle.com 		err = errno;
155913013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: "
156013013Sglenn.lagasse@oracle.com 		    "fdopen failed: %s\n"), strerror(err));
156113013Sglenn.lagasse@oracle.com 		(void) close(tmp_fd);
156213013Sglenn.lagasse@oracle.com 		(void) fclose(menu_fp);
156313013Sglenn.lagasse@oracle.com 		free(temp_menu);
156413013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
156513013Sglenn.lagasse@oracle.com 		goto cleanup;
156613013Sglenn.lagasse@oracle.com 	}
156713013Sglenn.lagasse@oracle.com 
156813013Sglenn.lagasse@oracle.com 	while (fgets(line, BUFSIZ, menu_fp)) {
156913013Sglenn.lagasse@oracle.com 		char tline[BUFSIZ];
157013013Sglenn.lagasse@oracle.com 		char new_line[BUFSIZ];
157113013Sglenn.lagasse@oracle.com 		char *c = NULL;
157213013Sglenn.lagasse@oracle.com 
157313013Sglenn.lagasse@oracle.com 		(void) strlcpy(tline, line, sizeof (tline));
157413013Sglenn.lagasse@oracle.com 
157513013Sglenn.lagasse@oracle.com 		/* Tokenize line */
157613013Sglenn.lagasse@oracle.com 		c = strtok(tline, BE_WHITE_SPACE);
157713013Sglenn.lagasse@oracle.com 
157813013Sglenn.lagasse@oracle.com 		if (c == NULL) {
157913013Sglenn.lagasse@oracle.com 			/* Found empty line, write it out. */
158013013Sglenn.lagasse@oracle.com 			(void) fputs(line, new_fp);
158113013Sglenn.lagasse@oracle.com 		} else if (c[0] == '#') {
158213013Sglenn.lagasse@oracle.com 			/* Found a comment line, write it out. */
158313013Sglenn.lagasse@oracle.com 			(void) fputs(line, new_fp);
158413013Sglenn.lagasse@oracle.com 		} else if (strcmp(c, "title") == 0) {
158513013Sglenn.lagasse@oracle.com 			char *name = NULL;
158613013Sglenn.lagasse@oracle.com 			char *desc = NULL;
158713013Sglenn.lagasse@oracle.com 
158813013Sglenn.lagasse@oracle.com 			/*
158913013Sglenn.lagasse@oracle.com 			 * Found a 'title' line, parse out BE name or
159013013Sglenn.lagasse@oracle.com 			 * the description.
159113013Sglenn.lagasse@oracle.com 			 */
159213013Sglenn.lagasse@oracle.com 			name = strtok(NULL, BE_WHITE_SPACE);
159313013Sglenn.lagasse@oracle.com 
159413013Sglenn.lagasse@oracle.com 			if (name == NULL) {
159513013Sglenn.lagasse@oracle.com 				/*
159613013Sglenn.lagasse@oracle.com 				 * Nothing after 'title', just push
159713013Sglenn.lagasse@oracle.com 				 * this line through
159813013Sglenn.lagasse@oracle.com 				 */
159913013Sglenn.lagasse@oracle.com 				(void) fputs(line, new_fp);
160013013Sglenn.lagasse@oracle.com 			} else {
160113013Sglenn.lagasse@oracle.com 				/*
160213013Sglenn.lagasse@oracle.com 				 * Grab the remainder of the title which
160313013Sglenn.lagasse@oracle.com 				 * could be a multi worded description
160413013Sglenn.lagasse@oracle.com 				 */
160513013Sglenn.lagasse@oracle.com 				desc = strtok(NULL, "\n");
160613013Sglenn.lagasse@oracle.com 
160713013Sglenn.lagasse@oracle.com 				if (strcmp(name, be_orig_name) == 0) {
160813013Sglenn.lagasse@oracle.com 					/*
160913013Sglenn.lagasse@oracle.com 					 * The first token of the title is
161013013Sglenn.lagasse@oracle.com 					 * the old BE name, replace it with
161113013Sglenn.lagasse@oracle.com 					 * the new one, and write it out
161213013Sglenn.lagasse@oracle.com 					 * along with the remainder of
161313013Sglenn.lagasse@oracle.com 					 * description if there is one.
161413013Sglenn.lagasse@oracle.com 					 */
161513013Sglenn.lagasse@oracle.com 					if (desc) {
161613013Sglenn.lagasse@oracle.com 						(void) snprintf(new_line,
161713013Sglenn.lagasse@oracle.com 						    sizeof (new_line),
161813013Sglenn.lagasse@oracle.com 						    "title %s %s\n",
161913013Sglenn.lagasse@oracle.com 						    be_new_name, desc);
162013013Sglenn.lagasse@oracle.com 					} else {
162113013Sglenn.lagasse@oracle.com 						(void) snprintf(new_line,
162213013Sglenn.lagasse@oracle.com 						    sizeof (new_line),
162313013Sglenn.lagasse@oracle.com 						    "title %s\n", be_new_name);
162413013Sglenn.lagasse@oracle.com 					}
162513013Sglenn.lagasse@oracle.com 
162613013Sglenn.lagasse@oracle.com 					(void) fputs(new_line, new_fp);
162713013Sglenn.lagasse@oracle.com 				} else {
162813013Sglenn.lagasse@oracle.com 					(void) fputs(line, new_fp);
162913013Sglenn.lagasse@oracle.com 				}
163013013Sglenn.lagasse@oracle.com 			}
163113013Sglenn.lagasse@oracle.com 		} else if (strcmp(c, "bootfs") == 0) {
163213013Sglenn.lagasse@oracle.com 			/*
163313013Sglenn.lagasse@oracle.com 			 * Found a 'bootfs' line, parse out the BE root
163413013Sglenn.lagasse@oracle.com 			 * dataset value.
163513013Sglenn.lagasse@oracle.com 			 */
163613013Sglenn.lagasse@oracle.com 			char *root_ds = strtok(NULL, BE_WHITE_SPACE);
163713013Sglenn.lagasse@oracle.com 
163813013Sglenn.lagasse@oracle.com 			if (root_ds == NULL) {
163913013Sglenn.lagasse@oracle.com 				/*
164013013Sglenn.lagasse@oracle.com 				 * Nothing after 'bootfs', just push
164113013Sglenn.lagasse@oracle.com 				 * this line through
164213013Sglenn.lagasse@oracle.com 				 */
164313013Sglenn.lagasse@oracle.com 				(void) fputs(line, new_fp);
164413013Sglenn.lagasse@oracle.com 			} else {
164513013Sglenn.lagasse@oracle.com 				/*
164613013Sglenn.lagasse@oracle.com 				 * If this bootfs is the one we're renaming,
164713013Sglenn.lagasse@oracle.com 				 * write out the new root dataset value
164813013Sglenn.lagasse@oracle.com 				 */
164913013Sglenn.lagasse@oracle.com 				if (strcmp(root_ds, be_root_ds) == 0) {
165013013Sglenn.lagasse@oracle.com 					(void) snprintf(new_line,
165113013Sglenn.lagasse@oracle.com 					    sizeof (new_line), "bootfs %s\n",
165213013Sglenn.lagasse@oracle.com 					    be_new_root_ds);
165313013Sglenn.lagasse@oracle.com 
165413013Sglenn.lagasse@oracle.com 					(void) fputs(new_line, new_fp);
165513013Sglenn.lagasse@oracle.com 				} else {
165613013Sglenn.lagasse@oracle.com 					(void) fputs(line, new_fp);
165713013Sglenn.lagasse@oracle.com 				}
165813013Sglenn.lagasse@oracle.com 			}
165913013Sglenn.lagasse@oracle.com 		} else {
166013013Sglenn.lagasse@oracle.com 			/*
166113013Sglenn.lagasse@oracle.com 			 * Found some other line we don't care
166213013Sglenn.lagasse@oracle.com 			 * about, write it out.
166313013Sglenn.lagasse@oracle.com 			 */
166413013Sglenn.lagasse@oracle.com 			(void) fputs(line, new_fp);
166513013Sglenn.lagasse@oracle.com 		}
166613013Sglenn.lagasse@oracle.com 	}
166713013Sglenn.lagasse@oracle.com 
166813013Sglenn.lagasse@oracle.com 	(void) fclose(menu_fp);
166913013Sglenn.lagasse@oracle.com 	(void) fclose(new_fp);
167013013Sglenn.lagasse@oracle.com 	(void) close(tmp_fd);
167113013Sglenn.lagasse@oracle.com 
167213013Sglenn.lagasse@oracle.com 	if (rename(temp_menu, menu_file) != 0) {
167313013Sglenn.lagasse@oracle.com 		err = errno;
167413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: "
167513013Sglenn.lagasse@oracle.com 		    "failed to rename file %s to %s: %s\n"),
167613013Sglenn.lagasse@oracle.com 		    temp_menu, menu_file, strerror(err));
167713013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
167813013Sglenn.lagasse@oracle.com 	}
167913013Sglenn.lagasse@oracle.com 	free(temp_menu);
168013013Sglenn.lagasse@oracle.com 
168113013Sglenn.lagasse@oracle.com 	/* Set the perms and ownership of the updated file */
168213013Sglenn.lagasse@oracle.com 	if (chmod(menu_file, sb.st_mode) != 0) {
168313013Sglenn.lagasse@oracle.com 		err = errno;
168413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: "
168513013Sglenn.lagasse@oracle.com 		    "failed to chmod %s: %s\n"), menu_file, strerror(err));
168613013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
168713013Sglenn.lagasse@oracle.com 		goto cleanup;
168813013Sglenn.lagasse@oracle.com 	}
168913013Sglenn.lagasse@oracle.com 	if (chown(menu_file, sb.st_uid, sb.st_gid) != 0) {
169013013Sglenn.lagasse@oracle.com 		err = errno;
169113013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_update_menu: "
169213013Sglenn.lagasse@oracle.com 		    "failed to chown %s: %s\n"), menu_file, strerror(err));
169313013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
169413013Sglenn.lagasse@oracle.com 	}
169513013Sglenn.lagasse@oracle.com 
169613013Sglenn.lagasse@oracle.com cleanup:
169713013Sglenn.lagasse@oracle.com 	if (pool_mounted) {
169813013Sglenn.lagasse@oracle.com 		int err = BE_SUCCESS;
169913013Sglenn.lagasse@oracle.com 		err = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
170013013Sglenn.lagasse@oracle.com 		if (ret == BE_SUCCESS)
170113013Sglenn.lagasse@oracle.com 			ret = err;
170213013Sglenn.lagasse@oracle.com 		free(orig_mntpnt);
170313013Sglenn.lagasse@oracle.com 		free(ptmp_mntpnt);
170413013Sglenn.lagasse@oracle.com 	}
170513013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
170613013Sglenn.lagasse@oracle.com 	return (ret);
170713013Sglenn.lagasse@oracle.com }
170813013Sglenn.lagasse@oracle.com 
170913013Sglenn.lagasse@oracle.com /*
171013013Sglenn.lagasse@oracle.com  * Function:	be_has_menu_entry
171113013Sglenn.lagasse@oracle.com  * Description:	Checks to see if the BEs root dataset has an entry in the grub
171213013Sglenn.lagasse@oracle.com  *		menu.
171313013Sglenn.lagasse@oracle.com  * Parameters:
171413013Sglenn.lagasse@oracle.com  *		be_dataset - The root dataset of the BE
171513013Sglenn.lagasse@oracle.com  *		be_root_pool - The pool which contains the boot menu
171613013Sglenn.lagasse@oracle.com  *		entry - A pointer the the entry number of the BE if found.
171713013Sglenn.lagasse@oracle.com  * Returns:
171813013Sglenn.lagasse@oracle.com  *		B_TRUE - Success
171913013Sglenn.lagasse@oracle.com  *		B_FALSE - Failure
172013013Sglenn.lagasse@oracle.com  * Scope:
172113013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
172213013Sglenn.lagasse@oracle.com  */
172313013Sglenn.lagasse@oracle.com boolean_t
be_has_menu_entry(char * be_dataset,char * be_root_pool,int * entry)172413013Sglenn.lagasse@oracle.com be_has_menu_entry(char *be_dataset, char *be_root_pool, int *entry)
172513013Sglenn.lagasse@oracle.com {
172613013Sglenn.lagasse@oracle.com 	zfs_handle_t *zhp = NULL;
172713013Sglenn.lagasse@oracle.com 	char		menu_file[MAXPATHLEN];
172813013Sglenn.lagasse@oracle.com 	FILE		*menu_fp;
172913013Sglenn.lagasse@oracle.com 	char		line[BUFSIZ];
173013013Sglenn.lagasse@oracle.com 	char		*last;
173113013Sglenn.lagasse@oracle.com 	char		*rpool_mntpnt = NULL;
173213013Sglenn.lagasse@oracle.com 	char		*ptmp_mntpnt = NULL;
173313013Sglenn.lagasse@oracle.com 	char		*orig_mntpnt = NULL;
173413013Sglenn.lagasse@oracle.com 	int		ent_num = 0;
173513013Sglenn.lagasse@oracle.com 	boolean_t	ret = 0;
173613013Sglenn.lagasse@oracle.com 	boolean_t	pool_mounted = B_FALSE;
173713013Sglenn.lagasse@oracle.com 
173813013Sglenn.lagasse@oracle.com 
173913013Sglenn.lagasse@oracle.com 	/*
174013013Sglenn.lagasse@oracle.com 	 * Check to see if this system supports grub
174113013Sglenn.lagasse@oracle.com 	 */
174213013Sglenn.lagasse@oracle.com 	if ((zhp = zfs_open(g_zfs, be_root_pool, ZFS_TYPE_DATASET)) == NULL) {
174313013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_has_menu_entry: failed to open "
174413013Sglenn.lagasse@oracle.com 		    "pool dataset for %s: %s\n"), be_root_pool,
174513013Sglenn.lagasse@oracle.com 		    libzfs_error_description(g_zfs));
174613013Sglenn.lagasse@oracle.com 		return (B_FALSE);
174713013Sglenn.lagasse@oracle.com 	}
174813013Sglenn.lagasse@oracle.com 
174913013Sglenn.lagasse@oracle.com 	/*
175013013Sglenn.lagasse@oracle.com 	 * Check to see if the pool's dataset is mounted. If it isn't we'll
175113013Sglenn.lagasse@oracle.com 	 * attempt to mount it.
175213013Sglenn.lagasse@oracle.com 	 */
175313013Sglenn.lagasse@oracle.com 	if (be_mount_pool(zhp, &ptmp_mntpnt, &orig_mntpnt,
175413013Sglenn.lagasse@oracle.com 	    &pool_mounted) != 0) {
175513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_has_menu_entry: pool dataset "
175613013Sglenn.lagasse@oracle.com 		    "(%s) could not be mounted\n"), be_root_pool);
175713013Sglenn.lagasse@oracle.com 		ZFS_CLOSE(zhp);
175813013Sglenn.lagasse@oracle.com 		return (B_FALSE);
175913013Sglenn.lagasse@oracle.com 	}
176013013Sglenn.lagasse@oracle.com 
176113013Sglenn.lagasse@oracle.com 	/*
176213013Sglenn.lagasse@oracle.com 	 * Get the mountpoint for the root pool dataset.
176313013Sglenn.lagasse@oracle.com 	 */
176413013Sglenn.lagasse@oracle.com 	if (!zfs_is_mounted(zhp, &rpool_mntpnt)) {
176513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_has_menu_entry: pool "
176613013Sglenn.lagasse@oracle.com 		    "dataset (%s) is not mounted. Can't set "
176713013Sglenn.lagasse@oracle.com 		    "the default BE in the grub menu.\n"), be_root_pool);
176813013Sglenn.lagasse@oracle.com 		ret = B_FALSE;
176913013Sglenn.lagasse@oracle.com 		goto cleanup;
177013013Sglenn.lagasse@oracle.com 	}
177113013Sglenn.lagasse@oracle.com 
177213013Sglenn.lagasse@oracle.com 	if (be_has_grub()) {
177313013Sglenn.lagasse@oracle.com 		(void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
177413013Sglenn.lagasse@oracle.com 		    rpool_mntpnt, BE_GRUB_MENU);
177513013Sglenn.lagasse@oracle.com 	} else {
177613013Sglenn.lagasse@oracle.com 		(void) snprintf(menu_file, MAXPATHLEN, "/%s%s",
177713013Sglenn.lagasse@oracle.com 		    rpool_mntpnt, BE_SPARC_MENU);
177813013Sglenn.lagasse@oracle.com 	}
177913013Sglenn.lagasse@oracle.com 
178013013Sglenn.lagasse@oracle.com 	if (be_open_menu(be_root_pool, rpool_mntpnt, menu_file, &menu_fp, "r",
178113013Sglenn.lagasse@oracle.com 	    B_FALSE) != 0) {
178213013Sglenn.lagasse@oracle.com 		ret = B_FALSE;
178313013Sglenn.lagasse@oracle.com 		goto cleanup;
178413013Sglenn.lagasse@oracle.com 	} else if (menu_fp == NULL) {
178513013Sglenn.lagasse@oracle.com 		ret = B_FALSE;
178613013Sglenn.lagasse@oracle.com 		goto cleanup;
178713013Sglenn.lagasse@oracle.com 	}
178813013Sglenn.lagasse@oracle.com 
178913013Sglenn.lagasse@oracle.com 	free(rpool_mntpnt);
179013013Sglenn.lagasse@oracle.com 	rpool_mntpnt = NULL;
179113013Sglenn.lagasse@oracle.com 
179213013Sglenn.lagasse@oracle.com 	while (fgets(line, BUFSIZ, menu_fp)) {
179313013Sglenn.lagasse@oracle.com 		char *tok = strtok_r(line, BE_WHITE_SPACE, &last);
179413013Sglenn.lagasse@oracle.com 
179513013Sglenn.lagasse@oracle.com 		if (tok != NULL && tok[0] != '#') {
179613013Sglenn.lagasse@oracle.com 			if (strcmp(tok, "bootfs") == 0) {
179713013Sglenn.lagasse@oracle.com 				tok = strtok_r(last, BE_WHITE_SPACE, &last);
179813013Sglenn.lagasse@oracle.com 				if (tok != NULL && strcmp(tok,
179913013Sglenn.lagasse@oracle.com 				    be_dataset) == 0) {
180013013Sglenn.lagasse@oracle.com 					(void) fclose(menu_fp);
180113013Sglenn.lagasse@oracle.com 					/*
180213013Sglenn.lagasse@oracle.com 					 * The entry number needs to be
180313013Sglenn.lagasse@oracle.com 					 * decremented here because the title
180413013Sglenn.lagasse@oracle.com 					 * will always be the first line for
180513013Sglenn.lagasse@oracle.com 					 * an entry. Because of this we'll
180613013Sglenn.lagasse@oracle.com 					 * always be off by one entry when we
180713013Sglenn.lagasse@oracle.com 					 * check for bootfs.
180813013Sglenn.lagasse@oracle.com 					 */
180913013Sglenn.lagasse@oracle.com 					*entry = ent_num - 1;
181013013Sglenn.lagasse@oracle.com 					ret = B_TRUE;
181113013Sglenn.lagasse@oracle.com 					goto cleanup;
181213013Sglenn.lagasse@oracle.com 				}
181313013Sglenn.lagasse@oracle.com 			} else if (strcmp(tok, "title") == 0)
181413013Sglenn.lagasse@oracle.com 				ent_num++;
181513013Sglenn.lagasse@oracle.com 		}
181613013Sglenn.lagasse@oracle.com 	}
181713013Sglenn.lagasse@oracle.com 
181813013Sglenn.lagasse@oracle.com cleanup:
181913013Sglenn.lagasse@oracle.com 	if (pool_mounted) {
182013013Sglenn.lagasse@oracle.com 		(void) be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
182113013Sglenn.lagasse@oracle.com 		free(orig_mntpnt);
182213013Sglenn.lagasse@oracle.com 		free(ptmp_mntpnt);
182313013Sglenn.lagasse@oracle.com 	}
182413013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
182513013Sglenn.lagasse@oracle.com 	(void) fclose(menu_fp);
182613013Sglenn.lagasse@oracle.com 	return (ret);
182713013Sglenn.lagasse@oracle.com }
182813013Sglenn.lagasse@oracle.com 
182913013Sglenn.lagasse@oracle.com /*
183013013Sglenn.lagasse@oracle.com  * Function:	be_update_vfstab
183113013Sglenn.lagasse@oracle.com  * Description:	This function digs into a BE's vfstab and updates all
183213013Sglenn.lagasse@oracle.com  *		entries with file systems listed in be_fs_list_data_t.
183313013Sglenn.lagasse@oracle.com  *		The entry's root container dataset and be_name will be
183413013Sglenn.lagasse@oracle.com  *		updated with the parameters passed in.
183513013Sglenn.lagasse@oracle.com  * Parameters:
183613013Sglenn.lagasse@oracle.com  *		be_name - name of BE to update
183713013Sglenn.lagasse@oracle.com  *		old_rc_loc - dataset under which the root container dataset
183813013Sglenn.lagasse@oracle.com  *			of the old BE resides in.
183913013Sglenn.lagasse@oracle.com  *		new_rc_loc - dataset under which the root container dataset
184013013Sglenn.lagasse@oracle.com  *			of the new BE resides in.
184113013Sglenn.lagasse@oracle.com  *		fld - be_fs_list_data_t pointer providing the list of
184213013Sglenn.lagasse@oracle.com  *			file systems to look for in vfstab.
184313013Sglenn.lagasse@oracle.com  *		mountpoint - directory of where BE is currently mounted.
184413013Sglenn.lagasse@oracle.com  *			If NULL, then BE is not currently mounted.
184513013Sglenn.lagasse@oracle.com  * Returns:
184613013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
184713013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
184813013Sglenn.lagasse@oracle.com  * Scope:
184913013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
185013013Sglenn.lagasse@oracle.com  */
185113013Sglenn.lagasse@oracle.com int
be_update_vfstab(char * be_name,char * old_rc_loc,char * new_rc_loc,be_fs_list_data_t * fld,char * mountpoint)185213013Sglenn.lagasse@oracle.com be_update_vfstab(char *be_name, char *old_rc_loc, char *new_rc_loc,
185313013Sglenn.lagasse@oracle.com     be_fs_list_data_t *fld, char *mountpoint)
185413013Sglenn.lagasse@oracle.com {
185513013Sglenn.lagasse@oracle.com 	char		*tmp_mountpoint = NULL;
185613013Sglenn.lagasse@oracle.com 	char		alt_vfstab[MAXPATHLEN];
185713013Sglenn.lagasse@oracle.com 	int		ret = BE_SUCCESS, err = BE_SUCCESS;
185813013Sglenn.lagasse@oracle.com 
185913013Sglenn.lagasse@oracle.com 	if (fld == NULL || fld->fs_list == NULL || fld->fs_num == 0)
186013013Sglenn.lagasse@oracle.com 		return (BE_SUCCESS);
186113013Sglenn.lagasse@oracle.com 
186213013Sglenn.lagasse@oracle.com 	/* If BE not already mounted, mount the BE */
186313013Sglenn.lagasse@oracle.com 	if (mountpoint == NULL) {
186413013Sglenn.lagasse@oracle.com 		if ((ret = _be_mount(be_name, &tmp_mountpoint,
186513013Sglenn.lagasse@oracle.com 		    BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
186613013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_update_vfstab: "
186713013Sglenn.lagasse@oracle.com 			    "failed to mount BE (%s)\n"), be_name);
186813013Sglenn.lagasse@oracle.com 			return (ret);
186913013Sglenn.lagasse@oracle.com 		}
187013013Sglenn.lagasse@oracle.com 	} else {
187113013Sglenn.lagasse@oracle.com 		tmp_mountpoint = mountpoint;
187213013Sglenn.lagasse@oracle.com 	}
187313013Sglenn.lagasse@oracle.com 
187413013Sglenn.lagasse@oracle.com 	/* Get string for vfstab in the mounted BE. */
187513013Sglenn.lagasse@oracle.com 	(void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
187613013Sglenn.lagasse@oracle.com 	    tmp_mountpoint);
187713013Sglenn.lagasse@oracle.com 
187813013Sglenn.lagasse@oracle.com 	/* Update the vfstab */
187913013Sglenn.lagasse@oracle.com 	ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
188013013Sglenn.lagasse@oracle.com 	    fld);
188113013Sglenn.lagasse@oracle.com 
188213013Sglenn.lagasse@oracle.com 	/* Unmount BE if we mounted it */
188313013Sglenn.lagasse@oracle.com 	if (mountpoint == NULL) {
188413013Sglenn.lagasse@oracle.com 		if ((err = _be_unmount(be_name, 0)) == BE_SUCCESS) {
188513013Sglenn.lagasse@oracle.com 			/* Remove temporary mountpoint */
188613013Sglenn.lagasse@oracle.com 			(void) rmdir(tmp_mountpoint);
188713013Sglenn.lagasse@oracle.com 		} else {
188813013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_update_vfstab: "
188913013Sglenn.lagasse@oracle.com 			    "failed to unmount BE %s mounted at %s\n"),
189013013Sglenn.lagasse@oracle.com 			    be_name, tmp_mountpoint);
189113013Sglenn.lagasse@oracle.com 			if (ret == BE_SUCCESS)
189213013Sglenn.lagasse@oracle.com 				ret = err;
189313013Sglenn.lagasse@oracle.com 		}
189413013Sglenn.lagasse@oracle.com 
189513013Sglenn.lagasse@oracle.com 		free(tmp_mountpoint);
189613013Sglenn.lagasse@oracle.com 	}
189713013Sglenn.lagasse@oracle.com 
189813013Sglenn.lagasse@oracle.com 	return (ret);
189913013Sglenn.lagasse@oracle.com }
190013013Sglenn.lagasse@oracle.com 
190113013Sglenn.lagasse@oracle.com /*
190213013Sglenn.lagasse@oracle.com  * Function:	be_update_zone_vfstab
190313013Sglenn.lagasse@oracle.com  * Description:	This function digs into a zone BE's vfstab and updates all
190413013Sglenn.lagasse@oracle.com  *		entries with file systems listed in be_fs_list_data_t.
190513013Sglenn.lagasse@oracle.com  *		The entry's root container dataset and be_name will be
190613013Sglenn.lagasse@oracle.com  *		updated with the parameters passed in.
190713013Sglenn.lagasse@oracle.com  * Parameters:
190813013Sglenn.lagasse@oracle.com  *		zhp - zfs_handle_t pointer to zone root dataset.
190913013Sglenn.lagasse@oracle.com  *		be_name - name of zone BE to update
191013013Sglenn.lagasse@oracle.com  *		old_rc_loc - dataset under which the root container dataset
191113013Sglenn.lagasse@oracle.com  *			of the old zone BE resides in.
191213013Sglenn.lagasse@oracle.com  *		new_rc_loc - dataset under which the root container dataset
191313013Sglenn.lagasse@oracle.com  *			of the new zone BE resides in.
191413013Sglenn.lagasse@oracle.com  *		fld - be_fs_list_data_t pointer providing the list of
191513013Sglenn.lagasse@oracle.com  *			file systems to look for in vfstab.
191613013Sglenn.lagasse@oracle.com  * Returns:
191713013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
191813013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
191913013Sglenn.lagasse@oracle.com  * Scope:
192013013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
192113013Sglenn.lagasse@oracle.com  */
192213013Sglenn.lagasse@oracle.com int
be_update_zone_vfstab(zfs_handle_t * zhp,char * be_name,char * old_rc_loc,char * new_rc_loc,be_fs_list_data_t * fld)192313013Sglenn.lagasse@oracle.com be_update_zone_vfstab(zfs_handle_t *zhp, char *be_name, char *old_rc_loc,
192413013Sglenn.lagasse@oracle.com     char *new_rc_loc, be_fs_list_data_t *fld)
192513013Sglenn.lagasse@oracle.com {
192613013Sglenn.lagasse@oracle.com 	be_mount_data_t		md = { 0 };
192713013Sglenn.lagasse@oracle.com 	be_unmount_data_t	ud = { 0 };
192813013Sglenn.lagasse@oracle.com 	char			alt_vfstab[MAXPATHLEN];
192913013Sglenn.lagasse@oracle.com 	boolean_t		mounted_here = B_FALSE;
193013013Sglenn.lagasse@oracle.com 	int			ret = BE_SUCCESS;
193113013Sglenn.lagasse@oracle.com 
193213013Sglenn.lagasse@oracle.com 	/*
193313013Sglenn.lagasse@oracle.com 	 * If zone root not already mounted, mount it at a
193413013Sglenn.lagasse@oracle.com 	 * temporary location.
193513013Sglenn.lagasse@oracle.com 	 */
193613013Sglenn.lagasse@oracle.com 	if (!zfs_is_mounted(zhp, &md.altroot)) {
193713013Sglenn.lagasse@oracle.com 		/* Generate temporary mountpoint to mount zone root */
193813013Sglenn.lagasse@oracle.com 		if ((ret = be_make_tmp_mountpoint(&md.altroot)) != BE_SUCCESS) {
193913013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_update_zone_vfstab: "
194013013Sglenn.lagasse@oracle.com 			    "failed to make temporary mountpoint to "
194113013Sglenn.lagasse@oracle.com 			    "mount zone root\n"));
194213013Sglenn.lagasse@oracle.com 			return (ret);
194313013Sglenn.lagasse@oracle.com 		}
194413013Sglenn.lagasse@oracle.com 
194513013Sglenn.lagasse@oracle.com 		if (be_mount_zone_root(zhp, &md) != BE_SUCCESS) {
194613013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_update_zone_vfstab: "
194713013Sglenn.lagasse@oracle.com 			    "failed to mount zone root %s\n"),
194813013Sglenn.lagasse@oracle.com 			    zfs_get_name(zhp));
194913013Sglenn.lagasse@oracle.com 			free(md.altroot);
195013013Sglenn.lagasse@oracle.com 			return (BE_ERR_MOUNT_ZONEROOT);
195113013Sglenn.lagasse@oracle.com 		}
195213013Sglenn.lagasse@oracle.com 		mounted_here = B_TRUE;
195313013Sglenn.lagasse@oracle.com 	}
195413013Sglenn.lagasse@oracle.com 
195513013Sglenn.lagasse@oracle.com 	/* Get string from vfstab in the mounted zone BE */
195613013Sglenn.lagasse@oracle.com 	(void) snprintf(alt_vfstab, sizeof (alt_vfstab), "%s/etc/vfstab",
195713013Sglenn.lagasse@oracle.com 	    md.altroot);
195813013Sglenn.lagasse@oracle.com 
195913013Sglenn.lagasse@oracle.com 	/* Update the vfstab */
196013013Sglenn.lagasse@oracle.com 	ret = _update_vfstab(alt_vfstab, be_name, old_rc_loc, new_rc_loc,
196113013Sglenn.lagasse@oracle.com 	    fld);
196213013Sglenn.lagasse@oracle.com 
196313013Sglenn.lagasse@oracle.com 	/* Unmount zone root if we mounted it */
196413013Sglenn.lagasse@oracle.com 	if (mounted_here) {
196513013Sglenn.lagasse@oracle.com 		ud.force = B_TRUE;
196613013Sglenn.lagasse@oracle.com 
196713013Sglenn.lagasse@oracle.com 		if (be_unmount_zone_root(zhp, &ud) == BE_SUCCESS) {
196813013Sglenn.lagasse@oracle.com 			/* Remove the temporary mountpoint */
196913013Sglenn.lagasse@oracle.com 			(void) rmdir(md.altroot);
197013013Sglenn.lagasse@oracle.com 		} else {
197113013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_update_zone_vfstab: "
197213013Sglenn.lagasse@oracle.com 			    "failed to unmount zone root %s from %s\n"),
197313013Sglenn.lagasse@oracle.com 			    zfs_get_name(zhp), md.altroot);
197413013Sglenn.lagasse@oracle.com 			if (ret == 0)
197513013Sglenn.lagasse@oracle.com 				ret = BE_ERR_UMOUNT_ZONEROOT;
197613013Sglenn.lagasse@oracle.com 		}
197713013Sglenn.lagasse@oracle.com 	}
197813013Sglenn.lagasse@oracle.com 
197913013Sglenn.lagasse@oracle.com 	free(md.altroot);
198013013Sglenn.lagasse@oracle.com 	return (ret);
198113013Sglenn.lagasse@oracle.com }
198213013Sglenn.lagasse@oracle.com 
198313013Sglenn.lagasse@oracle.com /*
198413013Sglenn.lagasse@oracle.com  * Function:	be_auto_snap_name
198513013Sglenn.lagasse@oracle.com  * Description:	Generate an auto snapshot name constructed based on the
198613013Sglenn.lagasse@oracle.com  *		current date and time.  The auto snapshot name is of the form:
198713013Sglenn.lagasse@oracle.com  *
198813013Sglenn.lagasse@oracle.com  *			<date>-<time>
198913013Sglenn.lagasse@oracle.com  *
199013013Sglenn.lagasse@oracle.com  *		where <date> is in ISO standard format, so the resultant name
199113013Sglenn.lagasse@oracle.com  *		is of the form:
199213013Sglenn.lagasse@oracle.com  *
199313013Sglenn.lagasse@oracle.com  *			%Y-%m-%d-%H:%M:%S
199413013Sglenn.lagasse@oracle.com  *
199513013Sglenn.lagasse@oracle.com  * Parameters:
199613013Sglenn.lagasse@oracle.com  *		None
199713013Sglenn.lagasse@oracle.com  * Returns:
199813013Sglenn.lagasse@oracle.com  *		Success - pointer to auto generated snapshot name.  The name
199913013Sglenn.lagasse@oracle.com  *			is allocated in heap storage so the caller is
200013013Sglenn.lagasse@oracle.com  *			responsible for free'ing the name.
200113013Sglenn.lagasse@oracle.com  *		Failure - NULL
200213013Sglenn.lagasse@oracle.com  * Scope:
200313013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
200413013Sglenn.lagasse@oracle.com  */
200513013Sglenn.lagasse@oracle.com char *
be_auto_snap_name(void)200613013Sglenn.lagasse@oracle.com be_auto_snap_name(void)
200713013Sglenn.lagasse@oracle.com {
200813013Sglenn.lagasse@oracle.com 	time_t		utc_tm = NULL;
200913013Sglenn.lagasse@oracle.com 	struct tm	*gmt_tm = NULL;
201013013Sglenn.lagasse@oracle.com 	char		gmt_time_str[64];
201113013Sglenn.lagasse@oracle.com 	char		*auto_snap_name = NULL;
201213013Sglenn.lagasse@oracle.com 
201313013Sglenn.lagasse@oracle.com 	if (time(&utc_tm) == -1) {
201413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_auto_snap_name: time() failed\n"));
201513013Sglenn.lagasse@oracle.com 		return (NULL);
201613013Sglenn.lagasse@oracle.com 	}
201713013Sglenn.lagasse@oracle.com 
201813013Sglenn.lagasse@oracle.com 	if ((gmt_tm = gmtime(&utc_tm)) == NULL) {
201913013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_auto_snap_name: gmtime() failed\n"));
202013013Sglenn.lagasse@oracle.com 		return (NULL);
202113013Sglenn.lagasse@oracle.com 	}
202213013Sglenn.lagasse@oracle.com 
202313013Sglenn.lagasse@oracle.com 	(void) strftime(gmt_time_str, sizeof (gmt_time_str), "%F-%T", gmt_tm);
202413013Sglenn.lagasse@oracle.com 
202513013Sglenn.lagasse@oracle.com 	if ((auto_snap_name = strdup(gmt_time_str)) == NULL) {
202613013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_auto_snap_name: "
202713013Sglenn.lagasse@oracle.com 		    "memory allocation failed\n"));
202813013Sglenn.lagasse@oracle.com 		return (NULL);
202913013Sglenn.lagasse@oracle.com 	}
203013013Sglenn.lagasse@oracle.com 
203113013Sglenn.lagasse@oracle.com 	return (auto_snap_name);
203213013Sglenn.lagasse@oracle.com }
203313013Sglenn.lagasse@oracle.com 
203413013Sglenn.lagasse@oracle.com /*
203513013Sglenn.lagasse@oracle.com  * Function:	be_auto_be_name
203613013Sglenn.lagasse@oracle.com  * Description:	Generate an auto BE name constructed based on the BE name
203713013Sglenn.lagasse@oracle.com  *		of the original BE being cloned.
203813013Sglenn.lagasse@oracle.com  * Parameters:
203913013Sglenn.lagasse@oracle.com  *		obe_name - name of the original BE being cloned.
204013013Sglenn.lagasse@oracle.com  * Returns:
204113013Sglenn.lagasse@oracle.com  *		Success - pointer to auto generated BE name.  The name
204213013Sglenn.lagasse@oracle.com  *			is allocated in heap storage so the caller is
204313013Sglenn.lagasse@oracle.com  *			responsible for free'ing the name.
204413013Sglenn.lagasse@oracle.com  *		Failure - NULL
204513013Sglenn.lagasse@oracle.com  * Scope:
204613013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
204713013Sglenn.lagasse@oracle.com  */
204813013Sglenn.lagasse@oracle.com char *
be_auto_be_name(char * obe_name)204913013Sglenn.lagasse@oracle.com be_auto_be_name(char *obe_name)
205013013Sglenn.lagasse@oracle.com {
205113013Sglenn.lagasse@oracle.com 	return (be_get_auto_name(obe_name, NULL, B_FALSE));
205213013Sglenn.lagasse@oracle.com }
205313013Sglenn.lagasse@oracle.com 
205413013Sglenn.lagasse@oracle.com /*
205513013Sglenn.lagasse@oracle.com  * Function:	be_auto_zone_be_name
205613013Sglenn.lagasse@oracle.com  * Description:	Generate an auto BE name for a zone constructed based on
205713013Sglenn.lagasse@oracle.com  *              the BE name of the original zone BE being cloned.
205813013Sglenn.lagasse@oracle.com  * Parameters:
205913013Sglenn.lagasse@oracle.com  *              container_ds - container dataset for the zone.
206013013Sglenn.lagasse@oracle.com  *		zbe_name - name of the original zone BE being cloned.
206113013Sglenn.lagasse@oracle.com  * Returns:
206213013Sglenn.lagasse@oracle.com  *		Success - pointer to auto generated BE name.  The name
206313013Sglenn.lagasse@oracle.com  *			is allocated in heap storage so the caller is
206413013Sglenn.lagasse@oracle.com  *			responsible for free'ing the name.
206513013Sglenn.lagasse@oracle.com  *		Failure - NULL
206613013Sglenn.lagasse@oracle.com  * Scope:
206713013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
206813013Sglenn.lagasse@oracle.com  */
206913013Sglenn.lagasse@oracle.com char *
be_auto_zone_be_name(char * container_ds,char * zbe_name)207013013Sglenn.lagasse@oracle.com be_auto_zone_be_name(char *container_ds, char *zbe_name)
207113013Sglenn.lagasse@oracle.com {
207213013Sglenn.lagasse@oracle.com 	return (be_get_auto_name(zbe_name, container_ds, B_TRUE));
207313013Sglenn.lagasse@oracle.com }
207413013Sglenn.lagasse@oracle.com 
207513013Sglenn.lagasse@oracle.com /*
207613013Sglenn.lagasse@oracle.com  * Function:	be_valid_be_name
207713013Sglenn.lagasse@oracle.com  * Description:	Validates a BE name.
207813013Sglenn.lagasse@oracle.com  * Parameters:
207913013Sglenn.lagasse@oracle.com  *		be_name - name of BE to validate
208013013Sglenn.lagasse@oracle.com  * Returns:
208113013Sglenn.lagasse@oracle.com  *		B_TRUE - be_name is valid
208213013Sglenn.lagasse@oracle.com  *		B_FALSE - be_name is invalid
208313013Sglenn.lagasse@oracle.com  * Scope:
208413013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
208513013Sglenn.lagasse@oracle.com  */
208613013Sglenn.lagasse@oracle.com 
208713013Sglenn.lagasse@oracle.com boolean_t
be_valid_be_name(const char * be_name)208813013Sglenn.lagasse@oracle.com be_valid_be_name(const char *be_name)
208913013Sglenn.lagasse@oracle.com {
209013013Sglenn.lagasse@oracle.com 	const char	*c = NULL;
209113013Sglenn.lagasse@oracle.com 
209213013Sglenn.lagasse@oracle.com 	if (be_name == NULL)
209313013Sglenn.lagasse@oracle.com 		return (B_FALSE);
209413013Sglenn.lagasse@oracle.com 
209513013Sglenn.lagasse@oracle.com 	/*
209613013Sglenn.lagasse@oracle.com 	 * A BE name must not be a multi-level dataset name.  We also check
209713013Sglenn.lagasse@oracle.com 	 * that it does not contain the ' ' and '%' characters.  The ' ' is
209813013Sglenn.lagasse@oracle.com 	 * a valid character for datasets, however we don't allow that in a
209913013Sglenn.lagasse@oracle.com 	 * BE name.  The '%' is invalid, but zfs_name_valid() allows it for
210013013Sglenn.lagasse@oracle.com 	 * internal reasons, so we explicitly check for it here.
210113013Sglenn.lagasse@oracle.com 	 */
210213013Sglenn.lagasse@oracle.com 	c = be_name;
210313013Sglenn.lagasse@oracle.com 	while (*c != '\0' && *c != '/' && *c != ' ' && *c != '%')
210413013Sglenn.lagasse@oracle.com 		c++;
210513013Sglenn.lagasse@oracle.com 
210613013Sglenn.lagasse@oracle.com 	if (*c != '\0')
210713013Sglenn.lagasse@oracle.com 		return (B_FALSE);
210813013Sglenn.lagasse@oracle.com 
210913013Sglenn.lagasse@oracle.com 	/*
211013013Sglenn.lagasse@oracle.com 	 * The BE name must comply with a zfs dataset filesystem. We also
211113013Sglenn.lagasse@oracle.com 	 * verify its length to be < BE_NAME_MAX_LEN.
211213013Sglenn.lagasse@oracle.com 	 */
211313013Sglenn.lagasse@oracle.com 	if (!zfs_name_valid(be_name, ZFS_TYPE_FILESYSTEM) ||
211413013Sglenn.lagasse@oracle.com 	    strlen(be_name) > BE_NAME_MAX_LEN)
211513013Sglenn.lagasse@oracle.com 		return (B_FALSE);
211613013Sglenn.lagasse@oracle.com 
211713013Sglenn.lagasse@oracle.com 	return (B_TRUE);
211813013Sglenn.lagasse@oracle.com }
211913013Sglenn.lagasse@oracle.com 
212013013Sglenn.lagasse@oracle.com /*
212113013Sglenn.lagasse@oracle.com  * Function:	be_valid_auto_snap_name
212213013Sglenn.lagasse@oracle.com  * Description:	This function checks that a snapshot name is a valid auto
212313013Sglenn.lagasse@oracle.com  *		generated snapshot name.  A valid auto generated snapshot
212413013Sglenn.lagasse@oracle.com  *		name is of the form:
212513013Sglenn.lagasse@oracle.com  *
212613013Sglenn.lagasse@oracle.com  *			%Y-%m-%d-%H:%M:%S
212713013Sglenn.lagasse@oracle.com  *
212813013Sglenn.lagasse@oracle.com  *		An older form of the auto generated snapshot name also
212913013Sglenn.lagasse@oracle.com  *		included the snapshot's BE cleanup policy and a reserved
213013013Sglenn.lagasse@oracle.com  *		field.  Those names will also be verified by this function.
213113013Sglenn.lagasse@oracle.com  *
213213013Sglenn.lagasse@oracle.com  *		Examples of valid auto snapshot names are:
213313013Sglenn.lagasse@oracle.com  *
213413013Sglenn.lagasse@oracle.com  *			2008-03-31-18:41:30
213513013Sglenn.lagasse@oracle.com  *			2008-03-31-22:17:24
213613013Sglenn.lagasse@oracle.com  *			<policy>:-:2008:04-05-09:12:55
213713013Sglenn.lagasse@oracle.com  *			<policy>:-:2008:04-06-15:34:12
213813013Sglenn.lagasse@oracle.com  *
213913013Sglenn.lagasse@oracle.com  * Parameters:
214013013Sglenn.lagasse@oracle.com  *		name - name of the snapshot to be validated.
214113013Sglenn.lagasse@oracle.com  * Returns:
214213013Sglenn.lagasse@oracle.com  *		B_TRUE - the name is a valid auto snapshot name.
214313013Sglenn.lagasse@oracle.com  *		B_FALSE - the name is not a valid auto snapshot name.
214413013Sglenn.lagasse@oracle.com  * Scope:
214513013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
214613013Sglenn.lagasse@oracle.com  */
214713013Sglenn.lagasse@oracle.com boolean_t
be_valid_auto_snap_name(char * name)214813013Sglenn.lagasse@oracle.com be_valid_auto_snap_name(char *name)
214913013Sglenn.lagasse@oracle.com {
215013013Sglenn.lagasse@oracle.com 	struct tm gmt_tm;
215113013Sglenn.lagasse@oracle.com 
215213013Sglenn.lagasse@oracle.com 	char *policy = NULL;
215313013Sglenn.lagasse@oracle.com 	char *reserved = NULL;
215413013Sglenn.lagasse@oracle.com 	char *date = NULL;
215513013Sglenn.lagasse@oracle.com 	char *c = NULL;
215613013Sglenn.lagasse@oracle.com 
215713013Sglenn.lagasse@oracle.com 	/* Validate the snapshot name by converting it into utc time */
215813013Sglenn.lagasse@oracle.com 	if (strptime(name, "%Y-%m-%d-%T", &gmt_tm) != NULL &&
215913013Sglenn.lagasse@oracle.com 	    (mktime(&gmt_tm) != -1)) {
216013013Sglenn.lagasse@oracle.com 		return (B_TRUE);
216113013Sglenn.lagasse@oracle.com 	}
216213013Sglenn.lagasse@oracle.com 
216313013Sglenn.lagasse@oracle.com 	/*
216413013Sglenn.lagasse@oracle.com 	 * Validate the snapshot name against the older form of an
216513013Sglenn.lagasse@oracle.com 	 * auto generated snapshot name.
216613013Sglenn.lagasse@oracle.com 	 */
216713013Sglenn.lagasse@oracle.com 	policy = strdup(name);
216813013Sglenn.lagasse@oracle.com 
216913013Sglenn.lagasse@oracle.com 	/*
217013013Sglenn.lagasse@oracle.com 	 * Get the first field from the snapshot name,
217113013Sglenn.lagasse@oracle.com 	 * which is the BE policy
217213013Sglenn.lagasse@oracle.com 	 */
217313013Sglenn.lagasse@oracle.com 	c = strchr(policy, ':');
217413013Sglenn.lagasse@oracle.com 	if (c == NULL) {
217513013Sglenn.lagasse@oracle.com 		free(policy);
217613013Sglenn.lagasse@oracle.com 		return (B_FALSE);
217713013Sglenn.lagasse@oracle.com 	}
217813013Sglenn.lagasse@oracle.com 	c[0] = '\0';
217913013Sglenn.lagasse@oracle.com 
218013013Sglenn.lagasse@oracle.com 	/* Validate the policy name */
218113013Sglenn.lagasse@oracle.com 	if (!valid_be_policy(policy)) {
218213013Sglenn.lagasse@oracle.com 		free(policy);
218313013Sglenn.lagasse@oracle.com 		return (B_FALSE);
218413013Sglenn.lagasse@oracle.com 	}
218513013Sglenn.lagasse@oracle.com 
218613013Sglenn.lagasse@oracle.com 	/* Get the next field, which is the reserved field. */
218713013Sglenn.lagasse@oracle.com 	if (c[1] == NULL || c[1] == '\0') {
218813013Sglenn.lagasse@oracle.com 		free(policy);
218913013Sglenn.lagasse@oracle.com 		return (B_FALSE);
219013013Sglenn.lagasse@oracle.com 	}
219113013Sglenn.lagasse@oracle.com 	reserved = c+1;
219213013Sglenn.lagasse@oracle.com 	c = strchr(reserved, ':');
219313013Sglenn.lagasse@oracle.com 	if (c == NULL) {
219413013Sglenn.lagasse@oracle.com 		free(policy);
219513013Sglenn.lagasse@oracle.com 		return (B_FALSE);
219613013Sglenn.lagasse@oracle.com 	}
219713013Sglenn.lagasse@oracle.com 	c[0] = '\0';
219813013Sglenn.lagasse@oracle.com 
219913013Sglenn.lagasse@oracle.com 	/* Validate the reserved field */
220013013Sglenn.lagasse@oracle.com 	if (strcmp(reserved, "-") != 0) {
220113013Sglenn.lagasse@oracle.com 		free(policy);
220213013Sglenn.lagasse@oracle.com 		return (B_FALSE);
220313013Sglenn.lagasse@oracle.com 	}
220413013Sglenn.lagasse@oracle.com 
220513013Sglenn.lagasse@oracle.com 	/* The remaining string should be the date field */
220613013Sglenn.lagasse@oracle.com 	if (c[1] == NULL || c[1] == '\0') {
220713013Sglenn.lagasse@oracle.com 		free(policy);
220813013Sglenn.lagasse@oracle.com 		return (B_FALSE);
220913013Sglenn.lagasse@oracle.com 	}
221013013Sglenn.lagasse@oracle.com 	date = c+1;
221113013Sglenn.lagasse@oracle.com 
221213013Sglenn.lagasse@oracle.com 	/* Validate the date string by converting it into utc time */
221313013Sglenn.lagasse@oracle.com 	if (strptime(date, "%Y-%m-%d-%T", &gmt_tm) == NULL ||
221413013Sglenn.lagasse@oracle.com 	    (mktime(&gmt_tm) == -1)) {
221513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_valid_auto_snap_name: "
221613013Sglenn.lagasse@oracle.com 		    "invalid auto snapshot name\n"));
221713013Sglenn.lagasse@oracle.com 		free(policy);
221813013Sglenn.lagasse@oracle.com 		return (B_FALSE);
221913013Sglenn.lagasse@oracle.com 	}
222013013Sglenn.lagasse@oracle.com 
222113013Sglenn.lagasse@oracle.com 	free(policy);
222213013Sglenn.lagasse@oracle.com 	return (B_TRUE);
222313013Sglenn.lagasse@oracle.com }
222413013Sglenn.lagasse@oracle.com 
222513013Sglenn.lagasse@oracle.com /*
222613013Sglenn.lagasse@oracle.com  * Function:	be_default_policy
222713013Sglenn.lagasse@oracle.com  * Description:	Temporary hardcoded policy support.  This function returns
222813013Sglenn.lagasse@oracle.com  *		the default policy type to be used to create a BE or a BE
222913013Sglenn.lagasse@oracle.com  *		snapshot.
223013013Sglenn.lagasse@oracle.com  * Parameters:
223113013Sglenn.lagasse@oracle.com  *		None
223213013Sglenn.lagasse@oracle.com  * Returns:
223313013Sglenn.lagasse@oracle.com  *		Name of default BE policy.
223413013Sglenn.lagasse@oracle.com  * Scope:
223513013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
223613013Sglenn.lagasse@oracle.com  */
223713013Sglenn.lagasse@oracle.com char *
be_default_policy(void)223813013Sglenn.lagasse@oracle.com be_default_policy(void)
223913013Sglenn.lagasse@oracle.com {
224013013Sglenn.lagasse@oracle.com 	return (BE_PLCY_STATIC);
224113013Sglenn.lagasse@oracle.com }
224213013Sglenn.lagasse@oracle.com 
224313013Sglenn.lagasse@oracle.com /*
224413013Sglenn.lagasse@oracle.com  * Function:	valid_be_policy
224513013Sglenn.lagasse@oracle.com  * Description:	Temporary hardcoded policy support.  This function valids
224613013Sglenn.lagasse@oracle.com  *		whether a policy is a valid known policy or not.
224713013Sglenn.lagasse@oracle.com  * Paramters:
224813013Sglenn.lagasse@oracle.com  *		policy - name of policy to validate.
224913013Sglenn.lagasse@oracle.com  * Returns:
225013013Sglenn.lagasse@oracle.com  *		B_TRUE - policy is a valid.
225113013Sglenn.lagasse@oracle.com  *		B_FALSE - policy is invalid.
225213013Sglenn.lagasse@oracle.com  * Scope:
225313013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
225413013Sglenn.lagasse@oracle.com  */
225513013Sglenn.lagasse@oracle.com boolean_t
valid_be_policy(char * policy)225613013Sglenn.lagasse@oracle.com valid_be_policy(char *policy)
225713013Sglenn.lagasse@oracle.com {
225813013Sglenn.lagasse@oracle.com 	if (policy == NULL)
225913013Sglenn.lagasse@oracle.com 		return (B_FALSE);
226013013Sglenn.lagasse@oracle.com 
226113013Sglenn.lagasse@oracle.com 	if (strcmp(policy, BE_PLCY_STATIC) == 0 ||
226213013Sglenn.lagasse@oracle.com 	    strcmp(policy, BE_PLCY_VOLATILE) == 0) {
226313013Sglenn.lagasse@oracle.com 		return (B_TRUE);
226413013Sglenn.lagasse@oracle.com 	}
226513013Sglenn.lagasse@oracle.com 
226613013Sglenn.lagasse@oracle.com 	return (B_FALSE);
226713013Sglenn.lagasse@oracle.com }
226813013Sglenn.lagasse@oracle.com 
226913013Sglenn.lagasse@oracle.com /*
227013013Sglenn.lagasse@oracle.com  * Function:	be_print_err
227113013Sglenn.lagasse@oracle.com  * Description:	This function prints out error messages if do_print is
227213013Sglenn.lagasse@oracle.com  *		set to B_TRUE or if the BE_PRINT_ERR environment variable
227313013Sglenn.lagasse@oracle.com  *		is set to true.
227413013Sglenn.lagasse@oracle.com  * Paramters:
227513013Sglenn.lagasse@oracle.com  *		prnt_str - the string we wish to print and any arguments
227613013Sglenn.lagasse@oracle.com  *		for the format of that string.
227713013Sglenn.lagasse@oracle.com  * Returns:
227813013Sglenn.lagasse@oracle.com  *		void
227913013Sglenn.lagasse@oracle.com  * Scope:
228013013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
228113013Sglenn.lagasse@oracle.com  */
228213013Sglenn.lagasse@oracle.com void
be_print_err(char * prnt_str,...)228313013Sglenn.lagasse@oracle.com be_print_err(char *prnt_str, ...)
228413013Sglenn.lagasse@oracle.com {
228513013Sglenn.lagasse@oracle.com 	va_list ap;
228613013Sglenn.lagasse@oracle.com 	char buf[BUFSIZ];
228713013Sglenn.lagasse@oracle.com 	char *env_buf;
228813013Sglenn.lagasse@oracle.com 	static boolean_t env_checked = B_FALSE;
228913013Sglenn.lagasse@oracle.com 
229013013Sglenn.lagasse@oracle.com 	if (!env_checked) {
229113013Sglenn.lagasse@oracle.com 		if ((env_buf = getenv("BE_PRINT_ERR")) != NULL) {
229213013Sglenn.lagasse@oracle.com 			if (strcasecmp(env_buf, "true") == 0) {
229313013Sglenn.lagasse@oracle.com 				do_print = B_TRUE;
229413013Sglenn.lagasse@oracle.com 			}
229513013Sglenn.lagasse@oracle.com 		}
229613013Sglenn.lagasse@oracle.com 		env_checked = B_TRUE;
229713013Sglenn.lagasse@oracle.com 	}
229813013Sglenn.lagasse@oracle.com 
229913013Sglenn.lagasse@oracle.com 	if (do_print) {
230013013Sglenn.lagasse@oracle.com 		va_start(ap, prnt_str);
230113013Sglenn.lagasse@oracle.com 		/* LINTED variable format specifier */
230213013Sglenn.lagasse@oracle.com 		(void) vsnprintf(buf, BUFSIZ, prnt_str, ap);
230313013Sglenn.lagasse@oracle.com 		(void) fputs(buf, stderr);
230413013Sglenn.lagasse@oracle.com 		va_end(ap);
230513013Sglenn.lagasse@oracle.com 	}
230613013Sglenn.lagasse@oracle.com }
230713013Sglenn.lagasse@oracle.com 
230813013Sglenn.lagasse@oracle.com /*
230913013Sglenn.lagasse@oracle.com  * Function:	be_find_current_be
231013013Sglenn.lagasse@oracle.com  * Description:	Find the currently "active" BE. Fill in the
231113013Sglenn.lagasse@oracle.com  * 		passed in be_transaction_data_t reference with the
231213013Sglenn.lagasse@oracle.com  *		active BE's data.
231313013Sglenn.lagasse@oracle.com  * Paramters:
231413013Sglenn.lagasse@oracle.com  *		none
231513013Sglenn.lagasse@oracle.com  * Returns:
231613013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
231713013Sglenn.lagasse@oracle.com  *		be_errnot_t - Failure
231813013Sglenn.lagasse@oracle.com  * Scope:
231913013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
232013013Sglenn.lagasse@oracle.com  * Notes:
232113013Sglenn.lagasse@oracle.com  *		The caller is responsible for initializing the libzfs handle
232213013Sglenn.lagasse@oracle.com  *		and freeing the memory used by the active be_name.
232313013Sglenn.lagasse@oracle.com  */
232413013Sglenn.lagasse@oracle.com int
be_find_current_be(be_transaction_data_t * bt)232513013Sglenn.lagasse@oracle.com be_find_current_be(be_transaction_data_t *bt)
232613013Sglenn.lagasse@oracle.com {
232713013Sglenn.lagasse@oracle.com 	int	zret;
232813013Sglenn.lagasse@oracle.com 
232913013Sglenn.lagasse@oracle.com 	if ((zret = zpool_iter(g_zfs, be_zpool_find_current_be_callback,
233013013Sglenn.lagasse@oracle.com 	    bt)) == 0) {
233113013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_find_current_be: failed to "
233213013Sglenn.lagasse@oracle.com 		    "find current BE name\n"));
233313013Sglenn.lagasse@oracle.com 		return (BE_ERR_BE_NOENT);
233413013Sglenn.lagasse@oracle.com 	} else if (zret < 0) {
233513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_find_current_be: "
233613013Sglenn.lagasse@oracle.com 		    "zpool_iter failed: %s\n"),
233713013Sglenn.lagasse@oracle.com 		    libzfs_error_description(g_zfs));
233813013Sglenn.lagasse@oracle.com 		return (zfs_err_to_be_err(g_zfs));
233913013Sglenn.lagasse@oracle.com 	}
234013013Sglenn.lagasse@oracle.com 
234113013Sglenn.lagasse@oracle.com 	return (BE_SUCCESS);
234213013Sglenn.lagasse@oracle.com }
234313013Sglenn.lagasse@oracle.com 
234413013Sglenn.lagasse@oracle.com /*
234513013Sglenn.lagasse@oracle.com  * Function:	be_zpool_find_current_be_callback
234613013Sglenn.lagasse@oracle.com  * Description: Callback function used to iterate through all existing pools
234713013Sglenn.lagasse@oracle.com  *		to find the BE that is the currently booted BE.
234813013Sglenn.lagasse@oracle.com  * Parameters:
234913013Sglenn.lagasse@oracle.com  *		zlp - zpool_handle_t pointer to the current pool being
235013013Sglenn.lagasse@oracle.com  *			looked at.
235113013Sglenn.lagasse@oracle.com  *		data - be_transaction_data_t pointer.
235213013Sglenn.lagasse@oracle.com  *			Upon successfully finding the current BE, the
235313013Sglenn.lagasse@oracle.com  *			obe_zpool member of this parameter is set to the
235413013Sglenn.lagasse@oracle.com  *			pool it is found in.
235513013Sglenn.lagasse@oracle.com  * Return:
235613013Sglenn.lagasse@oracle.com  *		1 - Found current BE in this pool.
235713013Sglenn.lagasse@oracle.com  *		0 - Did not find current BE in this pool.
235813013Sglenn.lagasse@oracle.com  * Scope:
235913013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
236013013Sglenn.lagasse@oracle.com  */
236113013Sglenn.lagasse@oracle.com int
be_zpool_find_current_be_callback(zpool_handle_t * zlp,void * data)236213013Sglenn.lagasse@oracle.com be_zpool_find_current_be_callback(zpool_handle_t *zlp, void *data)
236313013Sglenn.lagasse@oracle.com {
236413013Sglenn.lagasse@oracle.com 	be_transaction_data_t	*bt = data;
236513013Sglenn.lagasse@oracle.com 	zfs_handle_t		*zhp = NULL;
236613013Sglenn.lagasse@oracle.com 	const char		*zpool =  zpool_get_name(zlp);
236713013Sglenn.lagasse@oracle.com 	char			be_container_ds[MAXPATHLEN];
236813013Sglenn.lagasse@oracle.com 
236913013Sglenn.lagasse@oracle.com 	/*
237013013Sglenn.lagasse@oracle.com 	 * Generate string for BE container dataset
237113013Sglenn.lagasse@oracle.com 	 */
237213013Sglenn.lagasse@oracle.com 	be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds));
237313013Sglenn.lagasse@oracle.com 
237413013Sglenn.lagasse@oracle.com 	/*
237513013Sglenn.lagasse@oracle.com 	 * Check if a BE container dataset exists in this pool.
237613013Sglenn.lagasse@oracle.com 	 */
237713013Sglenn.lagasse@oracle.com 	if (!zfs_dataset_exists(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) {
237813013Sglenn.lagasse@oracle.com 		zpool_close(zlp);
237913013Sglenn.lagasse@oracle.com 		return (0);
238013013Sglenn.lagasse@oracle.com 	}
238113013Sglenn.lagasse@oracle.com 
238213013Sglenn.lagasse@oracle.com 	/*
238313013Sglenn.lagasse@oracle.com 	 * Get handle to this zpool's BE container dataset.
238413013Sglenn.lagasse@oracle.com 	 */
238513013Sglenn.lagasse@oracle.com 	if ((zhp = zfs_open(g_zfs, be_container_ds, ZFS_TYPE_FILESYSTEM)) ==
238613013Sglenn.lagasse@oracle.com 	    NULL) {
238713013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_zpool_find_current_be_callback: "
238813013Sglenn.lagasse@oracle.com 		    "failed to open BE container dataset (%s)\n"),
238913013Sglenn.lagasse@oracle.com 		    be_container_ds);
239013013Sglenn.lagasse@oracle.com 		zpool_close(zlp);
239113013Sglenn.lagasse@oracle.com 		return (0);
239213013Sglenn.lagasse@oracle.com 	}
239313013Sglenn.lagasse@oracle.com 
239413013Sglenn.lagasse@oracle.com 	/*
239513013Sglenn.lagasse@oracle.com 	 * Iterate through all potential BEs in this zpool
239613013Sglenn.lagasse@oracle.com 	 */
239713013Sglenn.lagasse@oracle.com 	if (zfs_iter_filesystems(zhp, be_zfs_find_current_be_callback, bt)) {
239813013Sglenn.lagasse@oracle.com 		/*
239913013Sglenn.lagasse@oracle.com 		 * Found current BE dataset; set obe_zpool
240013013Sglenn.lagasse@oracle.com 		 */
240113013Sglenn.lagasse@oracle.com 		if ((bt->obe_zpool = strdup(zpool)) == NULL) {
240213013Sglenn.lagasse@oracle.com 			be_print_err(gettext(
240313013Sglenn.lagasse@oracle.com 			    "be_zpool_find_current_be_callback: "
240413013Sglenn.lagasse@oracle.com 			    "memory allocation failed\n"));
240513013Sglenn.lagasse@oracle.com 			ZFS_CLOSE(zhp);
240613013Sglenn.lagasse@oracle.com 			zpool_close(zlp);
240713013Sglenn.lagasse@oracle.com 			return (0);
240813013Sglenn.lagasse@oracle.com 		}
240913013Sglenn.lagasse@oracle.com 
241013013Sglenn.lagasse@oracle.com 		ZFS_CLOSE(zhp);
241113013Sglenn.lagasse@oracle.com 		zpool_close(zlp);
241213013Sglenn.lagasse@oracle.com 		return (1);
241313013Sglenn.lagasse@oracle.com 	}
241413013Sglenn.lagasse@oracle.com 
241513013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
241613013Sglenn.lagasse@oracle.com 	zpool_close(zlp);
241713013Sglenn.lagasse@oracle.com 
241813013Sglenn.lagasse@oracle.com 	return (0);
241913013Sglenn.lagasse@oracle.com }
242013013Sglenn.lagasse@oracle.com 
242113013Sglenn.lagasse@oracle.com /*
242213013Sglenn.lagasse@oracle.com  * Function:	be_zfs_find_current_be_callback
242313013Sglenn.lagasse@oracle.com  * Description:	Callback function used to iterate through all BEs in a
242413013Sglenn.lagasse@oracle.com  *		pool to find the BE that is the currently booted BE.
242513013Sglenn.lagasse@oracle.com  * Parameters:
242613013Sglenn.lagasse@oracle.com  *		zhp - zfs_handle_t pointer to current filesystem being checked.
242713013Sglenn.lagasse@oracle.com  *		data - be_transaction-data_t pointer
242813013Sglenn.lagasse@oracle.com  *			Upon successfully finding the current BE, the
242913013Sglenn.lagasse@oracle.com  *			obe_name and obe_root_ds members of this parameter
243013013Sglenn.lagasse@oracle.com  *			are set to the BE name and BE's root dataset
243113013Sglenn.lagasse@oracle.com  *			respectively.
243213013Sglenn.lagasse@oracle.com  * Return:
243313013Sglenn.lagasse@oracle.com  *		1 - Found current BE.
243413013Sglenn.lagasse@oracle.com  *		0 - Did not find current BE.
243513013Sglenn.lagasse@oracle.com  * Scope:
243613013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
243713013Sglenn.lagasse@oracle.com  */
243813013Sglenn.lagasse@oracle.com int
be_zfs_find_current_be_callback(zfs_handle_t * zhp,void * data)243913013Sglenn.lagasse@oracle.com be_zfs_find_current_be_callback(zfs_handle_t *zhp, void *data)
244013013Sglenn.lagasse@oracle.com {
244113013Sglenn.lagasse@oracle.com 	be_transaction_data_t	*bt = data;
244213013Sglenn.lagasse@oracle.com 	char			*mp = NULL;
244313013Sglenn.lagasse@oracle.com 
244413013Sglenn.lagasse@oracle.com 	/*
244513013Sglenn.lagasse@oracle.com 	 * Check if dataset is mounted, and if so where.
244613013Sglenn.lagasse@oracle.com 	 */
244713013Sglenn.lagasse@oracle.com 	if (zfs_is_mounted(zhp, &mp)) {
244813013Sglenn.lagasse@oracle.com 		/*
244913013Sglenn.lagasse@oracle.com 		 * If mounted at root, set obe_root_ds and obe_name
245013013Sglenn.lagasse@oracle.com 		 */
245113013Sglenn.lagasse@oracle.com 		if (mp != NULL && strcmp(mp, "/") == 0) {
245213013Sglenn.lagasse@oracle.com 			free(mp);
245313013Sglenn.lagasse@oracle.com 
245413013Sglenn.lagasse@oracle.com 			if ((bt->obe_root_ds = strdup(zfs_get_name(zhp)))
245513013Sglenn.lagasse@oracle.com 			    == NULL) {
245613013Sglenn.lagasse@oracle.com 				be_print_err(gettext(
245713013Sglenn.lagasse@oracle.com 				    "be_zfs_find_current_be_callback: "
245813013Sglenn.lagasse@oracle.com 				    "memory allocation failed\n"));
245913013Sglenn.lagasse@oracle.com 				ZFS_CLOSE(zhp);
246013013Sglenn.lagasse@oracle.com 				return (0);
246113013Sglenn.lagasse@oracle.com 			}
246213013Sglenn.lagasse@oracle.com 			if ((bt->obe_name = strdup(basename(bt->obe_root_ds)))
246313013Sglenn.lagasse@oracle.com 			    == NULL) {
246413013Sglenn.lagasse@oracle.com 				be_print_err(gettext(
246513013Sglenn.lagasse@oracle.com 				    "be_zfs_find_current_be_callback: "
246613013Sglenn.lagasse@oracle.com 				    "memory allocation failed\n"));
246713013Sglenn.lagasse@oracle.com 				ZFS_CLOSE(zhp);
246813013Sglenn.lagasse@oracle.com 				return (0);
246913013Sglenn.lagasse@oracle.com 			}
247013013Sglenn.lagasse@oracle.com 
247113013Sglenn.lagasse@oracle.com 			ZFS_CLOSE(zhp);
247213013Sglenn.lagasse@oracle.com 			return (1);
247313013Sglenn.lagasse@oracle.com 		}
247413013Sglenn.lagasse@oracle.com 
247513013Sglenn.lagasse@oracle.com 		free(mp);
247613013Sglenn.lagasse@oracle.com 	}
247713013Sglenn.lagasse@oracle.com 	ZFS_CLOSE(zhp);
247813013Sglenn.lagasse@oracle.com 
247913013Sglenn.lagasse@oracle.com 	return (0);
248013013Sglenn.lagasse@oracle.com }
248113013Sglenn.lagasse@oracle.com 
248213013Sglenn.lagasse@oracle.com /*
248313013Sglenn.lagasse@oracle.com  * Function:	be_check_be_roots_callback
248413013Sglenn.lagasse@oracle.com  * Description:	This function checks whether or not the dataset name passed
248513013Sglenn.lagasse@oracle.com  *		is hierachically located under the BE root container dataset
248613013Sglenn.lagasse@oracle.com  *		for this pool.
248713013Sglenn.lagasse@oracle.com  * Parameters:
248813013Sglenn.lagasse@oracle.com  *		zlp - zpool_handle_t pointer to current pool being processed.
248913013Sglenn.lagasse@oracle.com  *		data - name of dataset to check
249013013Sglenn.lagasse@oracle.com  * Returns:
249113013Sglenn.lagasse@oracle.com  *		0 - dataset is not in this pool's BE root container dataset
249213013Sglenn.lagasse@oracle.com  *		1 - dataset is in this pool's BE root container dataset
249313013Sglenn.lagasse@oracle.com  * Scope:
249413013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
249513013Sglenn.lagasse@oracle.com  */
249613013Sglenn.lagasse@oracle.com int
be_check_be_roots_callback(zpool_handle_t * zlp,void * data)249713013Sglenn.lagasse@oracle.com be_check_be_roots_callback(zpool_handle_t *zlp, void *data)
249813013Sglenn.lagasse@oracle.com {
249913013Sglenn.lagasse@oracle.com 	const char	*zpool = zpool_get_name(zlp);
250013013Sglenn.lagasse@oracle.com 	char		*ds = data;
250113013Sglenn.lagasse@oracle.com 	char		be_container_ds[MAXPATHLEN];
250213013Sglenn.lagasse@oracle.com 
250313013Sglenn.lagasse@oracle.com 	/* Generate string for this pool's BE root container dataset */
250413013Sglenn.lagasse@oracle.com 	be_make_container_ds(zpool, be_container_ds, sizeof (be_container_ds));
250513013Sglenn.lagasse@oracle.com 
250613013Sglenn.lagasse@oracle.com 	/*
250713013Sglenn.lagasse@oracle.com 	 * If dataset lives under the BE root container dataset
250813013Sglenn.lagasse@oracle.com 	 * of this pool, return failure.
250913013Sglenn.lagasse@oracle.com 	 */
251013013Sglenn.lagasse@oracle.com 	if (strncmp(be_container_ds, ds, strlen(be_container_ds)) == 0 &&
251113013Sglenn.lagasse@oracle.com 	    ds[strlen(be_container_ds)] == '/') {
251213013Sglenn.lagasse@oracle.com 		zpool_close(zlp);
251313013Sglenn.lagasse@oracle.com 		return (1);
251413013Sglenn.lagasse@oracle.com 	}
251513013Sglenn.lagasse@oracle.com 
251613013Sglenn.lagasse@oracle.com 	zpool_close(zlp);
251713013Sglenn.lagasse@oracle.com 	return (0);
251813013Sglenn.lagasse@oracle.com }
251913013Sglenn.lagasse@oracle.com 
252013013Sglenn.lagasse@oracle.com /*
252113013Sglenn.lagasse@oracle.com  * Function:	zfs_err_to_be_err
252213013Sglenn.lagasse@oracle.com  * Description:	This function takes the error stored in the libzfs handle
252313013Sglenn.lagasse@oracle.com  *		and maps it to an be_errno_t. If there are no matching
252413013Sglenn.lagasse@oracle.com  *		be_errno_t's then BE_ERR_ZFS is returned.
252513013Sglenn.lagasse@oracle.com  * Paramters:
252613013Sglenn.lagasse@oracle.com  *		zfsh - The libzfs handle containing the error we're looking up.
252713013Sglenn.lagasse@oracle.com  * Returns:
252813013Sglenn.lagasse@oracle.com  *		be_errno_t
252913013Sglenn.lagasse@oracle.com  * Scope:
253013013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
253113013Sglenn.lagasse@oracle.com  */
253213013Sglenn.lagasse@oracle.com int
zfs_err_to_be_err(libzfs_handle_t * zfsh)253313013Sglenn.lagasse@oracle.com zfs_err_to_be_err(libzfs_handle_t *zfsh)
253413013Sglenn.lagasse@oracle.com {
253513013Sglenn.lagasse@oracle.com 	int err = libzfs_errno(zfsh);
253613013Sglenn.lagasse@oracle.com 
253713013Sglenn.lagasse@oracle.com 	switch (err) {
253813013Sglenn.lagasse@oracle.com 	case 0:
253913013Sglenn.lagasse@oracle.com 		return (BE_SUCCESS);
254013013Sglenn.lagasse@oracle.com 	case EZFS_PERM:
254113013Sglenn.lagasse@oracle.com 		return (BE_ERR_PERM);
254213013Sglenn.lagasse@oracle.com 	case EZFS_INTR:
254313013Sglenn.lagasse@oracle.com 		return (BE_ERR_INTR);
254413013Sglenn.lagasse@oracle.com 	case EZFS_NOENT:
254513013Sglenn.lagasse@oracle.com 		return (BE_ERR_NOENT);
254613013Sglenn.lagasse@oracle.com 	case EZFS_NOSPC:
254713013Sglenn.lagasse@oracle.com 		return (BE_ERR_NOSPC);
254813013Sglenn.lagasse@oracle.com 	case EZFS_MOUNTFAILED:
254913013Sglenn.lagasse@oracle.com 		return (BE_ERR_MOUNT);
255013013Sglenn.lagasse@oracle.com 	case EZFS_UMOUNTFAILED:
255113013Sglenn.lagasse@oracle.com 		return (BE_ERR_UMOUNT);
255213013Sglenn.lagasse@oracle.com 	case EZFS_EXISTS:
255313013Sglenn.lagasse@oracle.com 		return (BE_ERR_BE_EXISTS);
255413013Sglenn.lagasse@oracle.com 	case EZFS_BUSY:
255513013Sglenn.lagasse@oracle.com 		return (BE_ERR_DEV_BUSY);
2556*13049SGeorge.Wilson@Sun.COM 	case EZFS_POOLREADONLY:
255713013Sglenn.lagasse@oracle.com 		return (BE_ERR_ROFS);
255813013Sglenn.lagasse@oracle.com 	case EZFS_NAMETOOLONG:
255913013Sglenn.lagasse@oracle.com 		return (BE_ERR_NAMETOOLONG);
256013013Sglenn.lagasse@oracle.com 	case EZFS_NODEVICE:
256113013Sglenn.lagasse@oracle.com 		return (BE_ERR_NODEV);
256213013Sglenn.lagasse@oracle.com 	case EZFS_POOL_INVALARG:
256313013Sglenn.lagasse@oracle.com 		return (BE_ERR_INVAL);
256413013Sglenn.lagasse@oracle.com 	case EZFS_PROPTYPE:
256513013Sglenn.lagasse@oracle.com 		return (BE_ERR_INVALPROP);
256613013Sglenn.lagasse@oracle.com 	case EZFS_BADTYPE:
256713013Sglenn.lagasse@oracle.com 		return (BE_ERR_DSTYPE);
256813013Sglenn.lagasse@oracle.com 	case EZFS_PROPNONINHERIT:
256913013Sglenn.lagasse@oracle.com 		return (BE_ERR_NONINHERIT);
257013013Sglenn.lagasse@oracle.com 	case EZFS_PROPREADONLY:
257113013Sglenn.lagasse@oracle.com 		return (BE_ERR_READONLYPROP);
257213013Sglenn.lagasse@oracle.com 	case EZFS_RESILVERING:
257313013Sglenn.lagasse@oracle.com 	case EZFS_POOLUNAVAIL:
257413013Sglenn.lagasse@oracle.com 		return (BE_ERR_UNAVAIL);
257513013Sglenn.lagasse@oracle.com 	case EZFS_DSREADONLY:
257613013Sglenn.lagasse@oracle.com 		return (BE_ERR_READONLYDS);
257713013Sglenn.lagasse@oracle.com 	default:
257813013Sglenn.lagasse@oracle.com 		return (BE_ERR_ZFS);
257913013Sglenn.lagasse@oracle.com 	}
258013013Sglenn.lagasse@oracle.com }
258113013Sglenn.lagasse@oracle.com 
258213013Sglenn.lagasse@oracle.com /*
258313013Sglenn.lagasse@oracle.com  * Function:	errno_to_be_err
258413013Sglenn.lagasse@oracle.com  * Description:	This function takes an errno and maps it to an be_errno_t.
258513013Sglenn.lagasse@oracle.com  *		If there are no matching be_errno_t's then BE_ERR_UNKNOWN is
258613013Sglenn.lagasse@oracle.com  *		returned.
258713013Sglenn.lagasse@oracle.com  * Paramters:
258813013Sglenn.lagasse@oracle.com  *		err - The errno we're compairing against.
258913013Sglenn.lagasse@oracle.com  * Returns:
259013013Sglenn.lagasse@oracle.com  *		be_errno_t
259113013Sglenn.lagasse@oracle.com  * Scope:
259213013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
259313013Sglenn.lagasse@oracle.com  */
259413013Sglenn.lagasse@oracle.com int
errno_to_be_err(int err)259513013Sglenn.lagasse@oracle.com errno_to_be_err(int err)
259613013Sglenn.lagasse@oracle.com {
259713013Sglenn.lagasse@oracle.com 	switch (err) {
259813013Sglenn.lagasse@oracle.com 	case EPERM:
259913013Sglenn.lagasse@oracle.com 		return (BE_ERR_PERM);
260013013Sglenn.lagasse@oracle.com 	case EACCES:
260113013Sglenn.lagasse@oracle.com 		return (BE_ERR_ACCESS);
260213013Sglenn.lagasse@oracle.com 	case ECANCELED:
260313013Sglenn.lagasse@oracle.com 		return (BE_ERR_CANCELED);
260413013Sglenn.lagasse@oracle.com 	case EINTR:
260513013Sglenn.lagasse@oracle.com 		return (BE_ERR_INTR);
260613013Sglenn.lagasse@oracle.com 	case ENOENT:
260713013Sglenn.lagasse@oracle.com 		return (BE_ERR_NOENT);
260813013Sglenn.lagasse@oracle.com 	case ENOSPC:
260913013Sglenn.lagasse@oracle.com 	case EDQUOT:
261013013Sglenn.lagasse@oracle.com 		return (BE_ERR_NOSPC);
261113013Sglenn.lagasse@oracle.com 	case EEXIST:
261213013Sglenn.lagasse@oracle.com 		return (BE_ERR_BE_EXISTS);
261313013Sglenn.lagasse@oracle.com 	case EBUSY:
261413013Sglenn.lagasse@oracle.com 		return (BE_ERR_BUSY);
261513013Sglenn.lagasse@oracle.com 	case EROFS:
261613013Sglenn.lagasse@oracle.com 		return (BE_ERR_ROFS);
261713013Sglenn.lagasse@oracle.com 	case ENAMETOOLONG:
261813013Sglenn.lagasse@oracle.com 		return (BE_ERR_NAMETOOLONG);
261913013Sglenn.lagasse@oracle.com 	case ENXIO:
262013013Sglenn.lagasse@oracle.com 		return (BE_ERR_NXIO);
262113013Sglenn.lagasse@oracle.com 	case EINVAL:
262213013Sglenn.lagasse@oracle.com 		return (BE_ERR_INVAL);
262313013Sglenn.lagasse@oracle.com 	case EFAULT:
262413013Sglenn.lagasse@oracle.com 		return (BE_ERR_FAULT);
262513013Sglenn.lagasse@oracle.com 	default:
262613013Sglenn.lagasse@oracle.com 		return (BE_ERR_UNKNOWN);
262713013Sglenn.lagasse@oracle.com 	}
262813013Sglenn.lagasse@oracle.com }
262913013Sglenn.lagasse@oracle.com 
263013013Sglenn.lagasse@oracle.com /*
263113013Sglenn.lagasse@oracle.com  * Function:	be_err_to_str
263213013Sglenn.lagasse@oracle.com  * Description:	This function takes a be_errno_t and maps it to a message.
263313013Sglenn.lagasse@oracle.com  *		If there are no matching be_errno_t's then NULL is returned.
263413013Sglenn.lagasse@oracle.com  * Paramters:
263513013Sglenn.lagasse@oracle.com  *		be_errno_t - The be_errno_t we're mapping.
263613013Sglenn.lagasse@oracle.com  * Returns:
263713013Sglenn.lagasse@oracle.com  *		string or NULL if the error code is not known.
263813013Sglenn.lagasse@oracle.com  * Scope:
263913013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
264013013Sglenn.lagasse@oracle.com  */
264113013Sglenn.lagasse@oracle.com char *
be_err_to_str(int err)264213013Sglenn.lagasse@oracle.com be_err_to_str(int err)
264313013Sglenn.lagasse@oracle.com {
264413013Sglenn.lagasse@oracle.com 	switch (err) {
264513013Sglenn.lagasse@oracle.com 	case BE_ERR_ACCESS:
264613013Sglenn.lagasse@oracle.com 		return (gettext("Permission denied."));
264713013Sglenn.lagasse@oracle.com 	case BE_ERR_ACTIVATE_CURR:
264813013Sglenn.lagasse@oracle.com 		return (gettext("Activation of current BE failed."));
264913013Sglenn.lagasse@oracle.com 	case BE_ERR_AUTONAME:
265013013Sglenn.lagasse@oracle.com 		return (gettext("Auto naming failed."));
265113013Sglenn.lagasse@oracle.com 	case BE_ERR_BE_NOENT:
265213013Sglenn.lagasse@oracle.com 		return (gettext("No such BE."));
265313013Sglenn.lagasse@oracle.com 	case BE_ERR_BUSY:
265413013Sglenn.lagasse@oracle.com 		return (gettext("Mount busy."));
265513013Sglenn.lagasse@oracle.com 	case BE_ERR_DEV_BUSY:
265613013Sglenn.lagasse@oracle.com 		return (gettext("Device busy."));
265713013Sglenn.lagasse@oracle.com 	case BE_ERR_CANCELED:
265813013Sglenn.lagasse@oracle.com 		return (gettext("Operation canceled."));
265913013Sglenn.lagasse@oracle.com 	case BE_ERR_CLONE:
266013013Sglenn.lagasse@oracle.com 		return (gettext("BE clone failed."));
266113013Sglenn.lagasse@oracle.com 	case BE_ERR_COPY:
266213013Sglenn.lagasse@oracle.com 		return (gettext("BE copy failed."));
266313013Sglenn.lagasse@oracle.com 	case BE_ERR_CREATDS:
266413013Sglenn.lagasse@oracle.com 		return (gettext("Dataset creation failed."));
266513013Sglenn.lagasse@oracle.com 	case BE_ERR_CURR_BE_NOT_FOUND:
266613013Sglenn.lagasse@oracle.com 		return (gettext("Can't find current BE."));
266713013Sglenn.lagasse@oracle.com 	case BE_ERR_DESTROY:
266813013Sglenn.lagasse@oracle.com 		return (gettext("Failed to destroy BE or snapshot."));
266913013Sglenn.lagasse@oracle.com 	case BE_ERR_DESTROY_CURR_BE:
267013013Sglenn.lagasse@oracle.com 		return (gettext("Cannot destroy current BE."));
267113013Sglenn.lagasse@oracle.com 	case BE_ERR_DEMOTE:
267213013Sglenn.lagasse@oracle.com 		return (gettext("BE demotion failed."));
267313013Sglenn.lagasse@oracle.com 	case BE_ERR_DSTYPE:
267413013Sglenn.lagasse@oracle.com 		return (gettext("Invalid dataset type."));
267513013Sglenn.lagasse@oracle.com 	case BE_ERR_BE_EXISTS:
267613013Sglenn.lagasse@oracle.com 		return (gettext("BE exists."));
267713013Sglenn.lagasse@oracle.com 	case BE_ERR_INIT:
267813013Sglenn.lagasse@oracle.com 		return (gettext("be_zfs_init failed."));
267913013Sglenn.lagasse@oracle.com 	case BE_ERR_INTR:
268013013Sglenn.lagasse@oracle.com 		return (gettext("Interupted system call."));
268113013Sglenn.lagasse@oracle.com 	case BE_ERR_INVAL:
268213013Sglenn.lagasse@oracle.com 		return (gettext("Invalid argument."));
268313013Sglenn.lagasse@oracle.com 	case BE_ERR_INVALPROP:
268413013Sglenn.lagasse@oracle.com 		return (gettext("Invalid property for dataset."));
268513013Sglenn.lagasse@oracle.com 	case BE_ERR_INVALMOUNTPOINT:
268613013Sglenn.lagasse@oracle.com 		return (gettext("Unexpected mountpoint."));
268713013Sglenn.lagasse@oracle.com 	case BE_ERR_MOUNT:
268813013Sglenn.lagasse@oracle.com 		return (gettext("Mount failed."));
268913013Sglenn.lagasse@oracle.com 	case BE_ERR_MOUNTED:
269013013Sglenn.lagasse@oracle.com 		return (gettext("Already mounted."));
269113013Sglenn.lagasse@oracle.com 	case BE_ERR_NAMETOOLONG:
269213013Sglenn.lagasse@oracle.com 		return (gettext("name > BUFSIZ."));
269313013Sglenn.lagasse@oracle.com 	case BE_ERR_NOENT:
269413013Sglenn.lagasse@oracle.com 		return (gettext("Doesn't exist."));
269513013Sglenn.lagasse@oracle.com 	case BE_ERR_POOL_NOENT:
269613013Sglenn.lagasse@oracle.com 		return (gettext("No such pool."));
269713013Sglenn.lagasse@oracle.com 	case BE_ERR_NODEV:
269813013Sglenn.lagasse@oracle.com 		return (gettext("No such device."));
269913013Sglenn.lagasse@oracle.com 	case BE_ERR_NOTMOUNTED:
270013013Sglenn.lagasse@oracle.com 		return (gettext("File system not mounted."));
270113013Sglenn.lagasse@oracle.com 	case BE_ERR_NOMEM:
270213013Sglenn.lagasse@oracle.com 		return (gettext("Not enough memory."));
270313013Sglenn.lagasse@oracle.com 	case BE_ERR_NONINHERIT:
270413013Sglenn.lagasse@oracle.com 		return (gettext(
270513013Sglenn.lagasse@oracle.com 		    "Property is not inheritable for the BE dataset."));
270613013Sglenn.lagasse@oracle.com 	case BE_ERR_NXIO:
270713013Sglenn.lagasse@oracle.com 		return (gettext("No such device or address."));
270813013Sglenn.lagasse@oracle.com 	case BE_ERR_NOSPC:
270913013Sglenn.lagasse@oracle.com 		return (gettext("No space on device."));
271013013Sglenn.lagasse@oracle.com 	case BE_ERR_NOTSUP:
271113013Sglenn.lagasse@oracle.com 		return (gettext("Operation not supported."));
271213013Sglenn.lagasse@oracle.com 	case BE_ERR_OPEN:
271313013Sglenn.lagasse@oracle.com 		return (gettext("Open failed."));
271413013Sglenn.lagasse@oracle.com 	case BE_ERR_PERM:
271513013Sglenn.lagasse@oracle.com 		return (gettext("Not owner."));
271613013Sglenn.lagasse@oracle.com 	case BE_ERR_UNAVAIL:
271713013Sglenn.lagasse@oracle.com 		return (gettext("The BE is currently unavailable."));
271813013Sglenn.lagasse@oracle.com 	case BE_ERR_PROMOTE:
271913013Sglenn.lagasse@oracle.com 		return (gettext("BE promotion failed."));
272013013Sglenn.lagasse@oracle.com 	case BE_ERR_ROFS:
272113013Sglenn.lagasse@oracle.com 		return (gettext("Read only file system."));
272213013Sglenn.lagasse@oracle.com 	case BE_ERR_READONLYDS:
272313013Sglenn.lagasse@oracle.com 		return (gettext("Read only dataset."));
272413013Sglenn.lagasse@oracle.com 	case BE_ERR_READONLYPROP:
272513013Sglenn.lagasse@oracle.com 		return (gettext("Read only property."));
272613013Sglenn.lagasse@oracle.com 	case BE_ERR_RENAME_ACTIVE:
272713013Sglenn.lagasse@oracle.com 		return (gettext("Renaming the active BE is not supported."));
272813013Sglenn.lagasse@oracle.com 	case BE_ERR_SS_EXISTS:
272913013Sglenn.lagasse@oracle.com 		return (gettext("Snapshot exists."));
273013013Sglenn.lagasse@oracle.com 	case BE_ERR_SS_NOENT:
273113013Sglenn.lagasse@oracle.com 		return (gettext("No such snapshot."));
273213013Sglenn.lagasse@oracle.com 	case BE_ERR_UMOUNT:
273313013Sglenn.lagasse@oracle.com 		return (gettext("Unmount failed."));
273413013Sglenn.lagasse@oracle.com 	case BE_ERR_UMOUNT_CURR_BE:
273513013Sglenn.lagasse@oracle.com 		return (gettext("Can't unmount the current BE."));
273613013Sglenn.lagasse@oracle.com 	case BE_ERR_UMOUNT_SHARED:
273713013Sglenn.lagasse@oracle.com 		return (gettext("Unmount of a shared File System failed."));
273813013Sglenn.lagasse@oracle.com 	case BE_ERR_FAULT:
273913013Sglenn.lagasse@oracle.com 		return (gettext("Bad address."));
274013013Sglenn.lagasse@oracle.com 	case BE_ERR_UNKNOWN:
274113013Sglenn.lagasse@oracle.com 		return (gettext("Unknown error."));
274213013Sglenn.lagasse@oracle.com 	case BE_ERR_ZFS:
274313013Sglenn.lagasse@oracle.com 		return (gettext("ZFS returned an error."));
274413013Sglenn.lagasse@oracle.com 	case BE_ERR_GEN_UUID:
274513013Sglenn.lagasse@oracle.com 		return (gettext("Failed to generate uuid."));
274613013Sglenn.lagasse@oracle.com 	case BE_ERR_PARSE_UUID:
274713013Sglenn.lagasse@oracle.com 		return (gettext("Failed to parse uuid."));
274813013Sglenn.lagasse@oracle.com 	case BE_ERR_NO_UUID:
274913013Sglenn.lagasse@oracle.com 		return (gettext("No uuid"));
275013013Sglenn.lagasse@oracle.com 	case BE_ERR_ZONE_NO_PARENTBE:
275113013Sglenn.lagasse@oracle.com 		return (gettext("No parent uuid"));
275213013Sglenn.lagasse@oracle.com 	case BE_ERR_ZONE_MULTIPLE_ACTIVE:
275313013Sglenn.lagasse@oracle.com 		return (gettext("Multiple active zone roots"));
275413013Sglenn.lagasse@oracle.com 	case BE_ERR_ZONE_NO_ACTIVE_ROOT:
275513013Sglenn.lagasse@oracle.com 		return (gettext("No active zone root"));
275613013Sglenn.lagasse@oracle.com 	case BE_ERR_ZONE_ROOT_NOT_LEGACY:
275713013Sglenn.lagasse@oracle.com 		return (gettext("Zone root not legacy"));
275813013Sglenn.lagasse@oracle.com 	case BE_ERR_MOUNT_ZONEROOT:
275913013Sglenn.lagasse@oracle.com 		return (gettext("Failed to mount a zone root."));
276013013Sglenn.lagasse@oracle.com 	case BE_ERR_UMOUNT_ZONEROOT:
276113013Sglenn.lagasse@oracle.com 		return (gettext("Failed to unmount a zone root."));
276213013Sglenn.lagasse@oracle.com 	case BE_ERR_NO_MOUNTED_ZONE:
276313013Sglenn.lagasse@oracle.com 		return (gettext("Zone is not mounted"));
276413013Sglenn.lagasse@oracle.com 	case BE_ERR_ZONES_UNMOUNT:
276513013Sglenn.lagasse@oracle.com 		return (gettext("Unable to unmount a zone BE."));
276613013Sglenn.lagasse@oracle.com 	case BE_ERR_NO_MENU:
276713013Sglenn.lagasse@oracle.com 		return (gettext("Missing boot menu file."));
276813013Sglenn.lagasse@oracle.com 	case BE_ERR_BAD_MENU_PATH:
276913013Sglenn.lagasse@oracle.com 		return (gettext("Invalid path for menu.lst file"));
277013013Sglenn.lagasse@oracle.com 	case BE_ERR_ZONE_SS_EXISTS:
277113013Sglenn.lagasse@oracle.com 		return (gettext("Zone snapshot exists."));
277213013Sglenn.lagasse@oracle.com 	case BE_ERR_ADD_SPLASH_ICT:
277313013Sglenn.lagasse@oracle.com 		return (gettext("Add_spash_image ICT failed."));
277413013Sglenn.lagasse@oracle.com 	case BE_ERR_BOOTFILE_INST:
277513013Sglenn.lagasse@oracle.com 		return (gettext("Error installing boot files."));
277613013Sglenn.lagasse@oracle.com 	case BE_ERR_EXTCMD:
277713013Sglenn.lagasse@oracle.com 		return (gettext("Error running an external command."));
277813013Sglenn.lagasse@oracle.com 	default:
277913013Sglenn.lagasse@oracle.com 		return (NULL);
278013013Sglenn.lagasse@oracle.com 	}
278113013Sglenn.lagasse@oracle.com }
278213013Sglenn.lagasse@oracle.com 
278313013Sglenn.lagasse@oracle.com /*
278413013Sglenn.lagasse@oracle.com  * Function:    be_has_grub
278513013Sglenn.lagasse@oracle.com  * Description: Boolean function indicating whether the current system
278613013Sglenn.lagasse@oracle.com  *		uses grub.
278713013Sglenn.lagasse@oracle.com  * Return:      B_FALSE - the system does not have grub
278813013Sglenn.lagasse@oracle.com  *              B_TRUE - the system does have grub.
278913013Sglenn.lagasse@oracle.com  * Scope:
279013013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
279113013Sglenn.lagasse@oracle.com  */
279213013Sglenn.lagasse@oracle.com boolean_t
be_has_grub(void)279313013Sglenn.lagasse@oracle.com be_has_grub(void)
279413013Sglenn.lagasse@oracle.com {
279513013Sglenn.lagasse@oracle.com 	/*
279613013Sglenn.lagasse@oracle.com 	 * TODO: This will need to be expanded to check for the existence of
279713013Sglenn.lagasse@oracle.com 	 * grub if and when there is grub support for SPARC.
279813013Sglenn.lagasse@oracle.com 	 */
279913013Sglenn.lagasse@oracle.com 	return (be_is_isa("i386"));
280013013Sglenn.lagasse@oracle.com }
280113013Sglenn.lagasse@oracle.com 
280213013Sglenn.lagasse@oracle.com /*
280313013Sglenn.lagasse@oracle.com  * Function:    be_is_isa
280413013Sglenn.lagasse@oracle.com  * Description: Boolean function indicating whether the instruction set
280513013Sglenn.lagasse@oracle.com  *              architecture of the executing system matches the name provided.
280613013Sglenn.lagasse@oracle.com  *              The string must match a system defined architecture (e.g.
280713013Sglenn.lagasse@oracle.com  *              "i386", "sparc") and is case sensitive.
280813013Sglenn.lagasse@oracle.com  * Parameters:  name - string representing the name of instruction set
280913013Sglenn.lagasse@oracle.com  *			architecture being tested
281013013Sglenn.lagasse@oracle.com  * Returns:     B_FALSE - the system instruction set architecture is different
281113013Sglenn.lagasse@oracle.com  *			from the one specified
281213013Sglenn.lagasse@oracle.com  *              B_TRUE - the system instruction set architecture is the same
281313013Sglenn.lagasse@oracle.com  *			as the one specified
281413013Sglenn.lagasse@oracle.com  * Scope:
281513013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
281613013Sglenn.lagasse@oracle.com  */
281713013Sglenn.lagasse@oracle.com boolean_t
be_is_isa(char * name)281813013Sglenn.lagasse@oracle.com be_is_isa(char *name)
281913013Sglenn.lagasse@oracle.com {
282013013Sglenn.lagasse@oracle.com 	return ((strcmp((char *)be_get_default_isa(), name) == 0));
282113013Sglenn.lagasse@oracle.com }
282213013Sglenn.lagasse@oracle.com 
282313013Sglenn.lagasse@oracle.com /*
282413013Sglenn.lagasse@oracle.com  * Function: be_get_default_isa
282513013Sglenn.lagasse@oracle.com  * Description:
282613013Sglenn.lagasse@oracle.com  *      Returns the default instruction set architecture of the
282713013Sglenn.lagasse@oracle.com  *      machine it is executed on. (eg. sparc, i386, ...)
282813013Sglenn.lagasse@oracle.com  *      NOTE:   SYS_INST environment variable may override default
282913013Sglenn.lagasse@oracle.com  *              return value
283013013Sglenn.lagasse@oracle.com  * Parameters:
283113013Sglenn.lagasse@oracle.com  *		none
283213013Sglenn.lagasse@oracle.com  * Returns:
283313013Sglenn.lagasse@oracle.com  *		NULL - the architecture returned by sysinfo() was too
283413013Sglenn.lagasse@oracle.com  *			long for local variables
283513013Sglenn.lagasse@oracle.com  *		char * - pointer to a string containing the default
283613013Sglenn.lagasse@oracle.com  *			implementation
283713013Sglenn.lagasse@oracle.com  * Scope:
283813013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
283913013Sglenn.lagasse@oracle.com  */
284013013Sglenn.lagasse@oracle.com char *
be_get_default_isa(void)284113013Sglenn.lagasse@oracle.com be_get_default_isa(void)
284213013Sglenn.lagasse@oracle.com {
284313013Sglenn.lagasse@oracle.com 	int	i;
284413013Sglenn.lagasse@oracle.com 	char	*envp;
284513013Sglenn.lagasse@oracle.com 	static char	default_inst[ARCH_LENGTH] = "";
284613013Sglenn.lagasse@oracle.com 
284713013Sglenn.lagasse@oracle.com 	if (default_inst[0] == '\0') {
284813013Sglenn.lagasse@oracle.com 		if ((envp = getenv("SYS_INST")) != NULL) {
284913013Sglenn.lagasse@oracle.com 			if ((int)strlen(envp) >= ARCH_LENGTH)
285013013Sglenn.lagasse@oracle.com 				return (NULL);
285113013Sglenn.lagasse@oracle.com 			else
285213013Sglenn.lagasse@oracle.com 				(void) strcpy(default_inst, envp);
285313013Sglenn.lagasse@oracle.com 		} else  {
285413013Sglenn.lagasse@oracle.com 			i = sysinfo(SI_ARCHITECTURE, default_inst, ARCH_LENGTH);
285513013Sglenn.lagasse@oracle.com 			if (i < 0 || i > ARCH_LENGTH)
285613013Sglenn.lagasse@oracle.com 				return (NULL);
285713013Sglenn.lagasse@oracle.com 		}
285813013Sglenn.lagasse@oracle.com 	}
285913013Sglenn.lagasse@oracle.com 	return (default_inst);
286013013Sglenn.lagasse@oracle.com }
286113013Sglenn.lagasse@oracle.com 
286213013Sglenn.lagasse@oracle.com /*
286313013Sglenn.lagasse@oracle.com  * Function: be_run_cmd
286413013Sglenn.lagasse@oracle.com  * Description:
286513013Sglenn.lagasse@oracle.com  *	Runs a command in a separate subprocess.  Splits out stdout from stderr
286613013Sglenn.lagasse@oracle.com  *	and sends each to its own buffer.  Buffers must be pre-allocated and
286713013Sglenn.lagasse@oracle.com  *	passed in as arguments.  Buffer sizes are also passed in as arguments.
286813013Sglenn.lagasse@oracle.com  *
286913013Sglenn.lagasse@oracle.com  *	Notes / caveats:
287013013Sglenn.lagasse@oracle.com  *	- Command being run is assumed to not have any stdout or stderr
287113013Sglenn.lagasse@oracle.com  *		redirection.
287213013Sglenn.lagasse@oracle.com  *	- Commands which emit total stderr output of greater than PIPE_BUF
287313013Sglenn.lagasse@oracle.com  *		bytes can hang.  For such commands, a different implementation
287413013Sglenn.lagasse@oracle.com  *		which uses poll(2) must be used.
287513013Sglenn.lagasse@oracle.com  *	- stdout_buf can be NULL.  In this case, stdout_bufsize is ignored, and
287613013Sglenn.lagasse@oracle.com  *		the stream which would have gone to it is sent to the bit
287713013Sglenn.lagasse@oracle.com  *		bucket.
287813013Sglenn.lagasse@oracle.com  *	- stderr_buf cannot be NULL.
287913013Sglenn.lagasse@oracle.com  *	- Only subprocess errors are appended to the stderr_buf.  Errors
288013013Sglenn.lagasse@oracle.com  *		running the command are reported through be_print_err().
288113013Sglenn.lagasse@oracle.com  *	- Data which would overflow its respective buffer is sent to the bit
288213013Sglenn.lagasse@oracle.com  *		bucket.
288313013Sglenn.lagasse@oracle.com  *
288413013Sglenn.lagasse@oracle.com  * Parameters:
288513013Sglenn.lagasse@oracle.com  *		command: command to run.  Assumed not to have embedded stdout
288613013Sglenn.lagasse@oracle.com  *			or stderr redirection.  May have stdin redirection,
288713013Sglenn.lagasse@oracle.com  *			however.
288813013Sglenn.lagasse@oracle.com  *		stderr_buf: buffer returning subprocess stderr data.  Errors
288913013Sglenn.lagasse@oracle.com  *			reported by this function are reported through
289013013Sglenn.lagasse@oracle.com  *			be_print_err().
289113013Sglenn.lagasse@oracle.com  *		stderr_bufsize: size of stderr_buf
289213013Sglenn.lagasse@oracle.com  *		stdout_buf: buffer returning subprocess stdout data.
289313013Sglenn.lagasse@oracle.com  *		stdout_bufsize: size of stdout_buf
289413013Sglenn.lagasse@oracle.com  * Returns:
289513013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - The command ran successfully without returning
289613013Sglenn.lagasse@oracle.com  *			errors.
289713013Sglenn.lagasse@oracle.com  *		BE_ERR_EXTCMD
289813013Sglenn.lagasse@oracle.com  *			- The command could not be run.
289913013Sglenn.lagasse@oracle.com  *			- The command terminated with error status.
290013013Sglenn.lagasse@oracle.com  *			- There were errors extracting or returning subprocess
290113013Sglenn.lagasse@oracle.com  *				data.
290213013Sglenn.lagasse@oracle.com  *		BE_ERR_NOMEM - The command exceeds the command buffer size.
290313013Sglenn.lagasse@oracle.com  *		BE_ERR_INVAL - An invalid argument was specified.
290413013Sglenn.lagasse@oracle.com  * Scope:
290513013Sglenn.lagasse@oracle.com  *		Semi-private (library wide use only)
290613013Sglenn.lagasse@oracle.com  */
290713013Sglenn.lagasse@oracle.com int
be_run_cmd(char * command,char * stderr_buf,int stderr_bufsize,char * stdout_buf,int stdout_bufsize)290813013Sglenn.lagasse@oracle.com be_run_cmd(char *command, char *stderr_buf, int stderr_bufsize,
290913013Sglenn.lagasse@oracle.com     char *stdout_buf, int stdout_bufsize)
291013013Sglenn.lagasse@oracle.com {
291113013Sglenn.lagasse@oracle.com 	char *temp_filename = strdup(tmpnam(NULL));
291213013Sglenn.lagasse@oracle.com 	FILE *stdout_str = NULL;
291313013Sglenn.lagasse@oracle.com 	FILE *stderr_str = NULL;
291413013Sglenn.lagasse@oracle.com 	char cmdline[BUFSIZ];
291513013Sglenn.lagasse@oracle.com 	char oneline[BUFSIZ];
291613013Sglenn.lagasse@oracle.com 	int exit_status;
291713013Sglenn.lagasse@oracle.com 	int rval = BE_SUCCESS;
291813013Sglenn.lagasse@oracle.com 
291913013Sglenn.lagasse@oracle.com 	if ((command == NULL) || (stderr_buf == NULL) ||
292013013Sglenn.lagasse@oracle.com 	    (stderr_bufsize <= 0) || (stdout_bufsize <  0) ||
292113013Sglenn.lagasse@oracle.com 	    ((stdout_buf != NULL) ^ (stdout_bufsize != 0))) {
292213013Sglenn.lagasse@oracle.com 		return (BE_ERR_INVAL);
292313013Sglenn.lagasse@oracle.com }
292413013Sglenn.lagasse@oracle.com 
292513013Sglenn.lagasse@oracle.com 	/* Set up command so popen returns stderr, not stdout */
292613013Sglenn.lagasse@oracle.com 	if (snprintf(cmdline, BUFSIZ, "%s 2> %s", command,
292713013Sglenn.lagasse@oracle.com 	    temp_filename) >= BUFSIZ) {
292813013Sglenn.lagasse@oracle.com 		rval = BE_ERR_NOMEM;
292913013Sglenn.lagasse@oracle.com 		goto cleanup;
293013013Sglenn.lagasse@oracle.com 	}
293113013Sglenn.lagasse@oracle.com 
293213013Sglenn.lagasse@oracle.com 	/* Set up the fifo that will make stderr available. */
293313013Sglenn.lagasse@oracle.com 	if (mkfifo(temp_filename, 0600) != 0) {
293413013Sglenn.lagasse@oracle.com 		(void) be_print_err(gettext("be_run_cmd: mkfifo: %s\n"),
293513013Sglenn.lagasse@oracle.com 		    strerror(errno));
293613013Sglenn.lagasse@oracle.com 		rval = BE_ERR_EXTCMD;
293713013Sglenn.lagasse@oracle.com 		goto cleanup;
293813013Sglenn.lagasse@oracle.com 	}
293913013Sglenn.lagasse@oracle.com 
294013013Sglenn.lagasse@oracle.com 	if ((stdout_str = popen(cmdline, "r")) == NULL) {
294113013Sglenn.lagasse@oracle.com 		(void) be_print_err(gettext("be_run_cmd: popen: %s\n"),
294213013Sglenn.lagasse@oracle.com 		    strerror(errno));
294313013Sglenn.lagasse@oracle.com 		rval = BE_ERR_EXTCMD;
294413013Sglenn.lagasse@oracle.com 		goto cleanup;
294513013Sglenn.lagasse@oracle.com 	}
294613013Sglenn.lagasse@oracle.com 
294713013Sglenn.lagasse@oracle.com 	if ((stderr_str = fopen(temp_filename, "r")) == NULL) {
294813013Sglenn.lagasse@oracle.com 		(void) be_print_err(gettext("be_run_cmd: fopen: %s\n"),
294913013Sglenn.lagasse@oracle.com 		    strerror(errno));
295013013Sglenn.lagasse@oracle.com 		(void) pclose(stdout_str);
295113013Sglenn.lagasse@oracle.com 		rval = BE_ERR_EXTCMD;
295213013Sglenn.lagasse@oracle.com 		goto cleanup;
295313013Sglenn.lagasse@oracle.com 	}
295413013Sglenn.lagasse@oracle.com 
295513013Sglenn.lagasse@oracle.com 	/* Read stdout first, as it usually outputs more than stderr. */
295613013Sglenn.lagasse@oracle.com 	oneline[BUFSIZ-1] = '\0';
295713013Sglenn.lagasse@oracle.com 	while (fgets(oneline, BUFSIZ-1, stdout_str) != NULL) {
295813013Sglenn.lagasse@oracle.com 		if (stdout_str != NULL) {
295913013Sglenn.lagasse@oracle.com 			(void) strlcat(stdout_buf, oneline, stdout_bufsize);
296013013Sglenn.lagasse@oracle.com 		}
296113013Sglenn.lagasse@oracle.com 	}
296213013Sglenn.lagasse@oracle.com 
296313013Sglenn.lagasse@oracle.com 	while (fgets(oneline, BUFSIZ-1, stderr_str) != NULL) {
296413013Sglenn.lagasse@oracle.com 		(void) strlcat(stderr_buf, oneline, stderr_bufsize);
296513013Sglenn.lagasse@oracle.com 	}
296613013Sglenn.lagasse@oracle.com 
296713013Sglenn.lagasse@oracle.com 	/* Close pipe, get exit status. */
296813013Sglenn.lagasse@oracle.com 	if ((exit_status = pclose(stdout_str)) == -1) {
296913013Sglenn.lagasse@oracle.com 		(void) be_print_err(gettext("be_run_cmd: pclose: %s\n"),
297013013Sglenn.lagasse@oracle.com 		    strerror(errno));
297113013Sglenn.lagasse@oracle.com 		rval = BE_ERR_EXTCMD;
297213013Sglenn.lagasse@oracle.com 	} else if (WIFEXITED(exit_status)) {
297313013Sglenn.lagasse@oracle.com 		exit_status = (int)((char)WEXITSTATUS(exit_status));
297413013Sglenn.lagasse@oracle.com 		if (exit_status != 0) {
297513013Sglenn.lagasse@oracle.com 			(void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: "
297613013Sglenn.lagasse@oracle.com 			    "command terminated with error status: %d\n"),
297713013Sglenn.lagasse@oracle.com 			    exit_status);
297813013Sglenn.lagasse@oracle.com 			(void) strlcat(stderr_buf, oneline, stderr_bufsize);
297913013Sglenn.lagasse@oracle.com 			rval = BE_ERR_EXTCMD;
298013013Sglenn.lagasse@oracle.com 		}
298113013Sglenn.lagasse@oracle.com 	} else {
298213013Sglenn.lagasse@oracle.com 		(void) snprintf(oneline, BUFSIZ, gettext("be_run_cmd: command "
298313013Sglenn.lagasse@oracle.com 		    "terminated on signal: %s\n"),
298413013Sglenn.lagasse@oracle.com 		    strsignal(WTERMSIG(exit_status)));
298513013Sglenn.lagasse@oracle.com 		(void) strlcat(stderr_buf, oneline, stderr_bufsize);
298613013Sglenn.lagasse@oracle.com 		rval = BE_ERR_EXTCMD;
298713013Sglenn.lagasse@oracle.com 	}
298813013Sglenn.lagasse@oracle.com 
298913013Sglenn.lagasse@oracle.com cleanup:
299013013Sglenn.lagasse@oracle.com 	(void) unlink(temp_filename);
299113013Sglenn.lagasse@oracle.com 	(void) free(temp_filename);
299213013Sglenn.lagasse@oracle.com 
299313013Sglenn.lagasse@oracle.com 	return (rval);
299413013Sglenn.lagasse@oracle.com }
299513013Sglenn.lagasse@oracle.com 
299613013Sglenn.lagasse@oracle.com /* ********************************************************************	*/
299713013Sglenn.lagasse@oracle.com /*			Private Functions				*/
299813013Sglenn.lagasse@oracle.com /* ******************************************************************** */
299913013Sglenn.lagasse@oracle.com 
300013013Sglenn.lagasse@oracle.com /*
300113013Sglenn.lagasse@oracle.com  * Function:	update_dataset
300213013Sglenn.lagasse@oracle.com  * Description:	This function takes a dataset name and replaces the zpool
300313013Sglenn.lagasse@oracle.com  *		and be_name components of the dataset with the new be_name
300413013Sglenn.lagasse@oracle.com  *		zpool passed in.
300513013Sglenn.lagasse@oracle.com  * Parameters:
300613013Sglenn.lagasse@oracle.com  *		dataset - name of dataset
300713013Sglenn.lagasse@oracle.com  *		dataset_len - lenth of buffer in which dataset is passed in.
300813013Sglenn.lagasse@oracle.com  *		be_name - name of new BE name to update to.
300913013Sglenn.lagasse@oracle.com  *		old_rc_loc - dataset under which the root container dataset
301013013Sglenn.lagasse@oracle.com  *			for the old BE lives.
301113013Sglenn.lagasse@oracle.com  *		new_rc_loc - dataset under which the root container dataset
301213013Sglenn.lagasse@oracle.com  *			for the new BE lives.
301313013Sglenn.lagasse@oracle.com  * Returns:
301413013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
301513013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
301613013Sglenn.lagasse@oracle.com  * Scope:
301713013Sglenn.lagasse@oracle.com  *		Private
301813013Sglenn.lagasse@oracle.com  */
301913013Sglenn.lagasse@oracle.com static int
update_dataset(char * dataset,int dataset_len,char * be_name,char * old_rc_loc,char * new_rc_loc)302013013Sglenn.lagasse@oracle.com update_dataset(char *dataset, int dataset_len, char *be_name,
302113013Sglenn.lagasse@oracle.com     char *old_rc_loc, char *new_rc_loc)
302213013Sglenn.lagasse@oracle.com {
302313013Sglenn.lagasse@oracle.com 	char	*ds = NULL;
302413013Sglenn.lagasse@oracle.com 	char	*sub_ds = NULL;
302513013Sglenn.lagasse@oracle.com 
302613013Sglenn.lagasse@oracle.com 	/* Tear off the BE container dataset */
302713013Sglenn.lagasse@oracle.com 	if ((ds = be_make_name_from_ds(dataset, old_rc_loc)) == NULL) {
302813013Sglenn.lagasse@oracle.com 		return (BE_ERR_INVAL);
302913013Sglenn.lagasse@oracle.com 	}
303013013Sglenn.lagasse@oracle.com 
303113013Sglenn.lagasse@oracle.com 	/* Get dataset name relative to BE root, if there is one */
303213013Sglenn.lagasse@oracle.com 	sub_ds = strchr(ds, '/');
303313013Sglenn.lagasse@oracle.com 
303413013Sglenn.lagasse@oracle.com 	/* Generate the BE root dataset name */
303513013Sglenn.lagasse@oracle.com 	be_make_root_ds(new_rc_loc, be_name, dataset, dataset_len);
303613013Sglenn.lagasse@oracle.com 
303713013Sglenn.lagasse@oracle.com 	/* If a subordinate dataset name was found, append it */
303813013Sglenn.lagasse@oracle.com 	if (sub_ds != NULL)
303913013Sglenn.lagasse@oracle.com 		(void) strlcat(dataset, sub_ds, dataset_len);
304013013Sglenn.lagasse@oracle.com 
304113013Sglenn.lagasse@oracle.com 	free(ds);
304213013Sglenn.lagasse@oracle.com 	return (BE_SUCCESS);
304313013Sglenn.lagasse@oracle.com }
304413013Sglenn.lagasse@oracle.com 
304513013Sglenn.lagasse@oracle.com /*
304613013Sglenn.lagasse@oracle.com  * Function:	_update_vfstab
304713013Sglenn.lagasse@oracle.com  * Description:	This function updates a vfstab file to reflect the new
304813013Sglenn.lagasse@oracle.com  *		root container dataset location and be_name for all
304913013Sglenn.lagasse@oracle.com  *		entries listed in the be_fs_list_data_t structure passed in.
305013013Sglenn.lagasse@oracle.com  * Parameters:
305113013Sglenn.lagasse@oracle.com  *		vfstab - vfstab file to modify
305213013Sglenn.lagasse@oracle.com  *		be_name - name of BE to update.
305313013Sglenn.lagasse@oracle.com  *		old_rc_loc - dataset under which the root container dataset
305413013Sglenn.lagasse@oracle.com  *			of the old BE resides in.
305513013Sglenn.lagasse@oracle.com  *		new_rc_loc - dataset under which the root container dataset
305613013Sglenn.lagasse@oracle.com  *			of the new BE resides in.
305713013Sglenn.lagasse@oracle.com  *		fld - be_fs_list_data_t pointer providing the list of
305813013Sglenn.lagasse@oracle.com  *			file systems to look for in vfstab.
305913013Sglenn.lagasse@oracle.com  * Returns:
306013013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
306113013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
306213013Sglenn.lagasse@oracle.com  * Scope:
306313013Sglenn.lagasse@oracle.com  *		Private
306413013Sglenn.lagasse@oracle.com  */
306513013Sglenn.lagasse@oracle.com static int
_update_vfstab(char * vfstab,char * be_name,char * old_rc_loc,char * new_rc_loc,be_fs_list_data_t * fld)306613013Sglenn.lagasse@oracle.com _update_vfstab(char *vfstab, char *be_name, char *old_rc_loc,
306713013Sglenn.lagasse@oracle.com     char *new_rc_loc, be_fs_list_data_t *fld)
306813013Sglenn.lagasse@oracle.com {
306913013Sglenn.lagasse@oracle.com 	struct vfstab	vp;
307013013Sglenn.lagasse@oracle.com 	char		*tmp_vfstab = NULL;
307113013Sglenn.lagasse@oracle.com 	char		comments_buf[BUFSIZ];
307213013Sglenn.lagasse@oracle.com 	FILE		*comments = NULL;
307313013Sglenn.lagasse@oracle.com 	FILE		*vfs_ents = NULL;
307413013Sglenn.lagasse@oracle.com 	FILE		*tfile = NULL;
307513013Sglenn.lagasse@oracle.com 	struct stat	sb;
307613013Sglenn.lagasse@oracle.com 	char		dev[MAXPATHLEN];
307713013Sglenn.lagasse@oracle.com 	char		*c;
307813013Sglenn.lagasse@oracle.com 	int		fd;
307913013Sglenn.lagasse@oracle.com 	int		ret = BE_SUCCESS, err = 0;
308013013Sglenn.lagasse@oracle.com 	int		i;
308113013Sglenn.lagasse@oracle.com 	int		tmp_vfstab_len = 0;
308213013Sglenn.lagasse@oracle.com 
308313013Sglenn.lagasse@oracle.com 	errno = 0;
308413013Sglenn.lagasse@oracle.com 
308513013Sglenn.lagasse@oracle.com 	/*
308613013Sglenn.lagasse@oracle.com 	 * Open vfstab for reading twice.  First is for comments,
308713013Sglenn.lagasse@oracle.com 	 * second is for actual entries.
308813013Sglenn.lagasse@oracle.com 	 */
308913013Sglenn.lagasse@oracle.com 	if ((comments = fopen(vfstab, "r")) == NULL ||
309013013Sglenn.lagasse@oracle.com 	    (vfs_ents = fopen(vfstab, "r")) == NULL) {
309113013Sglenn.lagasse@oracle.com 		err = errno;
309213013Sglenn.lagasse@oracle.com 		be_print_err(gettext("_update_vfstab: "
309313013Sglenn.lagasse@oracle.com 		    "failed to open vfstab (%s): %s\n"), vfstab,
309413013Sglenn.lagasse@oracle.com 		    strerror(err));
309513013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
309613013Sglenn.lagasse@oracle.com 		goto cleanup;
309713013Sglenn.lagasse@oracle.com 	}
309813013Sglenn.lagasse@oracle.com 
309913013Sglenn.lagasse@oracle.com 	/* Grab the stats of the original vfstab file */
310013013Sglenn.lagasse@oracle.com 	if (stat(vfstab, &sb) != 0) {
310113013Sglenn.lagasse@oracle.com 		err = errno;
310213013Sglenn.lagasse@oracle.com 		be_print_err(gettext("_update_vfstab: "
310313013Sglenn.lagasse@oracle.com 		    "failed to stat file %s: %s\n"), vfstab,
310413013Sglenn.lagasse@oracle.com 		    strerror(err));
310513013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
310613013Sglenn.lagasse@oracle.com 		goto cleanup;
310713013Sglenn.lagasse@oracle.com 	}
310813013Sglenn.lagasse@oracle.com 
310913013Sglenn.lagasse@oracle.com 	/* Create tmp file for modified vfstab */
311013013Sglenn.lagasse@oracle.com 	if ((tmp_vfstab = (char *)malloc(strlen(vfstab) + 7))
311113013Sglenn.lagasse@oracle.com 	    == NULL) {
311213013Sglenn.lagasse@oracle.com 		be_print_err(gettext("_update_vfstab: "
311313013Sglenn.lagasse@oracle.com 		    "malloc failed\n"));
311413013Sglenn.lagasse@oracle.com 		ret = BE_ERR_NOMEM;
311513013Sglenn.lagasse@oracle.com 		goto cleanup;
311613013Sglenn.lagasse@oracle.com 	}
311713013Sglenn.lagasse@oracle.com 	tmp_vfstab_len = strlen(vfstab) + 7;
311813013Sglenn.lagasse@oracle.com 	(void) memset(tmp_vfstab, 0, tmp_vfstab_len);
311913013Sglenn.lagasse@oracle.com 	(void) strlcpy(tmp_vfstab, vfstab, tmp_vfstab_len);
312013013Sglenn.lagasse@oracle.com 	(void) strlcat(tmp_vfstab, "XXXXXX", tmp_vfstab_len);
312113013Sglenn.lagasse@oracle.com 	if ((fd = mkstemp(tmp_vfstab)) == -1) {
312213013Sglenn.lagasse@oracle.com 		err = errno;
312313013Sglenn.lagasse@oracle.com 		be_print_err(gettext("_update_vfstab: "
312413013Sglenn.lagasse@oracle.com 		    "mkstemp failed: %s\n"), strerror(err));
312513013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
312613013Sglenn.lagasse@oracle.com 		goto cleanup;
312713013Sglenn.lagasse@oracle.com 	}
312813013Sglenn.lagasse@oracle.com 	if ((tfile = fdopen(fd, "w")) == NULL) {
312913013Sglenn.lagasse@oracle.com 		err = errno;
313013013Sglenn.lagasse@oracle.com 		be_print_err(gettext("_update_vfstab: "
313113013Sglenn.lagasse@oracle.com 		    "could not open file for write\n"));
313213013Sglenn.lagasse@oracle.com 		(void) close(fd);
313313013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
313413013Sglenn.lagasse@oracle.com 		goto cleanup;
313513013Sglenn.lagasse@oracle.com 	}
313613013Sglenn.lagasse@oracle.com 
313713013Sglenn.lagasse@oracle.com 	while (fgets(comments_buf, BUFSIZ, comments)) {
313813013Sglenn.lagasse@oracle.com 		for (c = comments_buf; *c != '\0' && isspace(*c); c++)
313913013Sglenn.lagasse@oracle.com 			;
314013013Sglenn.lagasse@oracle.com 		if (*c == '\0') {
314113013Sglenn.lagasse@oracle.com 			continue;
314213013Sglenn.lagasse@oracle.com 		} else if (*c == '#') {
314313013Sglenn.lagasse@oracle.com 			/*
314413013Sglenn.lagasse@oracle.com 			 * If line is a comment line, just put
314513013Sglenn.lagasse@oracle.com 			 * it through to the tmp vfstab.
314613013Sglenn.lagasse@oracle.com 			 */
314713013Sglenn.lagasse@oracle.com 			(void) fputs(comments_buf, tfile);
314813013Sglenn.lagasse@oracle.com 		} else {
314913013Sglenn.lagasse@oracle.com 			/*
315013013Sglenn.lagasse@oracle.com 			 * Else line is a vfstab entry, grab it
315113013Sglenn.lagasse@oracle.com 			 * into a vfstab struct.
315213013Sglenn.lagasse@oracle.com 			 */
315313013Sglenn.lagasse@oracle.com 			if (getvfsent(vfs_ents, &vp) != 0) {
315413013Sglenn.lagasse@oracle.com 				err = errno;
315513013Sglenn.lagasse@oracle.com 				be_print_err(gettext("_update_vfstab: "
315613013Sglenn.lagasse@oracle.com 				    "getvfsent failed: %s\n"), strerror(err));
315713013Sglenn.lagasse@oracle.com 				ret = errno_to_be_err(err);
315813013Sglenn.lagasse@oracle.com 				goto cleanup;
315913013Sglenn.lagasse@oracle.com 			}
316013013Sglenn.lagasse@oracle.com 
316113013Sglenn.lagasse@oracle.com 			if (vp.vfs_special == NULL || vp.vfs_mountp == NULL) {
316213013Sglenn.lagasse@oracle.com 				(void) putvfsent(tfile, &vp);
316313013Sglenn.lagasse@oracle.com 				continue;
316413013Sglenn.lagasse@oracle.com 			}
316513013Sglenn.lagasse@oracle.com 
316613013Sglenn.lagasse@oracle.com 			/*
316713013Sglenn.lagasse@oracle.com 			 * If the entry is one of the entries in the list
316813013Sglenn.lagasse@oracle.com 			 * of file systems to update, modify it's device
316913013Sglenn.lagasse@oracle.com 			 * field to be correct for this BE.
317013013Sglenn.lagasse@oracle.com 			 */
317113013Sglenn.lagasse@oracle.com 			for (i = 0; i < fld->fs_num; i++) {
317213013Sglenn.lagasse@oracle.com 				if (strcmp(vp.vfs_special, fld->fs_list[i])
317313013Sglenn.lagasse@oracle.com 				    == 0) {
317413013Sglenn.lagasse@oracle.com 					/*
317513013Sglenn.lagasse@oracle.com 					 * Found entry that needs an update.
317613013Sglenn.lagasse@oracle.com 					 * Replace the root container dataset
317713013Sglenn.lagasse@oracle.com 					 * location and be_name in the
317813013Sglenn.lagasse@oracle.com 					 * entry's device.
317913013Sglenn.lagasse@oracle.com 					 */
318013013Sglenn.lagasse@oracle.com 					(void) strlcpy(dev, vp.vfs_special,
318113013Sglenn.lagasse@oracle.com 					    sizeof (dev));
318213013Sglenn.lagasse@oracle.com 
318313013Sglenn.lagasse@oracle.com 					if ((ret = update_dataset(dev,
318413013Sglenn.lagasse@oracle.com 					    sizeof (dev), be_name, old_rc_loc,
318513013Sglenn.lagasse@oracle.com 					    new_rc_loc)) != 0) {
318613013Sglenn.lagasse@oracle.com 						be_print_err(
318713013Sglenn.lagasse@oracle.com 						    gettext("_update_vfstab: "
318813013Sglenn.lagasse@oracle.com 						    "Failed to update device "
318913013Sglenn.lagasse@oracle.com 						    "field for vfstab entry "
319013013Sglenn.lagasse@oracle.com 						    "%s\n"), fld->fs_list[i]);
319113013Sglenn.lagasse@oracle.com 						goto cleanup;
319213013Sglenn.lagasse@oracle.com 					}
319313013Sglenn.lagasse@oracle.com 
319413013Sglenn.lagasse@oracle.com 					vp.vfs_special = dev;
319513013Sglenn.lagasse@oracle.com 					break;
319613013Sglenn.lagasse@oracle.com 				}
319713013Sglenn.lagasse@oracle.com 			}
319813013Sglenn.lagasse@oracle.com 
319913013Sglenn.lagasse@oracle.com 			/* Put entry through to tmp vfstab */
320013013Sglenn.lagasse@oracle.com 			(void) putvfsent(tfile, &vp);
320113013Sglenn.lagasse@oracle.com 		}
320213013Sglenn.lagasse@oracle.com 	}
320313013Sglenn.lagasse@oracle.com 
320413013Sglenn.lagasse@oracle.com 	(void) fclose(comments);
320513013Sglenn.lagasse@oracle.com 	comments = NULL;
320613013Sglenn.lagasse@oracle.com 	(void) fclose(vfs_ents);
320713013Sglenn.lagasse@oracle.com 	vfs_ents = NULL;
320813013Sglenn.lagasse@oracle.com 	(void) fclose(tfile);
320913013Sglenn.lagasse@oracle.com 	tfile = NULL;
321013013Sglenn.lagasse@oracle.com 
321113013Sglenn.lagasse@oracle.com 	/* Copy tmp vfstab into place */
321213013Sglenn.lagasse@oracle.com 	if (rename(tmp_vfstab, vfstab) != 0) {
321313013Sglenn.lagasse@oracle.com 		err = errno;
321413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("_update_vfstab: "
321513013Sglenn.lagasse@oracle.com 		    "failed to rename file %s to %s: %s\n"), tmp_vfstab,
321613013Sglenn.lagasse@oracle.com 		    vfstab, strerror(err));
321713013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
321813013Sglenn.lagasse@oracle.com 		goto cleanup;
321913013Sglenn.lagasse@oracle.com 	}
322013013Sglenn.lagasse@oracle.com 
322113013Sglenn.lagasse@oracle.com 	/* Set the perms and ownership of the updated file */
322213013Sglenn.lagasse@oracle.com 	if (chmod(vfstab, sb.st_mode) != 0) {
322313013Sglenn.lagasse@oracle.com 		err = errno;
322413013Sglenn.lagasse@oracle.com 		be_print_err(gettext("_update_vfstab: "
322513013Sglenn.lagasse@oracle.com 		    "failed to chmod %s: %s\n"), vfstab, strerror(err));
322613013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
322713013Sglenn.lagasse@oracle.com 		goto cleanup;
322813013Sglenn.lagasse@oracle.com 	}
322913013Sglenn.lagasse@oracle.com 	if (chown(vfstab, sb.st_uid, sb.st_gid) != 0) {
323013013Sglenn.lagasse@oracle.com 		err = errno;
323113013Sglenn.lagasse@oracle.com 		be_print_err(gettext("_update_vfstab: "
323213013Sglenn.lagasse@oracle.com 		    "failed to chown %s: %s\n"), vfstab, strerror(err));
323313013Sglenn.lagasse@oracle.com 		ret = errno_to_be_err(err);
323413013Sglenn.lagasse@oracle.com 		goto cleanup;
323513013Sglenn.lagasse@oracle.com 	}
323613013Sglenn.lagasse@oracle.com 
323713013Sglenn.lagasse@oracle.com cleanup:
323813013Sglenn.lagasse@oracle.com 	if (comments != NULL)
323913013Sglenn.lagasse@oracle.com 		(void) fclose(comments);
324013013Sglenn.lagasse@oracle.com 	if (vfs_ents != NULL)
324113013Sglenn.lagasse@oracle.com 		(void) fclose(vfs_ents);
324213013Sglenn.lagasse@oracle.com 	(void) unlink(tmp_vfstab);
324313013Sglenn.lagasse@oracle.com 	(void) free(tmp_vfstab);
324413013Sglenn.lagasse@oracle.com 	if (tfile != NULL)
324513013Sglenn.lagasse@oracle.com 		(void) fclose(tfile);
324613013Sglenn.lagasse@oracle.com 
324713013Sglenn.lagasse@oracle.com 	return (ret);
324813013Sglenn.lagasse@oracle.com }
324913013Sglenn.lagasse@oracle.com 
325013013Sglenn.lagasse@oracle.com 
325113013Sglenn.lagasse@oracle.com /*
325213013Sglenn.lagasse@oracle.com  * Function:	be_get_auto_name
325313013Sglenn.lagasse@oracle.com  * Description:	Generate an auto name constructed based on the BE name
325413013Sglenn.lagasse@oracle.com  *		of the original BE or zone BE being cloned.
325513013Sglenn.lagasse@oracle.com  * Parameters:
325613013Sglenn.lagasse@oracle.com  *		obe_name - name of the original BE or zone BE being cloned.
325713013Sglenn.lagasse@oracle.com  *              container_ds - container dataset for the zone.
325813013Sglenn.lagasse@oracle.com  *                             Note: if zone_be is false this should be
325913013Sglenn.lagasse@oracle.com  *                                  NULL.
326013013Sglenn.lagasse@oracle.com  *		zone_be - flag that indicates if we are operating on a zone BE.
326113013Sglenn.lagasse@oracle.com  * Returns:
326213013Sglenn.lagasse@oracle.com  *		Success - pointer to auto generated BE name.  The name
326313013Sglenn.lagasse@oracle.com  *			is allocated in heap storage so the caller is
326413013Sglenn.lagasse@oracle.com  *			responsible for free'ing the name.
326513013Sglenn.lagasse@oracle.com  *		Failure - NULL
326613013Sglenn.lagasse@oracle.com  * Scope:
326713013Sglenn.lagasse@oracle.com  *		Private
326813013Sglenn.lagasse@oracle.com  */
326913013Sglenn.lagasse@oracle.com static char *
be_get_auto_name(char * obe_name,char * be_container_ds,boolean_t zone_be)327013013Sglenn.lagasse@oracle.com be_get_auto_name(char *obe_name, char *be_container_ds, boolean_t zone_be)
327113013Sglenn.lagasse@oracle.com {
327213013Sglenn.lagasse@oracle.com 	be_node_list_t	*be_nodes = NULL;
327313013Sglenn.lagasse@oracle.com 	be_node_list_t	*cur_be = NULL;
327413013Sglenn.lagasse@oracle.com 	char		auto_be_name[MAXPATHLEN];
327513013Sglenn.lagasse@oracle.com 	char		base_be_name[MAXPATHLEN];
327613013Sglenn.lagasse@oracle.com 	char		cur_be_name[MAXPATHLEN];
327713013Sglenn.lagasse@oracle.com 	char		*num_str = NULL;
327813013Sglenn.lagasse@oracle.com 	char		*c = NULL;
327913013Sglenn.lagasse@oracle.com 	int		num = 0;
328013013Sglenn.lagasse@oracle.com 	int		cur_num = 0;
328113013Sglenn.lagasse@oracle.com 
328213013Sglenn.lagasse@oracle.com 	errno = 0;
328313013Sglenn.lagasse@oracle.com 
328413013Sglenn.lagasse@oracle.com 	/*
328513013Sglenn.lagasse@oracle.com 	 * Check if obe_name is already in an auto BE name format.
328613013Sglenn.lagasse@oracle.com 	 * If it is, then strip off the increment number to get the
328713013Sglenn.lagasse@oracle.com 	 * base name.
328813013Sglenn.lagasse@oracle.com 	 */
328913013Sglenn.lagasse@oracle.com 	(void) strlcpy(base_be_name, obe_name, sizeof (base_be_name));
329013013Sglenn.lagasse@oracle.com 
329113013Sglenn.lagasse@oracle.com 	if ((num_str = strrchr(base_be_name, BE_AUTO_NAME_DELIM))
329213013Sglenn.lagasse@oracle.com 	    != NULL) {
329313013Sglenn.lagasse@oracle.com 		/* Make sure remaining string is all digits */
329413013Sglenn.lagasse@oracle.com 		c = num_str + 1;
329513013Sglenn.lagasse@oracle.com 		while (c[0] != '\0' && isdigit(c[0]))
329613013Sglenn.lagasse@oracle.com 			c++;
329713013Sglenn.lagasse@oracle.com 		/*
329813013Sglenn.lagasse@oracle.com 		 * If we're now at the end of the string strip off the
329913013Sglenn.lagasse@oracle.com 		 * increment number.
330013013Sglenn.lagasse@oracle.com 		 */
330113013Sglenn.lagasse@oracle.com 		if (c[0] == '\0')
330213013Sglenn.lagasse@oracle.com 			num_str[0] = '\0';
330313013Sglenn.lagasse@oracle.com 	}
330413013Sglenn.lagasse@oracle.com 
330513013Sglenn.lagasse@oracle.com 	if (zone_be) {
330613013Sglenn.lagasse@oracle.com 		if (be_container_ds == NULL)
330713013Sglenn.lagasse@oracle.com 			return (NULL);
330813013Sglenn.lagasse@oracle.com 		if (be_get_zone_be_list(obe_name, be_container_ds,
330913013Sglenn.lagasse@oracle.com 		    &be_nodes) != BE_SUCCESS) {
331013013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_get_auto_name: "
331113013Sglenn.lagasse@oracle.com 			    "be_get_zone_be_list failed\n"));
331213013Sglenn.lagasse@oracle.com 			return (NULL);
331313013Sglenn.lagasse@oracle.com 		}
331413013Sglenn.lagasse@oracle.com 	} else if (_be_list(NULL, &be_nodes) != BE_SUCCESS) {
331513013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_get_auto_name: be_list failed\n"));
331613013Sglenn.lagasse@oracle.com 		return (NULL);
331713013Sglenn.lagasse@oracle.com 	}
331813013Sglenn.lagasse@oracle.com 
331913013Sglenn.lagasse@oracle.com 	for (cur_be = be_nodes; cur_be != NULL; cur_be = cur_be->be_next_node) {
332013013Sglenn.lagasse@oracle.com 		(void) strlcpy(cur_be_name, cur_be->be_node_name,
332113013Sglenn.lagasse@oracle.com 		    sizeof (cur_be_name));
332213013Sglenn.lagasse@oracle.com 
332313013Sglenn.lagasse@oracle.com 		/* If cur_be_name doesn't match at least base be name, skip. */
332413013Sglenn.lagasse@oracle.com 		if (strncmp(cur_be_name, base_be_name, strlen(base_be_name))
332513013Sglenn.lagasse@oracle.com 		    != 0)
332613013Sglenn.lagasse@oracle.com 			continue;
332713013Sglenn.lagasse@oracle.com 
332813013Sglenn.lagasse@oracle.com 		/* Get the string following the base be name */
332913013Sglenn.lagasse@oracle.com 		num_str = cur_be_name + strlen(base_be_name);
333013013Sglenn.lagasse@oracle.com 
333113013Sglenn.lagasse@oracle.com 		/*
333213013Sglenn.lagasse@oracle.com 		 * If nothing follows the base be name, this cur_be_name
333313013Sglenn.lagasse@oracle.com 		 * is the BE named with the base be name, skip.
333413013Sglenn.lagasse@oracle.com 		 */
333513013Sglenn.lagasse@oracle.com 		if (num_str == NULL || num_str[0] == '\0')
333613013Sglenn.lagasse@oracle.com 			continue;
333713013Sglenn.lagasse@oracle.com 
333813013Sglenn.lagasse@oracle.com 		/*
333913013Sglenn.lagasse@oracle.com 		 * Remove the name delimiter.  If its not there,
334013013Sglenn.lagasse@oracle.com 		 * cur_be_name isn't part of this BE name stream, skip.
334113013Sglenn.lagasse@oracle.com 		 */
334213013Sglenn.lagasse@oracle.com 		if (num_str[0] == BE_AUTO_NAME_DELIM)
334313013Sglenn.lagasse@oracle.com 			num_str++;
334413013Sglenn.lagasse@oracle.com 		else
334513013Sglenn.lagasse@oracle.com 			continue;
334613013Sglenn.lagasse@oracle.com 
334713013Sglenn.lagasse@oracle.com 		/* Make sure remaining string is all digits */
334813013Sglenn.lagasse@oracle.com 		c = num_str;
334913013Sglenn.lagasse@oracle.com 		while (c[0] != '\0' && isdigit(c[0]))
335013013Sglenn.lagasse@oracle.com 			c++;
335113013Sglenn.lagasse@oracle.com 		if (c[0] != '\0')
335213013Sglenn.lagasse@oracle.com 			continue;
335313013Sglenn.lagasse@oracle.com 
335413013Sglenn.lagasse@oracle.com 		/* Convert the number string to an int */
335513013Sglenn.lagasse@oracle.com 		cur_num = atoi(num_str);
335613013Sglenn.lagasse@oracle.com 
335713013Sglenn.lagasse@oracle.com 		/*
335813013Sglenn.lagasse@oracle.com 		 * If failed to convert the string, skip it.  If its too
335913013Sglenn.lagasse@oracle.com 		 * long to be converted to an int, we wouldn't auto generate
336013013Sglenn.lagasse@oracle.com 		 * this number anyway so there couldn't be a conflict.
336113013Sglenn.lagasse@oracle.com 		 * We treat it as a manually created BE name.
336213013Sglenn.lagasse@oracle.com 		 */
336313013Sglenn.lagasse@oracle.com 		if (cur_num == 0 && errno == EINVAL)
336413013Sglenn.lagasse@oracle.com 			continue;
336513013Sglenn.lagasse@oracle.com 
336613013Sglenn.lagasse@oracle.com 		/*
336713013Sglenn.lagasse@oracle.com 		 * Compare current number to current max number,
336813013Sglenn.lagasse@oracle.com 		 * take higher of the two.
336913013Sglenn.lagasse@oracle.com 		 */
337013013Sglenn.lagasse@oracle.com 		if (cur_num > num)
337113013Sglenn.lagasse@oracle.com 			num = cur_num;
337213013Sglenn.lagasse@oracle.com 	}
337313013Sglenn.lagasse@oracle.com 
337413013Sglenn.lagasse@oracle.com 	/*
337513013Sglenn.lagasse@oracle.com 	 * Store off a copy of 'num' incase we need it later.  If incrementing
337613013Sglenn.lagasse@oracle.com 	 * 'num' causes it to roll over, this means 'num' is the largest
337713013Sglenn.lagasse@oracle.com 	 * positive int possible; we'll need it later in the loop to determine
337813013Sglenn.lagasse@oracle.com 	 * if we've exhausted all possible increment numbers.  We store it in
337913013Sglenn.lagasse@oracle.com 	 * 'cur_num'.
338013013Sglenn.lagasse@oracle.com 	 */
338113013Sglenn.lagasse@oracle.com 	cur_num = num;
338213013Sglenn.lagasse@oracle.com 
338313013Sglenn.lagasse@oracle.com 	/* Increment 'num' to get new auto BE name number */
338413013Sglenn.lagasse@oracle.com 	if (++num <= 0) {
338513013Sglenn.lagasse@oracle.com 		int ret = 0;
338613013Sglenn.lagasse@oracle.com 
338713013Sglenn.lagasse@oracle.com 		/*
338813013Sglenn.lagasse@oracle.com 		 * Since incrementing 'num' caused it to rollover, start
338913013Sglenn.lagasse@oracle.com 		 * over at 0 and find the first available number.
339013013Sglenn.lagasse@oracle.com 		 */
339113013Sglenn.lagasse@oracle.com 		for (num = 0; num < cur_num; num++) {
339213013Sglenn.lagasse@oracle.com 
339313013Sglenn.lagasse@oracle.com 			(void) snprintf(cur_be_name, sizeof (cur_be_name),
339413013Sglenn.lagasse@oracle.com 			    "%s%c%d", base_be_name, BE_AUTO_NAME_DELIM, num);
339513013Sglenn.lagasse@oracle.com 
339613013Sglenn.lagasse@oracle.com 			ret = zpool_iter(g_zfs, be_exists_callback,
339713013Sglenn.lagasse@oracle.com 			    cur_be_name);
339813013Sglenn.lagasse@oracle.com 
339913013Sglenn.lagasse@oracle.com 			if (ret == 0) {
340013013Sglenn.lagasse@oracle.com 				/*
340113013Sglenn.lagasse@oracle.com 				 * BE name doesn't exist, break out
340213013Sglenn.lagasse@oracle.com 				 * to use 'num'.
340313013Sglenn.lagasse@oracle.com 				 */
340413013Sglenn.lagasse@oracle.com 				break;
340513013Sglenn.lagasse@oracle.com 			} else if (ret == 1) {
340613013Sglenn.lagasse@oracle.com 				/* BE name exists, continue looking */
340713013Sglenn.lagasse@oracle.com 				continue;
340813013Sglenn.lagasse@oracle.com 			} else {
340913013Sglenn.lagasse@oracle.com 				be_print_err(gettext("be_get_auto_name: "
341013013Sglenn.lagasse@oracle.com 				    "zpool_iter failed: %s\n"),
341113013Sglenn.lagasse@oracle.com 				    libzfs_error_description(g_zfs));
341213013Sglenn.lagasse@oracle.com 				be_free_list(be_nodes);
341313013Sglenn.lagasse@oracle.com 				return (NULL);
341413013Sglenn.lagasse@oracle.com 			}
341513013Sglenn.lagasse@oracle.com 		}
341613013Sglenn.lagasse@oracle.com 
341713013Sglenn.lagasse@oracle.com 		/*
341813013Sglenn.lagasse@oracle.com 		 * If 'num' equals 'cur_num', we've exhausted all possible
341913013Sglenn.lagasse@oracle.com 		 * auto BE names for this base BE name.
342013013Sglenn.lagasse@oracle.com 		 */
342113013Sglenn.lagasse@oracle.com 		if (num == cur_num) {
342213013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_get_auto_name: "
342313013Sglenn.lagasse@oracle.com 			    "No more available auto BE names for base "
342413013Sglenn.lagasse@oracle.com 			    "BE name %s\n"), base_be_name);
342513013Sglenn.lagasse@oracle.com 			be_free_list(be_nodes);
342613013Sglenn.lagasse@oracle.com 			return (NULL);
342713013Sglenn.lagasse@oracle.com 		}
342813013Sglenn.lagasse@oracle.com 	}
342913013Sglenn.lagasse@oracle.com 
343013013Sglenn.lagasse@oracle.com 	be_free_list(be_nodes);
343113013Sglenn.lagasse@oracle.com 
343213013Sglenn.lagasse@oracle.com 	/*
343313013Sglenn.lagasse@oracle.com 	 * Generate string for auto BE name.
343413013Sglenn.lagasse@oracle.com 	 */
343513013Sglenn.lagasse@oracle.com 	(void) snprintf(auto_be_name, sizeof (auto_be_name), "%s%c%d",
343613013Sglenn.lagasse@oracle.com 	    base_be_name, BE_AUTO_NAME_DELIM, num);
343713013Sglenn.lagasse@oracle.com 
343813013Sglenn.lagasse@oracle.com 	if ((c = strdup(auto_be_name)) == NULL) {
343913013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_get_auto_name: "
344013013Sglenn.lagasse@oracle.com 		    "memory allocation failed\n"));
344113013Sglenn.lagasse@oracle.com 		return (NULL);
344213013Sglenn.lagasse@oracle.com 	}
344313013Sglenn.lagasse@oracle.com 
344413013Sglenn.lagasse@oracle.com 	return (c);
344513013Sglenn.lagasse@oracle.com }
344613013Sglenn.lagasse@oracle.com 
344713013Sglenn.lagasse@oracle.com /*
344813013Sglenn.lagasse@oracle.com  * Function:	be_create_menu
344913013Sglenn.lagasse@oracle.com  * Description:
345013013Sglenn.lagasse@oracle.com  *		This function is used if no menu.lst file exists. In
345113013Sglenn.lagasse@oracle.com  *		this case a new file is created and if needed default
345213013Sglenn.lagasse@oracle.com  *		lines are added to the file.
345313013Sglenn.lagasse@oracle.com  * Parameters:
345413013Sglenn.lagasse@oracle.com  *		pool - The name of the pool the menu.lst file is on
345513013Sglenn.lagasse@oracle.com  *		pool_mntpt - The mountpoint for the pool we're using.
345613013Sglenn.lagasse@oracle.com  *		menu_file - The name of the file we're creating.
345713013Sglenn.lagasse@oracle.com  *		menu_fp - A pointer to the file pointer of the file we
345813013Sglenn.lagasse@oracle.com  *			  created. This is also used to pass back the file
345913013Sglenn.lagasse@oracle.com  *			  pointer to the newly created file.
346013013Sglenn.lagasse@oracle.com  *		mode - the original mode used for the failed attempt to
346113013Sglenn.lagasse@oracle.com  *		       non-existent file.
346213013Sglenn.lagasse@oracle.com  * Returns:
346313013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
346413013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
346513013Sglenn.lagasse@oracle.com  * Scope:
346613013Sglenn.lagasse@oracle.com  *		Private
346713013Sglenn.lagasse@oracle.com  */
346813013Sglenn.lagasse@oracle.com static int
be_create_menu(char * pool,char * pool_mntpt,char * menu_file,FILE ** menu_fp,char * mode)346913013Sglenn.lagasse@oracle.com be_create_menu(
347013013Sglenn.lagasse@oracle.com 	char *pool,
347113013Sglenn.lagasse@oracle.com 	char *pool_mntpt,
347213013Sglenn.lagasse@oracle.com 	char *menu_file,
347313013Sglenn.lagasse@oracle.com 	FILE **menu_fp,
347413013Sglenn.lagasse@oracle.com 	char *mode)
347513013Sglenn.lagasse@oracle.com {
347613013Sglenn.lagasse@oracle.com 	be_node_list_t	*be_nodes = NULL;
347713013Sglenn.lagasse@oracle.com 	char add_default_cmd[BUFSIZ];
347813013Sglenn.lagasse@oracle.com 	char *menu_path = NULL;
347913013Sglenn.lagasse@oracle.com 	char *be_rpool = NULL;
348013013Sglenn.lagasse@oracle.com 	char *be_name = NULL;
348113013Sglenn.lagasse@oracle.com 
348213013Sglenn.lagasse@oracle.com 	errno = 0;
348313013Sglenn.lagasse@oracle.com 
348413013Sglenn.lagasse@oracle.com 	if (menu_file == NULL || menu_fp == NULL || mode == NULL)
348513013Sglenn.lagasse@oracle.com 		return (BE_ERR_INVAL);
348613013Sglenn.lagasse@oracle.com 
348713013Sglenn.lagasse@oracle.com 	menu_path = strdup(menu_file);
348813013Sglenn.lagasse@oracle.com 	if (menu_path == NULL)
348913013Sglenn.lagasse@oracle.com 		return (BE_ERR_NOMEM);
349013013Sglenn.lagasse@oracle.com 
349113013Sglenn.lagasse@oracle.com 	(void) dirname(menu_path);
349213013Sglenn.lagasse@oracle.com 	if (*menu_path == '.') {
349313013Sglenn.lagasse@oracle.com 		free(menu_path);
349413013Sglenn.lagasse@oracle.com 		return (BE_ERR_BAD_MENU_PATH);
349513013Sglenn.lagasse@oracle.com 	}
349613013Sglenn.lagasse@oracle.com 	if (mkdirp(menu_path,
349713013Sglenn.lagasse@oracle.com 	    S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1 &&
349813013Sglenn.lagasse@oracle.com 	    errno != EEXIST) {
349913013Sglenn.lagasse@oracle.com 		free(menu_path);
350013013Sglenn.lagasse@oracle.com 		be_print_err(gettext("be_create_menu: Failed to create the %s "
350113013Sglenn.lagasse@oracle.com 		    "directory: %s\n"), menu_path, strerror(errno));
350213013Sglenn.lagasse@oracle.com 		return (errno_to_be_err(errno));
350313013Sglenn.lagasse@oracle.com 	}
350413013Sglenn.lagasse@oracle.com 	free(menu_path);
350513013Sglenn.lagasse@oracle.com 
350613013Sglenn.lagasse@oracle.com 	/*
350713013Sglenn.lagasse@oracle.com 	 * Check to see if this system supports grub
350813013Sglenn.lagasse@oracle.com 	 */
350913013Sglenn.lagasse@oracle.com 	if (be_has_grub()) {
351013013Sglenn.lagasse@oracle.com 		char be_run_cmd_errbuf[BUFSIZ];
351113013Sglenn.lagasse@oracle.com 		/*
351213013Sglenn.lagasse@oracle.com 		 * The grub menu is missing so we need to create it
351313013Sglenn.lagasse@oracle.com 		 * and fill in the first few lines.
351413013Sglenn.lagasse@oracle.com 		 */
351513013Sglenn.lagasse@oracle.com 		(void) snprintf(add_default_cmd, sizeof (add_default_cmd),
351613013Sglenn.lagasse@oracle.com 		    "%s add_splash_image_to_grub_menu %s",
351713013Sglenn.lagasse@oracle.com 		    INST_ICT, pool_mntpt);
351813013Sglenn.lagasse@oracle.com 		if (be_run_cmd(add_default_cmd, be_run_cmd_errbuf, BUFSIZ,
351913013Sglenn.lagasse@oracle.com 		    NULL, 0) != BE_SUCCESS) {
352013013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_create_menu: "
352113013Sglenn.lagasse@oracle.com 			    "add_splash_image_to_grub_menu ICT failed.\n"));
352213013Sglenn.lagasse@oracle.com 			be_print_err(gettext("  Command: \"%s\"\n"),
352313013Sglenn.lagasse@oracle.com 			    add_default_cmd);
352413013Sglenn.lagasse@oracle.com 			be_print_err(be_run_cmd_errbuf);
352513013Sglenn.lagasse@oracle.com 			return (BE_ERR_ADD_SPLASH_ICT);
352613013Sglenn.lagasse@oracle.com 		}
352713013Sglenn.lagasse@oracle.com 	} else {
352813013Sglenn.lagasse@oracle.com 		/*
352913013Sglenn.lagasse@oracle.com 		 * The menu file doesn't exist so we need to create a
353013013Sglenn.lagasse@oracle.com 		 * blank file.
353113013Sglenn.lagasse@oracle.com 		 */
353213013Sglenn.lagasse@oracle.com 		FILE *temp_fp = fopen(menu_file, "w+");
353313013Sglenn.lagasse@oracle.com 		if (temp_fp == NULL) {
353413013Sglenn.lagasse@oracle.com 			*menu_fp = NULL;
353513013Sglenn.lagasse@oracle.com 			return (errno_to_be_err(errno));
353613013Sglenn.lagasse@oracle.com 		}
353713013Sglenn.lagasse@oracle.com 		(void) fclose(temp_fp);
353813013Sglenn.lagasse@oracle.com 	}
353913013Sglenn.lagasse@oracle.com 
354013013Sglenn.lagasse@oracle.com 	/*
354113013Sglenn.lagasse@oracle.com 	 * Now we need to add all the BE's back into the the file.
354213013Sglenn.lagasse@oracle.com 	 */
354313013Sglenn.lagasse@oracle.com 	if (_be_list(NULL, &be_nodes) == BE_SUCCESS) {
354413013Sglenn.lagasse@oracle.com 		while (be_nodes != NULL) {
354513013Sglenn.lagasse@oracle.com 			if (strcmp(pool, be_nodes->be_rpool) == 0) {
354613013Sglenn.lagasse@oracle.com 				(void) be_append_menu(be_nodes->be_node_name,
354713013Sglenn.lagasse@oracle.com 				    be_nodes->be_rpool, NULL, NULL, NULL);
354813013Sglenn.lagasse@oracle.com 			}
354913013Sglenn.lagasse@oracle.com 			if (be_nodes->be_active_on_boot) {
355013013Sglenn.lagasse@oracle.com 				be_rpool = strdup(be_nodes->be_rpool);
355113013Sglenn.lagasse@oracle.com 				be_name = strdup(be_nodes->be_node_name);
355213013Sglenn.lagasse@oracle.com 			}
355313013Sglenn.lagasse@oracle.com 
355413013Sglenn.lagasse@oracle.com 			be_nodes = be_nodes->be_next_node;
355513013Sglenn.lagasse@oracle.com 		}
355613013Sglenn.lagasse@oracle.com 	}
355713013Sglenn.lagasse@oracle.com 	be_free_list(be_nodes);
355813013Sglenn.lagasse@oracle.com 
355913013Sglenn.lagasse@oracle.com 	/*
356013013Sglenn.lagasse@oracle.com 	 * Check to see if this system supports grub
356113013Sglenn.lagasse@oracle.com 	 */
356213013Sglenn.lagasse@oracle.com 	if (be_has_grub()) {
356313013Sglenn.lagasse@oracle.com 		int err = be_change_grub_default(be_name, be_rpool);
356413013Sglenn.lagasse@oracle.com 		if (err != BE_SUCCESS)
356513013Sglenn.lagasse@oracle.com 			return (err);
356613013Sglenn.lagasse@oracle.com 	}
356713013Sglenn.lagasse@oracle.com 	*menu_fp = fopen(menu_file, mode);
356813013Sglenn.lagasse@oracle.com 	if (*menu_fp == NULL)
356913013Sglenn.lagasse@oracle.com 		return (errno_to_be_err(errno));
357013013Sglenn.lagasse@oracle.com 
357113013Sglenn.lagasse@oracle.com 	return (BE_SUCCESS);
357213013Sglenn.lagasse@oracle.com }
357313013Sglenn.lagasse@oracle.com 
357413013Sglenn.lagasse@oracle.com /*
357513013Sglenn.lagasse@oracle.com  * Function:	be_open_menu
357613013Sglenn.lagasse@oracle.com  * Description:
357713013Sglenn.lagasse@oracle.com  *		This function is used it open the menu.lst file. If this
357813013Sglenn.lagasse@oracle.com  *              file does not exist be_create_menu is called to create it
357913013Sglenn.lagasse@oracle.com  *              and the open file pointer is returned. If the file does
358013013Sglenn.lagasse@oracle.com  *              exist it is simply opened using the mode passed in.
358113013Sglenn.lagasse@oracle.com  * Parameters:
358213013Sglenn.lagasse@oracle.com  *		pool - The name of the pool the menu.lst file is on
358313013Sglenn.lagasse@oracle.com  *		pool_mntpt - The mountpoint for the pool we're using.
358413013Sglenn.lagasse@oracle.com  *			     The mountpoint is used since the mountpoint
358513013Sglenn.lagasse@oracle.com  *			     name can differ from the pool name.
358613013Sglenn.lagasse@oracle.com  *		menu_file - The name of the file we're opening.
358713013Sglenn.lagasse@oracle.com  *		menu_fp - A pointer to the file pointer of the file we're
358813013Sglenn.lagasse@oracle.com  *			  opening. This is also used to pass back the file
358913013Sglenn.lagasse@oracle.com  *			  pointer.
359013013Sglenn.lagasse@oracle.com  *		mode - the original mode to be used for opening the menu.lst
359113013Sglenn.lagasse@oracle.com  *                     file.
359213013Sglenn.lagasse@oracle.com  *              create_menu - If this is true and the menu.lst file does not
359313013Sglenn.lagasse@oracle.com  *                            exist we will attempt to re-create it. However
359413013Sglenn.lagasse@oracle.com  *                            if it's false the error returned from the fopen
359513013Sglenn.lagasse@oracle.com  *                            will be returned.
359613013Sglenn.lagasse@oracle.com  * Returns:
359713013Sglenn.lagasse@oracle.com  *		BE_SUCCESS - Success
359813013Sglenn.lagasse@oracle.com  *		be_errno_t - Failure
359913013Sglenn.lagasse@oracle.com  * Scope:
360013013Sglenn.lagasse@oracle.com  *		Private
360113013Sglenn.lagasse@oracle.com  */
360213013Sglenn.lagasse@oracle.com static int
be_open_menu(char * pool,char * pool_mntpt,char * menu_file,FILE ** menu_fp,char * mode,boolean_t create_menu)360313013Sglenn.lagasse@oracle.com be_open_menu(
360413013Sglenn.lagasse@oracle.com 	char *pool,
360513013Sglenn.lagasse@oracle.com 	char *pool_mntpt,
360613013Sglenn.lagasse@oracle.com 	char *menu_file,
360713013Sglenn.lagasse@oracle.com 	FILE **menu_fp,
360813013Sglenn.lagasse@oracle.com 	char *mode,
360913013Sglenn.lagasse@oracle.com 	boolean_t create_menu)
361013013Sglenn.lagasse@oracle.com {
361113013Sglenn.lagasse@oracle.com 	int	err = 0;
361213013Sglenn.lagasse@oracle.com 	boolean_t	set_print = B_FALSE;
361313013Sglenn.lagasse@oracle.com 
361413013Sglenn.lagasse@oracle.com 	*menu_fp = fopen(menu_file, mode);
361513013Sglenn.lagasse@oracle.com 	err = errno;
361613013Sglenn.lagasse@oracle.com 	if (*menu_fp == NULL) {
361713013Sglenn.lagasse@oracle.com 		if (err == ENOENT && create_menu) {
361813013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_open_menu: menu.lst "
361913013Sglenn.lagasse@oracle.com 			    "file %s does not exist,\n"), menu_file);
362013013Sglenn.lagasse@oracle.com 			if (!do_print) {
362113013Sglenn.lagasse@oracle.com 				set_print = B_TRUE;
362213013Sglenn.lagasse@oracle.com 				do_print = B_TRUE;
362313013Sglenn.lagasse@oracle.com 			}
362413013Sglenn.lagasse@oracle.com 			be_print_err(gettext("WARNING: menu.lst "
362513013Sglenn.lagasse@oracle.com 			    "file %s does not exist,\n         generating "
362613013Sglenn.lagasse@oracle.com 			    "a new menu.lst file\n"), menu_file);
362713013Sglenn.lagasse@oracle.com 			if (set_print)
362813013Sglenn.lagasse@oracle.com 				do_print = B_FALSE;
362913013Sglenn.lagasse@oracle.com 			err = 0;
363013013Sglenn.lagasse@oracle.com 			if ((err = be_create_menu(pool, pool_mntpt, menu_file,
363113013Sglenn.lagasse@oracle.com 			    menu_fp, mode)) == ENOENT)
363213013Sglenn.lagasse@oracle.com 				return (BE_ERR_NO_MENU);
363313013Sglenn.lagasse@oracle.com 			else if (err != BE_SUCCESS)
363413013Sglenn.lagasse@oracle.com 				return (err);
363513013Sglenn.lagasse@oracle.com 			else if (*menu_fp == NULL)
363613013Sglenn.lagasse@oracle.com 				return (BE_ERR_NO_MENU);
363713013Sglenn.lagasse@oracle.com 		} else {
363813013Sglenn.lagasse@oracle.com 			be_print_err(gettext("be_open_menu: failed "
363913013Sglenn.lagasse@oracle.com 			    "to open menu.lst file %s\n"), menu_file);
364013013Sglenn.lagasse@oracle.com 			if (err == ENOENT)
364113013Sglenn.lagasse@oracle.com 				return (BE_ERR_NO_MENU);
364213013Sglenn.lagasse@oracle.com 			else
364313013Sglenn.lagasse@oracle.com 				return (errno_to_be_err(err));
364413013Sglenn.lagasse@oracle.com 		}
364513013Sglenn.lagasse@oracle.com 	}
364613013Sglenn.lagasse@oracle.com 	return (BE_SUCCESS);
364713013Sglenn.lagasse@oracle.com }
3648