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