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