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