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