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. 24f169c0eaSGlenn Lagasse */ 25f169c0eaSGlenn Lagasse 267e0e2549SAlexander Eremin /* 271a902ef8SHans Rosenfeld * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 281a47de4eSToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com> 29*71668a2fSAndy Fiddaman * Copyright 2018 OmniOS Community Edition (OmniOSce) Association. 307e0e2549SAlexander Eremin */ 317e0e2549SAlexander Eremin 32f169c0eaSGlenn Lagasse #include <assert.h> 33f169c0eaSGlenn Lagasse #include <libintl.h> 34f169c0eaSGlenn Lagasse #include <libnvpair.h> 35f169c0eaSGlenn Lagasse #include <libzfs.h> 36f169c0eaSGlenn Lagasse #include <stdio.h> 37f169c0eaSGlenn Lagasse #include <stdlib.h> 38f169c0eaSGlenn Lagasse #include <string.h> 391a902ef8SHans Rosenfeld #include <strings.h> 40f169c0eaSGlenn Lagasse #include <errno.h> 41f169c0eaSGlenn Lagasse #include <sys/mnttab.h> 42f169c0eaSGlenn Lagasse #include <sys/types.h> 43f169c0eaSGlenn Lagasse #include <sys/stat.h> 441a902ef8SHans Rosenfeld #include <fcntl.h> 45f169c0eaSGlenn Lagasse #include <unistd.h> 461a902ef8SHans Rosenfeld #include <sys/efi_partition.h> 47f169c0eaSGlenn Lagasse 48f169c0eaSGlenn Lagasse #include <libbe.h> 49f169c0eaSGlenn Lagasse #include <libbe_priv.h> 50f169c0eaSGlenn Lagasse 51f169c0eaSGlenn Lagasse char *mnttab = MNTTAB; 52f169c0eaSGlenn Lagasse 53f169c0eaSGlenn Lagasse /* 54f169c0eaSGlenn Lagasse * Private function prototypes 55f169c0eaSGlenn Lagasse */ 56f169c0eaSGlenn Lagasse static int set_bootfs(char *boot_rpool, char *be_root_ds); 57f169c0eaSGlenn Lagasse static int set_canmount(be_node_list_t *, char *); 58a63c99a2SToomas Soome static boolean_t be_do_install_mbr(char *, nvlist_t *); 59a63c99a2SToomas Soome static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *, 60c7c0ceafSToomas Soome char *, uint16_t); 61c7c0ceafSToomas Soome static int be_do_installboot(be_transaction_data_t *, uint16_t); 62f169c0eaSGlenn Lagasse static int be_get_grub_vers(be_transaction_data_t *, char **, char **); 63f169c0eaSGlenn Lagasse static int get_ver_from_capfile(char *, char **); 64f169c0eaSGlenn Lagasse static int be_promote_zone_ds(char *, char *); 65f169c0eaSGlenn Lagasse static int be_promote_ds_callback(zfs_handle_t *, void *); 66f169c0eaSGlenn Lagasse 67f169c0eaSGlenn Lagasse /* ******************************************************************** */ 68f169c0eaSGlenn Lagasse /* Public Functions */ 69f169c0eaSGlenn Lagasse /* ******************************************************************** */ 70f169c0eaSGlenn Lagasse 71f169c0eaSGlenn Lagasse /* 72f169c0eaSGlenn Lagasse * Function: be_activate 73f169c0eaSGlenn Lagasse * Description: Calls _be_activate which activates the BE named in the 74f169c0eaSGlenn Lagasse * attributes passed in through be_attrs. The process of 75f169c0eaSGlenn Lagasse * activation sets the bootfs property of the root pool, resets 76f169c0eaSGlenn Lagasse * the canmount property to noauto, and sets the default in the 77f169c0eaSGlenn Lagasse * grub menu to the entry corresponding to the entry for the named 78f169c0eaSGlenn Lagasse * BE. 79f169c0eaSGlenn Lagasse * Parameters: 80f169c0eaSGlenn Lagasse * be_attrs - pointer to nvlist_t of attributes being passed in. 81f169c0eaSGlenn Lagasse * The follow attribute values are used by this function: 82f169c0eaSGlenn Lagasse * 83f169c0eaSGlenn Lagasse * BE_ATTR_ORIG_BE_NAME *required 84f169c0eaSGlenn Lagasse * Return: 85f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 86f169c0eaSGlenn Lagasse * be_errno_t - Failure 87f169c0eaSGlenn Lagasse * Scope: 88f169c0eaSGlenn Lagasse * Public 89f169c0eaSGlenn Lagasse */ 90f169c0eaSGlenn Lagasse int 91f169c0eaSGlenn Lagasse be_activate(nvlist_t *be_attrs) 92f169c0eaSGlenn Lagasse { 93f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 94f169c0eaSGlenn Lagasse char *be_name = NULL; 95f169c0eaSGlenn Lagasse 96f169c0eaSGlenn Lagasse /* Initialize libzfs handle */ 97f169c0eaSGlenn Lagasse if (!be_zfs_init()) 98f169c0eaSGlenn Lagasse return (BE_ERR_INIT); 99f169c0eaSGlenn Lagasse 100f169c0eaSGlenn Lagasse /* Get the BE name to activate */ 101f169c0eaSGlenn Lagasse if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name) 102f169c0eaSGlenn Lagasse != 0) { 103f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to " 104f169c0eaSGlenn Lagasse "lookup BE_ATTR_ORIG_BE_NAME attribute\n")); 105f169c0eaSGlenn Lagasse be_zfs_fini(); 106f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 107f169c0eaSGlenn Lagasse } 108f169c0eaSGlenn Lagasse 109f169c0eaSGlenn Lagasse /* Validate BE name */ 110f169c0eaSGlenn Lagasse if (!be_valid_be_name(be_name)) { 111f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: invalid BE name %s\n"), 112f169c0eaSGlenn Lagasse be_name); 113f169c0eaSGlenn Lagasse be_zfs_fini(); 114f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 115f169c0eaSGlenn Lagasse } 116f169c0eaSGlenn Lagasse 117f169c0eaSGlenn Lagasse ret = _be_activate(be_name); 118f169c0eaSGlenn Lagasse 119f169c0eaSGlenn Lagasse be_zfs_fini(); 120f169c0eaSGlenn Lagasse 121f169c0eaSGlenn Lagasse return (ret); 122f169c0eaSGlenn Lagasse } 123f169c0eaSGlenn Lagasse 124c7c0ceafSToomas Soome /* 125c7c0ceafSToomas Soome * Function: be_installboot 126c7c0ceafSToomas Soome * Description: Calls be_do_installboot to install/update bootloader on 127c7c0ceafSToomas Soome * pool passed in through be_attrs. The primary consumer is 128c7c0ceafSToomas Soome * bootadm command to avoid duplication of the code. 129c7c0ceafSToomas Soome * Parameters: 130c7c0ceafSToomas Soome * be_attrs - pointer to nvlist_t of attributes being passed in. 131c7c0ceafSToomas Soome * The following attribute values are used: 132c7c0ceafSToomas Soome * 133c7c0ceafSToomas Soome * BE_ATTR_ORIG_BE_NAME *required 134c7c0ceafSToomas Soome * BE_ATTR_ORIG_BE_POOL *required 135c7c0ceafSToomas Soome * BE_ATTR_ORIG_BE_ROOT *required 136c7c0ceafSToomas Soome * BE_ATTR_INSTALL_FLAGS optional 137c7c0ceafSToomas Soome * 138c7c0ceafSToomas Soome * Return: 139c7c0ceafSToomas Soome * BE_SUCCESS - Success 140c7c0ceafSToomas Soome * be_errno_t - Failure 141c7c0ceafSToomas Soome * Scope: 142c7c0ceafSToomas Soome * Public 143c7c0ceafSToomas Soome */ 144c7c0ceafSToomas Soome int 145c7c0ceafSToomas Soome be_installboot(nvlist_t *be_attrs) 146c7c0ceafSToomas Soome { 147c7c0ceafSToomas Soome int ret = BE_SUCCESS; 148c7c0ceafSToomas Soome uint16_t flags = 0; 149c7c0ceafSToomas Soome uint16_t verbose; 150c7c0ceafSToomas Soome be_transaction_data_t bt = { 0 }; 151c7c0ceafSToomas Soome 152c7c0ceafSToomas Soome /* Get flags */ 153c7c0ceafSToomas Soome if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK, 154c7c0ceafSToomas Soome BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) { 155c7c0ceafSToomas Soome be_print_err(gettext("be_installboot: failed to lookup " 156c7c0ceafSToomas Soome "BE_ATTR_INSTALL_FLAGS attribute\n")); 157c7c0ceafSToomas Soome return (BE_ERR_INVAL); 158c7c0ceafSToomas Soome } 159c7c0ceafSToomas Soome 160c7c0ceafSToomas Soome /* Set verbose early, so we get all messages */ 161c7c0ceafSToomas Soome verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE; 162c7c0ceafSToomas Soome if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE) 163c7c0ceafSToomas Soome libbe_print_errors(B_TRUE); 164c7c0ceafSToomas Soome 165c7c0ceafSToomas Soome ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, 166c7c0ceafSToomas Soome &bt.obe_name); 167c7c0ceafSToomas Soome if (ret != 0) { 168c7c0ceafSToomas Soome be_print_err(gettext("be_installboot: failed to " 169c7c0ceafSToomas Soome "lookup BE_ATTR_ORIG_BE_NAME attribute\n")); 170c7c0ceafSToomas Soome return (BE_ERR_INVAL); 171c7c0ceafSToomas Soome } 172c7c0ceafSToomas Soome 173c7c0ceafSToomas Soome ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL, 174c7c0ceafSToomas Soome &bt.obe_zpool); 175c7c0ceafSToomas Soome if (ret != 0) { 176c7c0ceafSToomas Soome be_print_err(gettext("be_installboot: failed to " 177c7c0ceafSToomas Soome "lookup BE_ATTR_ORIG_BE_POOL attribute\n")); 178c7c0ceafSToomas Soome return (BE_ERR_INVAL); 179c7c0ceafSToomas Soome } 180c7c0ceafSToomas Soome 181c7c0ceafSToomas Soome ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT, 182c7c0ceafSToomas Soome &bt.obe_root_ds); 183c7c0ceafSToomas Soome if (ret != 0) { 184c7c0ceafSToomas Soome be_print_err(gettext("be_installboot: failed to " 185c7c0ceafSToomas Soome "lookup BE_ATTR_ORIG_BE_ROOT attribute\n")); 186c7c0ceafSToomas Soome return (BE_ERR_INVAL); 187c7c0ceafSToomas Soome } 188c7c0ceafSToomas Soome 189c7c0ceafSToomas Soome /* Initialize libzfs handle */ 190c7c0ceafSToomas Soome if (!be_zfs_init()) 191c7c0ceafSToomas Soome return (BE_ERR_INIT); 192c7c0ceafSToomas Soome 193c7c0ceafSToomas Soome ret = be_do_installboot(&bt, flags); 194c7c0ceafSToomas Soome 195c7c0ceafSToomas Soome be_zfs_fini(); 196c7c0ceafSToomas Soome 197c7c0ceafSToomas Soome return (ret); 198c7c0ceafSToomas Soome } 199c7c0ceafSToomas Soome 200f169c0eaSGlenn Lagasse /* ******************************************************************** */ 201f169c0eaSGlenn Lagasse /* Semi Private Functions */ 202f169c0eaSGlenn Lagasse /* ******************************************************************** */ 203f169c0eaSGlenn Lagasse 204f169c0eaSGlenn Lagasse /* 205f169c0eaSGlenn Lagasse * Function: _be_activate 206f169c0eaSGlenn Lagasse * Description: This does the actual work described in be_activate. 207f169c0eaSGlenn Lagasse * Parameters: 208f169c0eaSGlenn Lagasse * be_name - pointer to the name of BE to activate. 209f169c0eaSGlenn Lagasse * 210f169c0eaSGlenn Lagasse * Return: 211f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 212f169c0eaSGlenn Lagasse * be_errnot_t - Failure 213f169c0eaSGlenn Lagasse * Scope: 214f169c0eaSGlenn Lagasse * Public 215f169c0eaSGlenn Lagasse */ 216f169c0eaSGlenn Lagasse int 217f169c0eaSGlenn Lagasse _be_activate(char *be_name) 218f169c0eaSGlenn Lagasse { 219f169c0eaSGlenn Lagasse be_transaction_data_t cb = { 0 }; 220f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 221f169c0eaSGlenn Lagasse char root_ds[MAXPATHLEN]; 2227e0e2549SAlexander Eremin char active_ds[MAXPATHLEN]; 223f169c0eaSGlenn Lagasse be_node_list_t *be_nodes = NULL; 224f169c0eaSGlenn Lagasse uuid_t uu = {0}; 225f169c0eaSGlenn Lagasse int entry, ret = BE_SUCCESS; 226f169c0eaSGlenn Lagasse int zret = 0; 227f169c0eaSGlenn Lagasse 228f169c0eaSGlenn Lagasse /* 229f169c0eaSGlenn Lagasse * TODO: The BE needs to be validated to make sure that it is actually 230f169c0eaSGlenn Lagasse * a bootable BE. 231f169c0eaSGlenn Lagasse */ 232f169c0eaSGlenn Lagasse 233f169c0eaSGlenn Lagasse if (be_name == NULL) 234f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 235f169c0eaSGlenn Lagasse 236f169c0eaSGlenn Lagasse /* Set obe_name to be_name in the cb structure */ 237f169c0eaSGlenn Lagasse cb.obe_name = be_name; 238f169c0eaSGlenn Lagasse 239f169c0eaSGlenn Lagasse /* find which zpool the be is in */ 240f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) { 241f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to " 242f169c0eaSGlenn Lagasse "find zpool for BE (%s)\n"), cb.obe_name); 243f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT); 244f169c0eaSGlenn Lagasse } else if (zret < 0) { 245f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: " 246f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"), 247f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 248f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 249f169c0eaSGlenn Lagasse return (ret); 250f169c0eaSGlenn Lagasse } 251f169c0eaSGlenn Lagasse 252f169c0eaSGlenn Lagasse be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds)); 253f169c0eaSGlenn Lagasse cb.obe_root_ds = strdup(root_ds); 254f169c0eaSGlenn Lagasse 255f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID) { 256c7c0ceafSToomas Soome ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL); 257c7c0ceafSToomas Soome if (ret != BE_SUCCESS) 258f169c0eaSGlenn Lagasse return (ret); 259a63c99a2SToomas Soome 260f169c0eaSGlenn Lagasse if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) { 261f169c0eaSGlenn Lagasse if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool, 262f169c0eaSGlenn Lagasse NULL, NULL, NULL)) != BE_SUCCESS) { 263f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: Failed to " 264a63c99a2SToomas Soome "add BE (%s) to the menu\n"), 265f169c0eaSGlenn Lagasse cb.obe_name); 266f169c0eaSGlenn Lagasse goto done; 267f169c0eaSGlenn Lagasse } 268f169c0eaSGlenn Lagasse } 269f169c0eaSGlenn Lagasse if (be_has_grub()) { 270f169c0eaSGlenn Lagasse if ((ret = be_change_grub_default(cb.obe_name, 271f169c0eaSGlenn Lagasse cb.obe_zpool)) != BE_SUCCESS) { 272f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to " 273f169c0eaSGlenn Lagasse "change the default entry in menu.lst\n")); 274f169c0eaSGlenn Lagasse goto done; 275f169c0eaSGlenn Lagasse } 276f169c0eaSGlenn Lagasse } 277f169c0eaSGlenn Lagasse } 278f169c0eaSGlenn Lagasse 279*71668a2fSAndy Fiddaman if ((ret = _be_list(cb.obe_name, &be_nodes, BE_LIST_DEFAULT)) 280*71668a2fSAndy Fiddaman != BE_SUCCESS) { 281f169c0eaSGlenn Lagasse return (ret); 282f169c0eaSGlenn Lagasse } 283f169c0eaSGlenn Lagasse 284f169c0eaSGlenn Lagasse if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) { 285f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to set " 286f169c0eaSGlenn Lagasse "canmount dataset property\n")); 287f169c0eaSGlenn Lagasse goto done; 288f169c0eaSGlenn Lagasse } 289f169c0eaSGlenn Lagasse 2907e0e2549SAlexander Eremin if (getzoneid() == GLOBAL_ZONEID) { 2917e0e2549SAlexander Eremin if ((ret = set_bootfs(be_nodes->be_rpool, 2927e0e2549SAlexander Eremin root_ds)) != BE_SUCCESS) { 293f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to set " 294f169c0eaSGlenn Lagasse "bootfs pool property for %s\n"), root_ds); 295f169c0eaSGlenn Lagasse goto done; 296f169c0eaSGlenn Lagasse } 2977e0e2549SAlexander Eremin } 298f169c0eaSGlenn Lagasse 299f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) { 300f169c0eaSGlenn Lagasse /* 301f169c0eaSGlenn Lagasse * We don't need to close the zfs handle at this 302f169c0eaSGlenn Lagasse * point because The callback funtion 303f169c0eaSGlenn Lagasse * be_promote_ds_callback() will close it for us. 304f169c0eaSGlenn Lagasse */ 305f169c0eaSGlenn Lagasse if (be_promote_ds_callback(zhp, NULL) != 0) { 306f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: " 307f169c0eaSGlenn Lagasse "failed to activate the " 308f169c0eaSGlenn Lagasse "datasets for %s: %s\n"), 309f169c0eaSGlenn Lagasse root_ds, 310f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 311f169c0eaSGlenn Lagasse ret = BE_ERR_PROMOTE; 312f169c0eaSGlenn Lagasse goto done; 313f169c0eaSGlenn Lagasse } 314f169c0eaSGlenn Lagasse } else { 3157e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to open " 316f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), root_ds, 317f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 318f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 319f169c0eaSGlenn Lagasse goto done; 320f169c0eaSGlenn Lagasse } 321f169c0eaSGlenn Lagasse 322f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID && 323f169c0eaSGlenn Lagasse be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS && 324f169c0eaSGlenn Lagasse (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds)) 325f169c0eaSGlenn Lagasse != BE_SUCCESS) { 326f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to promote " 327f169c0eaSGlenn Lagasse "the active zonepath datasets for zones in BE %s\n"), 328f169c0eaSGlenn Lagasse cb.obe_name); 329f169c0eaSGlenn Lagasse } 330f169c0eaSGlenn Lagasse 3317e0e2549SAlexander Eremin if (getzoneid() != GLOBAL_ZONEID) { 3327e0e2549SAlexander Eremin if (!be_zone_compare_uuids(root_ds)) { 3337e0e2549SAlexander Eremin be_print_err(gettext("be_activate: activating zone " 3347e0e2549SAlexander Eremin "root dataset from non-active global BE is not " 3357e0e2549SAlexander Eremin "supported\n")); 3367e0e2549SAlexander Eremin ret = BE_ERR_NOTSUP; 3377e0e2549SAlexander Eremin goto done; 3387e0e2549SAlexander Eremin } 3397e0e2549SAlexander Eremin if ((zhp = zfs_open(g_zfs, root_ds, 3407e0e2549SAlexander Eremin ZFS_TYPE_FILESYSTEM)) == NULL) { 3417e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to open " 3427e0e2549SAlexander Eremin "dataset (%s): %s\n"), root_ds, 3437e0e2549SAlexander Eremin libzfs_error_description(g_zfs)); 3447e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs); 3457e0e2549SAlexander Eremin goto done; 3467e0e2549SAlexander Eremin } 3477e0e2549SAlexander Eremin /* Find current active zone root dataset */ 3487e0e2549SAlexander Eremin if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool, 3497e0e2549SAlexander Eremin active_ds, sizeof (active_ds))) != BE_SUCCESS) { 3507e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to find " 3517e0e2549SAlexander Eremin "active zone root dataset\n")); 3527e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 3537e0e2549SAlexander Eremin goto done; 3547e0e2549SAlexander Eremin } 3557e0e2549SAlexander Eremin /* Do nothing if requested BE is already active */ 3567e0e2549SAlexander Eremin if (strcmp(root_ds, active_ds) == 0) { 3577e0e2549SAlexander Eremin ret = BE_SUCCESS; 3587e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 3597e0e2549SAlexander Eremin goto done; 3607e0e2549SAlexander Eremin } 3617e0e2549SAlexander Eremin 3627e0e2549SAlexander Eremin /* Set active property for BE */ 3637e0e2549SAlexander Eremin if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) { 3647e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to set " 3657e0e2549SAlexander Eremin "active property (%s): %s\n"), root_ds, 3667e0e2549SAlexander Eremin libzfs_error_description(g_zfs)); 3677e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs); 3687e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 3697e0e2549SAlexander Eremin goto done; 3707e0e2549SAlexander Eremin } 3717e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 3727e0e2549SAlexander Eremin 3737e0e2549SAlexander Eremin /* Unset active property for old active root dataset */ 3747e0e2549SAlexander Eremin if ((zhp = zfs_open(g_zfs, active_ds, 3757e0e2549SAlexander Eremin ZFS_TYPE_FILESYSTEM)) == NULL) { 3767e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to open " 3777e0e2549SAlexander Eremin "dataset (%s): %s\n"), active_ds, 3787e0e2549SAlexander Eremin libzfs_error_description(g_zfs)); 3797e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs); 3807e0e2549SAlexander Eremin goto done; 3817e0e2549SAlexander Eremin } 3827e0e2549SAlexander Eremin if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) { 3837e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to unset " 3847e0e2549SAlexander Eremin "active property (%s): %s\n"), active_ds, 3857e0e2549SAlexander Eremin libzfs_error_description(g_zfs)); 3867e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs); 3877e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 3887e0e2549SAlexander Eremin goto done; 3897e0e2549SAlexander Eremin } 3907e0e2549SAlexander Eremin ZFS_CLOSE(zhp); 3917e0e2549SAlexander Eremin } 392f169c0eaSGlenn Lagasse done: 393f169c0eaSGlenn Lagasse be_free_list(be_nodes); 394f169c0eaSGlenn Lagasse return (ret); 395f169c0eaSGlenn Lagasse } 396f169c0eaSGlenn Lagasse 397f169c0eaSGlenn Lagasse /* 398f169c0eaSGlenn Lagasse * Function: be_activate_current_be 399f169c0eaSGlenn Lagasse * Description: Set the currently "active" BE to be "active on boot" 400f169c0eaSGlenn Lagasse * Paramters: 401f169c0eaSGlenn Lagasse * none 402f169c0eaSGlenn Lagasse * Returns: 403f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 404f169c0eaSGlenn Lagasse * be_errnot_t - Failure 405f169c0eaSGlenn Lagasse * Scope: 406f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 407f169c0eaSGlenn Lagasse */ 408f169c0eaSGlenn Lagasse int 409f169c0eaSGlenn Lagasse be_activate_current_be(void) 410f169c0eaSGlenn Lagasse { 411f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 412f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 }; 413f169c0eaSGlenn Lagasse 414f169c0eaSGlenn Lagasse if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) { 415f169c0eaSGlenn Lagasse return (ret); 416f169c0eaSGlenn Lagasse } 417f169c0eaSGlenn Lagasse 418f169c0eaSGlenn Lagasse if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) { 419f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate_current_be: failed to " 420f169c0eaSGlenn Lagasse "activate %s\n"), bt.obe_name); 421f169c0eaSGlenn Lagasse return (ret); 422f169c0eaSGlenn Lagasse } 423f169c0eaSGlenn Lagasse 424f169c0eaSGlenn Lagasse return (BE_SUCCESS); 425f169c0eaSGlenn Lagasse } 426f169c0eaSGlenn Lagasse 427f169c0eaSGlenn Lagasse /* 428f169c0eaSGlenn Lagasse * Function: be_is_active_on_boot 429f169c0eaSGlenn Lagasse * Description: Checks if the BE name passed in has the "active on boot" 430f169c0eaSGlenn Lagasse * property set to B_TRUE. 431f169c0eaSGlenn Lagasse * Paramters: 432f169c0eaSGlenn Lagasse * be_name - the name of the BE to check 433f169c0eaSGlenn Lagasse * Returns: 434f169c0eaSGlenn Lagasse * B_TRUE - if active on boot. 435f169c0eaSGlenn Lagasse * B_FALSE - if not active on boot. 436f169c0eaSGlenn Lagasse * Scope: 437f169c0eaSGlenn Lagasse * Semi-private (library wide use only) 438f169c0eaSGlenn Lagasse */ 439f169c0eaSGlenn Lagasse boolean_t 440f169c0eaSGlenn Lagasse be_is_active_on_boot(char *be_name) 441f169c0eaSGlenn Lagasse { 442f169c0eaSGlenn Lagasse be_node_list_t *be_node = NULL; 443f169c0eaSGlenn Lagasse 444f169c0eaSGlenn Lagasse if (be_name == NULL) { 445f169c0eaSGlenn Lagasse be_print_err(gettext("be_is_active_on_boot: " 446f169c0eaSGlenn Lagasse "be_name must not be NULL\n")); 447f169c0eaSGlenn Lagasse return (B_FALSE); 448f169c0eaSGlenn Lagasse } 449f169c0eaSGlenn Lagasse 450*71668a2fSAndy Fiddaman if (_be_list(be_name, &be_node, BE_LIST_DEFAULT) != BE_SUCCESS) { 451f169c0eaSGlenn Lagasse return (B_FALSE); 452f169c0eaSGlenn Lagasse } 453f169c0eaSGlenn Lagasse 454f169c0eaSGlenn Lagasse if (be_node == NULL) { 455f169c0eaSGlenn Lagasse return (B_FALSE); 456f169c0eaSGlenn Lagasse } 457f169c0eaSGlenn Lagasse 458f169c0eaSGlenn Lagasse if (be_node->be_active_on_boot) { 459f169c0eaSGlenn Lagasse be_free_list(be_node); 460f169c0eaSGlenn Lagasse return (B_TRUE); 461f169c0eaSGlenn Lagasse } else { 462f169c0eaSGlenn Lagasse be_free_list(be_node); 463f169c0eaSGlenn Lagasse return (B_FALSE); 464f169c0eaSGlenn Lagasse } 465f169c0eaSGlenn Lagasse } 466f169c0eaSGlenn Lagasse 467f169c0eaSGlenn Lagasse /* ******************************************************************** */ 468f169c0eaSGlenn Lagasse /* Private Functions */ 469f169c0eaSGlenn Lagasse /* ******************************************************************** */ 470f169c0eaSGlenn Lagasse 471f169c0eaSGlenn Lagasse /* 472f169c0eaSGlenn Lagasse * Function: set_bootfs 473f169c0eaSGlenn Lagasse * Description: Sets the bootfs property on the boot pool to be the 474f169c0eaSGlenn Lagasse * root dataset of the activated BE. 475f169c0eaSGlenn Lagasse * Parameters: 476f169c0eaSGlenn Lagasse * boot_pool - The pool we're setting bootfs in. 477f169c0eaSGlenn Lagasse * be_root_ds - The main dataset for the BE. 478f169c0eaSGlenn Lagasse * Return: 479f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 480f169c0eaSGlenn Lagasse * be_errno_t - Failure 481f169c0eaSGlenn Lagasse * Scope: 482f169c0eaSGlenn Lagasse * Private 483f169c0eaSGlenn Lagasse */ 484f169c0eaSGlenn Lagasse static int 485f169c0eaSGlenn Lagasse set_bootfs(char *boot_rpool, char *be_root_ds) 486f169c0eaSGlenn Lagasse { 487f169c0eaSGlenn Lagasse zpool_handle_t *zhp; 488f169c0eaSGlenn Lagasse int err = BE_SUCCESS; 489f169c0eaSGlenn Lagasse 490f169c0eaSGlenn Lagasse if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) { 491f169c0eaSGlenn Lagasse be_print_err(gettext("set_bootfs: failed to open pool " 492f169c0eaSGlenn Lagasse "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs)); 493f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 494f169c0eaSGlenn Lagasse return (err); 495f169c0eaSGlenn Lagasse } 496f169c0eaSGlenn Lagasse 497f169c0eaSGlenn Lagasse err = zpool_set_prop(zhp, "bootfs", be_root_ds); 498f169c0eaSGlenn Lagasse if (err) { 499f169c0eaSGlenn Lagasse be_print_err(gettext("set_bootfs: failed to set " 500f169c0eaSGlenn Lagasse "bootfs property for pool %s: %s\n"), boot_rpool, 501f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 502f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 503f169c0eaSGlenn Lagasse zpool_close(zhp); 504f169c0eaSGlenn Lagasse return (err); 505f169c0eaSGlenn Lagasse } 506f169c0eaSGlenn Lagasse 507f169c0eaSGlenn Lagasse zpool_close(zhp); 508f169c0eaSGlenn Lagasse return (BE_SUCCESS); 509f169c0eaSGlenn Lagasse } 510f169c0eaSGlenn Lagasse 511f169c0eaSGlenn Lagasse /* 512f169c0eaSGlenn Lagasse * Function: set_canmount 513f169c0eaSGlenn Lagasse * Description: Sets the canmount property on the datasets of the 514f169c0eaSGlenn Lagasse * activated BE. 515f169c0eaSGlenn Lagasse * Parameters: 516f169c0eaSGlenn Lagasse * be_nodes - The be_node_t returned from be_list 517f169c0eaSGlenn Lagasse * value - The value of canmount we setting, on|off|noauto. 518f169c0eaSGlenn Lagasse * Return: 519f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 520f169c0eaSGlenn Lagasse * be_errno_t - Failure 521f169c0eaSGlenn Lagasse * Scope: 522f169c0eaSGlenn Lagasse * Private 523f169c0eaSGlenn Lagasse */ 524f169c0eaSGlenn Lagasse static int 525f169c0eaSGlenn Lagasse set_canmount(be_node_list_t *be_nodes, char *value) 526f169c0eaSGlenn Lagasse { 527f169c0eaSGlenn Lagasse char ds_path[MAXPATHLEN]; 528f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 529f169c0eaSGlenn Lagasse be_node_list_t *list = be_nodes; 530f169c0eaSGlenn Lagasse int err = BE_SUCCESS; 531f169c0eaSGlenn Lagasse 532f169c0eaSGlenn Lagasse while (list != NULL) { 533f169c0eaSGlenn Lagasse be_dataset_list_t *datasets = list->be_node_datasets; 534f169c0eaSGlenn Lagasse 535f169c0eaSGlenn Lagasse be_make_root_ds(list->be_rpool, list->be_node_name, ds_path, 536f169c0eaSGlenn Lagasse sizeof (ds_path)); 537f169c0eaSGlenn Lagasse 538f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) == 539f169c0eaSGlenn Lagasse NULL) { 540f169c0eaSGlenn Lagasse be_print_err(gettext("set_canmount: failed to open " 541f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), ds_path, 542f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 543f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 544f169c0eaSGlenn Lagasse return (err); 545f169c0eaSGlenn Lagasse } 546f169c0eaSGlenn Lagasse if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) { 547f169c0eaSGlenn Lagasse /* 548f169c0eaSGlenn Lagasse * it's already mounted so we can't change the 549f169c0eaSGlenn Lagasse * canmount property anyway. 550f169c0eaSGlenn Lagasse */ 551f169c0eaSGlenn Lagasse err = BE_SUCCESS; 552f169c0eaSGlenn Lagasse } else { 553f169c0eaSGlenn Lagasse err = zfs_prop_set(zhp, 554f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_CANMOUNT), value); 555f169c0eaSGlenn Lagasse if (err) { 556f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 557f169c0eaSGlenn Lagasse be_print_err(gettext("set_canmount: failed to " 558f169c0eaSGlenn Lagasse "set dataset property (%s): %s\n"), 559f169c0eaSGlenn Lagasse ds_path, libzfs_error_description(g_zfs)); 560f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 561f169c0eaSGlenn Lagasse return (err); 562f169c0eaSGlenn Lagasse } 563f169c0eaSGlenn Lagasse } 564f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 565f169c0eaSGlenn Lagasse 566f169c0eaSGlenn Lagasse while (datasets != NULL) { 567f169c0eaSGlenn Lagasse be_make_root_ds(list->be_rpool, 568f169c0eaSGlenn Lagasse datasets->be_dataset_name, ds_path, 569f169c0eaSGlenn Lagasse sizeof (ds_path)); 570f169c0eaSGlenn Lagasse 571f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) 572f169c0eaSGlenn Lagasse == NULL) { 573f169c0eaSGlenn Lagasse be_print_err(gettext("set_canmount: failed to " 574f169c0eaSGlenn Lagasse "open dataset %s: %s\n"), ds_path, 575f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 576f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 577f169c0eaSGlenn Lagasse return (err); 578f169c0eaSGlenn Lagasse } 579f169c0eaSGlenn Lagasse if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) { 580f169c0eaSGlenn Lagasse /* 581f169c0eaSGlenn Lagasse * it's already mounted so we can't change the 582f169c0eaSGlenn Lagasse * canmount property anyway. 583f169c0eaSGlenn Lagasse */ 584f169c0eaSGlenn Lagasse err = BE_SUCCESS; 585f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 586f169c0eaSGlenn Lagasse break; 587f169c0eaSGlenn Lagasse } 588f169c0eaSGlenn Lagasse err = zfs_prop_set(zhp, 589f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_CANMOUNT), value); 590f169c0eaSGlenn Lagasse if (err) { 591f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 592f169c0eaSGlenn Lagasse be_print_err(gettext("set_canmount: " 593f169c0eaSGlenn Lagasse "Failed to set property value %s " 594f169c0eaSGlenn Lagasse "for dataset %s: %s\n"), value, ds_path, 595f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 596f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 597f169c0eaSGlenn Lagasse return (err); 598f169c0eaSGlenn Lagasse } 599f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 600f169c0eaSGlenn Lagasse datasets = datasets->be_next_dataset; 601f169c0eaSGlenn Lagasse } 602f169c0eaSGlenn Lagasse list = list->be_next_node; 603f169c0eaSGlenn Lagasse } 604f169c0eaSGlenn Lagasse return (err); 605f169c0eaSGlenn Lagasse } 606f169c0eaSGlenn Lagasse 607f169c0eaSGlenn Lagasse /* 608f169c0eaSGlenn Lagasse * Function: be_get_grub_vers 609f169c0eaSGlenn Lagasse * Description: Gets the grub version number from /boot/grub/capability. If 610f169c0eaSGlenn Lagasse * capability file doesn't exist NULL is returned. 611f169c0eaSGlenn Lagasse * Parameters: 612f169c0eaSGlenn Lagasse * bt - The transaction data for the BE we're getting the grub 613f169c0eaSGlenn Lagasse * version for. 614f169c0eaSGlenn Lagasse * cur_vers - used to return the current version of grub from 615f169c0eaSGlenn Lagasse * the root pool. 616f169c0eaSGlenn Lagasse * new_vers - used to return the grub version of the BE we're 617f169c0eaSGlenn Lagasse * activating. 618f169c0eaSGlenn Lagasse * Return: 619f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 620f169c0eaSGlenn Lagasse * be_errno_t - Failed to find version 621f169c0eaSGlenn Lagasse * Scope: 622f169c0eaSGlenn Lagasse * Private 623f169c0eaSGlenn Lagasse */ 624f169c0eaSGlenn Lagasse static int 625f169c0eaSGlenn Lagasse be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers) 626f169c0eaSGlenn Lagasse { 627f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 628f169c0eaSGlenn Lagasse zfs_handle_t *pool_zhp = NULL; 629f169c0eaSGlenn Lagasse int ret = BE_SUCCESS; 630f169c0eaSGlenn Lagasse char cap_file[MAXPATHLEN]; 631f169c0eaSGlenn Lagasse char *temp_mntpnt = NULL; 632f169c0eaSGlenn Lagasse char *zpool_mntpt = NULL; 633f169c0eaSGlenn Lagasse char *ptmp_mntpnt = NULL; 634f169c0eaSGlenn Lagasse char *orig_mntpnt = NULL; 635f169c0eaSGlenn Lagasse boolean_t be_mounted = B_FALSE; 636f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE; 637f169c0eaSGlenn Lagasse 638f169c0eaSGlenn Lagasse if (!be_has_grub()) { 639f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: Not supported on " 640f169c0eaSGlenn Lagasse "this architecture\n")); 641f169c0eaSGlenn Lagasse return (BE_ERR_NOTSUP); 642f169c0eaSGlenn Lagasse } 643f169c0eaSGlenn Lagasse 644f169c0eaSGlenn Lagasse if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL || 645f169c0eaSGlenn Lagasse bt->obe_root_ds == NULL) { 646f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: Invalid BE\n")); 647f169c0eaSGlenn Lagasse return (BE_ERR_INVAL); 648f169c0eaSGlenn Lagasse } 649f169c0eaSGlenn Lagasse 650f169c0eaSGlenn Lagasse if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) == 651f169c0eaSGlenn Lagasse NULL) { 652f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"), 653f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 654f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs)); 655f169c0eaSGlenn Lagasse } 656f169c0eaSGlenn Lagasse 657f169c0eaSGlenn Lagasse /* 658f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll 659f169c0eaSGlenn Lagasse * attempt to mount it. 660f169c0eaSGlenn Lagasse */ 661f169c0eaSGlenn Lagasse if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt, 662f169c0eaSGlenn Lagasse &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) { 663f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: pool dataset " 664f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), bt->obe_zpool); 665f169c0eaSGlenn Lagasse ZFS_CLOSE(pool_zhp); 666f169c0eaSGlenn Lagasse return (ret); 667f169c0eaSGlenn Lagasse } 668f169c0eaSGlenn Lagasse 669f169c0eaSGlenn Lagasse /* 670f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset. 671f169c0eaSGlenn Lagasse */ 672f169c0eaSGlenn Lagasse if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) { 673f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: pool " 674a63c99a2SToomas Soome "dataset (%s) is not mounted. Can't read the " 675a63c99a2SToomas Soome "grub capability file.\n"), bt->obe_zpool); 676f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU; 677f169c0eaSGlenn Lagasse goto cleanup; 678f169c0eaSGlenn Lagasse } 679f169c0eaSGlenn Lagasse 680f169c0eaSGlenn Lagasse /* 681f169c0eaSGlenn Lagasse * get the version of the most recent grub update. 682f169c0eaSGlenn Lagasse */ 683f169c0eaSGlenn Lagasse (void) snprintf(cap_file, sizeof (cap_file), "%s%s", 684f169c0eaSGlenn Lagasse zpool_mntpt, BE_CAP_FILE); 685f169c0eaSGlenn Lagasse free(zpool_mntpt); 686f169c0eaSGlenn Lagasse zpool_mntpt = NULL; 687f169c0eaSGlenn Lagasse 688f169c0eaSGlenn Lagasse if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS) 689f169c0eaSGlenn Lagasse goto cleanup; 690f169c0eaSGlenn Lagasse 691f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) == 692f169c0eaSGlenn Lagasse NULL) { 693f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: failed to " 694f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), bt->obe_root_ds, 695f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 696f169c0eaSGlenn Lagasse free(cur_vers); 697f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 698f169c0eaSGlenn Lagasse goto cleanup; 699f169c0eaSGlenn Lagasse } 700f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &temp_mntpnt)) { 701f169c0eaSGlenn Lagasse if ((ret = _be_mount(bt->obe_name, &temp_mntpnt, 702f169c0eaSGlenn Lagasse BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 703f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: failed to " 704f169c0eaSGlenn Lagasse "mount BE (%s)\n"), bt->obe_name); 705f169c0eaSGlenn Lagasse free(*cur_vers); 706f169c0eaSGlenn Lagasse *cur_vers = NULL; 707f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 708f169c0eaSGlenn Lagasse goto cleanup; 709f169c0eaSGlenn Lagasse } 710f169c0eaSGlenn Lagasse be_mounted = B_TRUE; 711f169c0eaSGlenn Lagasse } 712f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 713f169c0eaSGlenn Lagasse 714f169c0eaSGlenn Lagasse /* 715f169c0eaSGlenn Lagasse * Now get the grub version for the BE being activated. 716f169c0eaSGlenn Lagasse */ 717f169c0eaSGlenn Lagasse (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt, 718f169c0eaSGlenn Lagasse BE_CAP_FILE); 719f169c0eaSGlenn Lagasse ret = get_ver_from_capfile(cap_file, new_vers); 720f169c0eaSGlenn Lagasse if (ret != BE_SUCCESS) { 721f169c0eaSGlenn Lagasse free(*cur_vers); 722f169c0eaSGlenn Lagasse *cur_vers = NULL; 723f169c0eaSGlenn Lagasse } 724f169c0eaSGlenn Lagasse if (be_mounted) 725f169c0eaSGlenn Lagasse (void) _be_unmount(bt->obe_name, 0); 726f169c0eaSGlenn Lagasse 727f169c0eaSGlenn Lagasse cleanup: 728f169c0eaSGlenn Lagasse if (pool_mounted) { 729f169c0eaSGlenn Lagasse int iret = BE_SUCCESS; 730f169c0eaSGlenn Lagasse iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt); 731f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS) 732f169c0eaSGlenn Lagasse ret = iret; 733f169c0eaSGlenn Lagasse free(orig_mntpnt); 734f169c0eaSGlenn Lagasse free(ptmp_mntpnt); 735f169c0eaSGlenn Lagasse } 736f169c0eaSGlenn Lagasse ZFS_CLOSE(pool_zhp); 737f169c0eaSGlenn Lagasse 738f169c0eaSGlenn Lagasse free(temp_mntpnt); 739f169c0eaSGlenn Lagasse return (ret); 740f169c0eaSGlenn Lagasse } 741f169c0eaSGlenn Lagasse 742f169c0eaSGlenn Lagasse /* 743f169c0eaSGlenn Lagasse * Function: get_ver_from_capfile 744f169c0eaSGlenn Lagasse * Description: Parses the capability file passed in looking for the VERSION 745f169c0eaSGlenn Lagasse * line. If found the version is returned in vers, if not then 746f169c0eaSGlenn Lagasse * NULL is returned in vers. 747f169c0eaSGlenn Lagasse * 748f169c0eaSGlenn Lagasse * Parameters: 749f169c0eaSGlenn Lagasse * file - the path to the capability file we want to parse. 750f169c0eaSGlenn Lagasse * vers - the version string that will be passed back. 751f169c0eaSGlenn Lagasse * Return: 752f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 753f169c0eaSGlenn Lagasse * be_errno_t - Failed to find version 754f169c0eaSGlenn Lagasse * Scope: 755f169c0eaSGlenn Lagasse * Private 756f169c0eaSGlenn Lagasse */ 757f169c0eaSGlenn Lagasse static int 758f169c0eaSGlenn Lagasse get_ver_from_capfile(char *file, char **vers) 759f169c0eaSGlenn Lagasse { 760f169c0eaSGlenn Lagasse FILE *fp = NULL; 761f169c0eaSGlenn Lagasse char line[BUFSIZ]; 762f169c0eaSGlenn Lagasse char *last = NULL; 763f169c0eaSGlenn Lagasse int err = BE_SUCCESS; 764f169c0eaSGlenn Lagasse errno = 0; 765f169c0eaSGlenn Lagasse 766f169c0eaSGlenn Lagasse if (!be_has_grub()) { 767f169c0eaSGlenn Lagasse be_print_err(gettext("get_ver_from_capfile: Not supported " 768f169c0eaSGlenn Lagasse "on this architecture\n")); 769f169c0eaSGlenn Lagasse return (BE_ERR_NOTSUP); 770f169c0eaSGlenn Lagasse } 771f169c0eaSGlenn Lagasse 772f169c0eaSGlenn Lagasse /* 773f169c0eaSGlenn Lagasse * Set version string to NULL; the only case this shouldn't be set 774f169c0eaSGlenn Lagasse * to be NULL is when we've actually found a version in the capability 775f169c0eaSGlenn Lagasse * file, which is set below. 776f169c0eaSGlenn Lagasse */ 777f169c0eaSGlenn Lagasse *vers = NULL; 778f169c0eaSGlenn Lagasse 779f169c0eaSGlenn Lagasse /* 780f169c0eaSGlenn Lagasse * If the capability file doesn't exist, we're returning success 781f169c0eaSGlenn Lagasse * because on older releases, the capability file did not exist 782f169c0eaSGlenn Lagasse * so this is a valid scenario. 783f169c0eaSGlenn Lagasse */ 784f169c0eaSGlenn Lagasse if (access(file, F_OK) == 0) { 785f169c0eaSGlenn Lagasse if ((fp = fopen(file, "r")) == NULL) { 786f169c0eaSGlenn Lagasse err = errno; 787f169c0eaSGlenn Lagasse be_print_err(gettext("get_ver_from_capfile: failed to " 788f169c0eaSGlenn Lagasse "open file %s with error %s\n"), file, 789f169c0eaSGlenn Lagasse strerror(err)); 790f169c0eaSGlenn Lagasse err = errno_to_be_err(err); 791f169c0eaSGlenn Lagasse return (err); 792f169c0eaSGlenn Lagasse } 793f169c0eaSGlenn Lagasse 794f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, fp)) { 795f169c0eaSGlenn Lagasse char *tok = strtok_r(line, "=", &last); 796f169c0eaSGlenn Lagasse 797f169c0eaSGlenn Lagasse if (tok == NULL || tok[0] == '#') { 798f169c0eaSGlenn Lagasse continue; 799f169c0eaSGlenn Lagasse } else if (strcmp(tok, "VERSION") == 0) { 800f169c0eaSGlenn Lagasse *vers = strdup(last); 801f169c0eaSGlenn Lagasse break; 802f169c0eaSGlenn Lagasse } 803f169c0eaSGlenn Lagasse } 804f169c0eaSGlenn Lagasse (void) fclose(fp); 805f169c0eaSGlenn Lagasse } 806f169c0eaSGlenn Lagasse 807f169c0eaSGlenn Lagasse return (BE_SUCCESS); 808f169c0eaSGlenn Lagasse } 809f169c0eaSGlenn Lagasse 810f169c0eaSGlenn Lagasse /* 811a63c99a2SToomas Soome * To be able to boot EFI labeled disks, stage1 needs to be written 8121a902ef8SHans Rosenfeld * into the MBR. We do not do this if we're on disks with a traditional 8131a902ef8SHans Rosenfeld * fdisk partition table only, or if any foreign EFI partitions exist. 8141a902ef8SHans Rosenfeld * In the trivial case of a whole-disk vdev we always write stage1 into 8151a902ef8SHans Rosenfeld * the MBR. 8161a902ef8SHans Rosenfeld */ 8171a902ef8SHans Rosenfeld static boolean_t 818a63c99a2SToomas Soome be_do_install_mbr(char *diskname, nvlist_t *child) 8191a902ef8SHans Rosenfeld { 8201a902ef8SHans Rosenfeld struct uuid allowed_uuids[] = { 8211a902ef8SHans Rosenfeld EFI_UNUSED, 8221a902ef8SHans Rosenfeld EFI_RESV1, 8231a902ef8SHans Rosenfeld EFI_BOOT, 8241a902ef8SHans Rosenfeld EFI_ROOT, 8251a902ef8SHans Rosenfeld EFI_SWAP, 8261a902ef8SHans Rosenfeld EFI_USR, 8271a902ef8SHans Rosenfeld EFI_BACKUP, 8281a902ef8SHans Rosenfeld EFI_RESV2, 8291a902ef8SHans Rosenfeld EFI_VAR, 8301a902ef8SHans Rosenfeld EFI_HOME, 8311a902ef8SHans Rosenfeld EFI_ALTSCTR, 8321a902ef8SHans Rosenfeld EFI_RESERVED, 8331a902ef8SHans Rosenfeld EFI_SYSTEM, 8341a902ef8SHans Rosenfeld EFI_BIOS_BOOT, 8351a902ef8SHans Rosenfeld EFI_SYMC_PUB, 8361a902ef8SHans Rosenfeld EFI_SYMC_CDS 8371a902ef8SHans Rosenfeld }; 8381a902ef8SHans Rosenfeld 8391a902ef8SHans Rosenfeld uint64_t whole; 8401a902ef8SHans Rosenfeld struct dk_gpt *gpt; 8411a902ef8SHans Rosenfeld struct uuid *u; 8421a902ef8SHans Rosenfeld int fd, npart, i, j; 8431a902ef8SHans Rosenfeld 8441a902ef8SHans Rosenfeld (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK, 8451a902ef8SHans Rosenfeld &whole); 8461a902ef8SHans Rosenfeld 8471a902ef8SHans Rosenfeld if (whole) 8481a902ef8SHans Rosenfeld return (B_TRUE); 8491a902ef8SHans Rosenfeld 8501a902ef8SHans Rosenfeld if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0) 8511a902ef8SHans Rosenfeld return (B_FALSE); 8521a902ef8SHans Rosenfeld 8531a902ef8SHans Rosenfeld if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0) 8541a902ef8SHans Rosenfeld return (B_FALSE); 8551a902ef8SHans Rosenfeld 8561a902ef8SHans Rosenfeld for (i = 0; i != npart; i++) { 8571a902ef8SHans Rosenfeld int match = 0; 8581a902ef8SHans Rosenfeld 8591a902ef8SHans Rosenfeld u = &gpt->efi_parts[i].p_guid; 8601a902ef8SHans Rosenfeld 8611a902ef8SHans Rosenfeld for (j = 0; 8621a902ef8SHans Rosenfeld j != sizeof (allowed_uuids) / sizeof (struct uuid); 8631a902ef8SHans Rosenfeld j++) 8641a902ef8SHans Rosenfeld if (bcmp(u, &allowed_uuids[j], 8651a902ef8SHans Rosenfeld sizeof (struct uuid)) == 0) 8661a902ef8SHans Rosenfeld match++; 8671a902ef8SHans Rosenfeld 8681a902ef8SHans Rosenfeld if (match == 0) 8691a902ef8SHans Rosenfeld return (B_FALSE); 8701a902ef8SHans Rosenfeld } 8711a902ef8SHans Rosenfeld 8721a902ef8SHans Rosenfeld return (B_TRUE); 8731a902ef8SHans Rosenfeld } 8741a902ef8SHans Rosenfeld 8751a902ef8SHans Rosenfeld static int 876a63c99a2SToomas Soome be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1, 877c7c0ceafSToomas Soome char *stage2, uint16_t flags) 8781a902ef8SHans Rosenfeld { 879a63c99a2SToomas Soome char install_cmd[MAXPATHLEN]; 8801a902ef8SHans Rosenfeld char be_run_cmd_errbuf[BUFSIZ]; 881c7c0ceafSToomas Soome char be_run_cmd_outbuf[BUFSIZ]; 8821a902ef8SHans Rosenfeld char diskname[MAXPATHLEN]; 8831a902ef8SHans Rosenfeld char *vname; 8841a902ef8SHans Rosenfeld char *path, *dsk_ptr; 885a63c99a2SToomas Soome char *flag = ""; 886c7c0ceafSToomas Soome int ret; 88708e9b2dfSHans Rosenfeld vdev_stat_t *vs; 88808e9b2dfSHans Rosenfeld uint_t vsc; 8891a902ef8SHans Rosenfeld 8901a902ef8SHans Rosenfeld if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) { 891a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: " 8921a902ef8SHans Rosenfeld "failed to get device path\n")); 8931a902ef8SHans Rosenfeld return (BE_ERR_NODEV); 8941a902ef8SHans Rosenfeld } 8951a902ef8SHans Rosenfeld 89608e9b2dfSHans Rosenfeld if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS, 89708e9b2dfSHans Rosenfeld (uint64_t **)&vs, &vsc) != 0) || 89808e9b2dfSHans Rosenfeld vs->vs_state < VDEV_STATE_DEGRADED) { 89908e9b2dfSHans Rosenfeld /* 90008e9b2dfSHans Rosenfeld * Don't try to run installgrub on a vdev that is not ONLINE 90108e9b2dfSHans Rosenfeld * or DEGRADED. Try to print a warning for each such vdev. 90208e9b2dfSHans Rosenfeld */ 90308e9b2dfSHans Rosenfeld be_print_err(gettext("be_do_installboot: " 90408e9b2dfSHans Rosenfeld "vdev %s is %s, can't install boot loader\n"), 90508e9b2dfSHans Rosenfeld path, zpool_state_to_name(vs->vs_state, vs->vs_aux)); 90608e9b2dfSHans Rosenfeld free(path); 90708e9b2dfSHans Rosenfeld return (BE_SUCCESS); 90808e9b2dfSHans Rosenfeld } 90908e9b2dfSHans Rosenfeld 9101a902ef8SHans Rosenfeld /* 9111a902ef8SHans Rosenfeld * Modify the vdev path to point to the raw disk. 9121a902ef8SHans Rosenfeld */ 9131a902ef8SHans Rosenfeld path = strdup(path); 9141a902ef8SHans Rosenfeld if (path == NULL) 9151a902ef8SHans Rosenfeld return (BE_ERR_NOMEM); 9161a902ef8SHans Rosenfeld 9171a902ef8SHans Rosenfeld dsk_ptr = strstr(path, "/dsk/"); 9181a902ef8SHans Rosenfeld if (dsk_ptr != NULL) { 9191a902ef8SHans Rosenfeld *dsk_ptr = '\0'; 9201a902ef8SHans Rosenfeld dsk_ptr++; 9211a902ef8SHans Rosenfeld } else { 9221a902ef8SHans Rosenfeld dsk_ptr = ""; 9231a902ef8SHans Rosenfeld } 9241a902ef8SHans Rosenfeld 9251a902ef8SHans Rosenfeld (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr); 9261a902ef8SHans Rosenfeld free(path); 9271a902ef8SHans Rosenfeld 9281a902ef8SHans Rosenfeld vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE); 9291a902ef8SHans Rosenfeld if (vname == NULL) { 930a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: " 9311a902ef8SHans Rosenfeld "failed to get device name: %s\n"), 9321a902ef8SHans Rosenfeld libzfs_error_description(g_zfs)); 9331a902ef8SHans Rosenfeld return (zfs_err_to_be_err(g_zfs)); 9341a902ef8SHans Rosenfeld } 9351a902ef8SHans Rosenfeld 936a63c99a2SToomas Soome if (be_is_isa("i386")) { 937c7c0ceafSToomas Soome uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE; 938c7c0ceafSToomas Soome uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR; 939c7c0ceafSToomas Soome 940c7c0ceafSToomas Soome if (force == BE_INSTALLBOOT_FLAG_FORCE) { 941c7c0ceafSToomas Soome if (mbr == BE_INSTALLBOOT_FLAG_MBR || 942c7c0ceafSToomas Soome be_do_install_mbr(diskname, child)) 943c7c0ceafSToomas Soome flag = "-F -m -f"; 944c7c0ceafSToomas Soome else 945c7c0ceafSToomas Soome flag = "-F"; 946c7c0ceafSToomas Soome } else { 947c7c0ceafSToomas Soome if (mbr == BE_INSTALLBOOT_FLAG_MBR || 948c7c0ceafSToomas Soome be_do_install_mbr(diskname, child)) 949a63c99a2SToomas Soome flag = "-m -f"; 950c7c0ceafSToomas Soome } 951c7c0ceafSToomas Soome 9521a47de4eSToomas Soome if (be_has_grub()) { 953a63c99a2SToomas Soome (void) snprintf(install_cmd, sizeof (install_cmd), 954a63c99a2SToomas Soome "%s %s %s %s %s", BE_INSTALL_GRUB, flag, 955a63c99a2SToomas Soome stage1, stage2, diskname); 9561a47de4eSToomas Soome } else { 9571a47de4eSToomas Soome (void) snprintf(install_cmd, sizeof (install_cmd), 9581a47de4eSToomas Soome "%s %s %s %s %s", BE_INSTALL_BOOT, flag, 9591a47de4eSToomas Soome stage1, stage2, diskname); 9601a47de4eSToomas Soome } 96166f18efaSToomas Soome } else if (be_is_isa("sparc")) { 962c7c0ceafSToomas Soome if ((flags & BE_INSTALLBOOT_FLAG_FORCE) == 963c7c0ceafSToomas Soome BE_INSTALLBOOT_FLAG_FORCE) 964c7c0ceafSToomas Soome flag = "-f -F zfs"; 965c7c0ceafSToomas Soome else 966a63c99a2SToomas Soome flag = "-F zfs"; 967c7c0ceafSToomas Soome 968a63c99a2SToomas Soome (void) snprintf(install_cmd, sizeof (install_cmd), 969a63c99a2SToomas Soome "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname); 97066f18efaSToomas Soome } else { 97166f18efaSToomas Soome be_print_err(gettext("be_do_installboot: unsupported " 97266f18efaSToomas Soome "architecture.\n")); 97366f18efaSToomas Soome return (BE_ERR_BOOTFILE_INST); 974a63c99a2SToomas Soome } 975a63c99a2SToomas Soome 976c7c0ceafSToomas Soome *be_run_cmd_outbuf = '\0'; 977c7c0ceafSToomas Soome *be_run_cmd_errbuf = '\0'; 978c7c0ceafSToomas Soome 979c7c0ceafSToomas Soome ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ, 980c7c0ceafSToomas Soome be_run_cmd_outbuf, BUFSIZ); 981c7c0ceafSToomas Soome 982c7c0ceafSToomas Soome if (ret != BE_SUCCESS) { 983a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: install " 9841a902ef8SHans Rosenfeld "failed for device %s.\n"), vname); 985c7c0ceafSToomas Soome ret = BE_ERR_BOOTFILE_INST; 986c7c0ceafSToomas Soome } 987c7c0ceafSToomas Soome 988c7c0ceafSToomas Soome be_print_err(gettext(" Command: \"%s\"\n"), install_cmd); 989c7c0ceafSToomas Soome if (be_run_cmd_outbuf[0] != 0) { 990c7c0ceafSToomas Soome be_print_err(gettext(" Output:\n")); 991c7c0ceafSToomas Soome be_print_err("%s", be_run_cmd_outbuf); 992c7c0ceafSToomas Soome } 993c7c0ceafSToomas Soome 994c7c0ceafSToomas Soome if (be_run_cmd_errbuf[0] != 0) { 995c7c0ceafSToomas Soome be_print_err(gettext(" Errors:\n")); 9961a902ef8SHans Rosenfeld be_print_err("%s", be_run_cmd_errbuf); 9971a902ef8SHans Rosenfeld } 9981a902ef8SHans Rosenfeld free(vname); 9991a902ef8SHans Rosenfeld 1000c7c0ceafSToomas Soome return (ret); 10011a902ef8SHans Rosenfeld } 10021a902ef8SHans Rosenfeld 10031a902ef8SHans Rosenfeld /* 1004a63c99a2SToomas Soome * Function: be_do_copy_grub_cap 1005a63c99a2SToomas Soome * Description: This function will copy grub capability file to BE. 1006f169c0eaSGlenn Lagasse * 1007f169c0eaSGlenn Lagasse * Parameters: 1008f169c0eaSGlenn Lagasse * bt - The transaction data for the BE we're activating. 1009f169c0eaSGlenn Lagasse * Return: 1010f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1011f169c0eaSGlenn Lagasse * be_errno_t - Failure 1012f169c0eaSGlenn Lagasse * 1013f169c0eaSGlenn Lagasse * Scope: 1014f169c0eaSGlenn Lagasse * Private 1015f169c0eaSGlenn Lagasse */ 1016f169c0eaSGlenn Lagasse static int 1017a63c99a2SToomas Soome be_do_copy_grub_cap(be_transaction_data_t *bt) 1018f169c0eaSGlenn Lagasse { 1019f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 1020f169c0eaSGlenn Lagasse char cap_file[MAXPATHLEN]; 1021f169c0eaSGlenn Lagasse char zpool_cap_file[MAXPATHLEN]; 1022a63c99a2SToomas Soome char line[BUFSIZ]; 1023a63c99a2SToomas Soome char *tmp_mntpnt = NULL; 1024a63c99a2SToomas Soome char *orig_mntpnt = NULL; 1025a63c99a2SToomas Soome char *pool_mntpnt = NULL; 1026a63c99a2SToomas Soome FILE *cap_fp = NULL; 1027a63c99a2SToomas Soome FILE *zpool_cap_fp = NULL; 1028f169c0eaSGlenn Lagasse int err = 0; 1029a63c99a2SToomas Soome int ret = BE_SUCCESS; 1030f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE; 1031a63c99a2SToomas Soome boolean_t be_mounted = B_FALSE; 1032f169c0eaSGlenn Lagasse 1033f169c0eaSGlenn Lagasse /* 1034a21e1692SToomas Soome * first get BE dataset mountpoint, we can free all the resources 1035a21e1692SToomas Soome * once cap_file is built, leaving only be unmount to be done. 1036f169c0eaSGlenn Lagasse */ 1037a21e1692SToomas Soome if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) == 1038a21e1692SToomas Soome NULL) { 1039a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: failed to " 1040a21e1692SToomas Soome "open BE root dataset (%s): %s\n"), bt->obe_root_ds, 1041a21e1692SToomas Soome libzfs_error_description(g_zfs)); 1042a21e1692SToomas Soome return (zfs_err_to_be_err(g_zfs)); 1043a21e1692SToomas Soome } 1044a21e1692SToomas Soome 1045a21e1692SToomas Soome if (!zfs_is_mounted(zhp, &tmp_mntpnt)) { 1046a21e1692SToomas Soome if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt, 1047a21e1692SToomas Soome BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 1048a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: failed to " 1049a21e1692SToomas Soome "mount BE (%s)\n"), bt->obe_name); 1050a21e1692SToomas Soome ZFS_CLOSE(zhp); 1051a21e1692SToomas Soome goto done; 1052a21e1692SToomas Soome } 1053a21e1692SToomas Soome be_mounted = B_TRUE; 1054a21e1692SToomas Soome } 1055a21e1692SToomas Soome ZFS_CLOSE(zhp); /* BE dataset handle is not needed any more */ 1056a21e1692SToomas Soome 1057a21e1692SToomas Soome (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt, 1058a21e1692SToomas Soome BE_CAP_FILE); 1059a21e1692SToomas Soome free(tmp_mntpnt); 1060a21e1692SToomas Soome 1061a21e1692SToomas Soome /* get pool root dataset mountpoint */ 1062a63c99a2SToomas Soome zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM); 1063a63c99a2SToomas Soome if (zhp == NULL) { 1064a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: zfs_open " 1065f169c0eaSGlenn Lagasse "failed: %s\n"), libzfs_error_description(g_zfs)); 1066a21e1692SToomas Soome ret = zfs_err_to_be_err(g_zfs); 1067a21e1692SToomas Soome goto done; 1068f169c0eaSGlenn Lagasse } 1069f169c0eaSGlenn Lagasse 1070f169c0eaSGlenn Lagasse /* 1071f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll 1072f169c0eaSGlenn Lagasse * attempt to mount it. 1073f169c0eaSGlenn Lagasse */ 1074a21e1692SToomas Soome if ((ret = be_mount_pool(zhp, &tmp_mntpnt, 1075f169c0eaSGlenn Lagasse &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) { 1076a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: pool dataset " 1077f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), bt->obe_zpool); 1078f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1079a21e1692SToomas Soome goto done; 1080f169c0eaSGlenn Lagasse } 1081f169c0eaSGlenn Lagasse 1082f169c0eaSGlenn Lagasse /* 1083f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset. 1084a21e1692SToomas Soome * NOTE: zhp must be kept for _be_unmount_pool() 1085f169c0eaSGlenn Lagasse */ 1086f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &pool_mntpnt)) { 1087a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: pool " 1088f169c0eaSGlenn Lagasse "dataset (%s) is not mounted. Can't check the grub " 1089f169c0eaSGlenn Lagasse "version from the grub capability file.\n"), bt->obe_zpool); 1090f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU; 1091f169c0eaSGlenn Lagasse goto done; 1092f169c0eaSGlenn Lagasse } 1093f169c0eaSGlenn Lagasse 1094f169c0eaSGlenn Lagasse (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s", 1095f169c0eaSGlenn Lagasse pool_mntpnt, BE_CAP_FILE); 1096f169c0eaSGlenn Lagasse free(pool_mntpnt); 1097a63c99a2SToomas Soome 1098f169c0eaSGlenn Lagasse if ((cap_fp = fopen(cap_file, "r")) == NULL) { 1099f169c0eaSGlenn Lagasse err = errno; 1100a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: failed to open grub " 1101f169c0eaSGlenn Lagasse "capability file\n")); 1102f169c0eaSGlenn Lagasse ret = errno_to_be_err(err); 1103f169c0eaSGlenn Lagasse goto done; 1104f169c0eaSGlenn Lagasse } 1105f169c0eaSGlenn Lagasse if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) { 1106f169c0eaSGlenn Lagasse err = errno; 1107a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: failed to open new " 1108f169c0eaSGlenn Lagasse "grub capability file\n")); 1109f169c0eaSGlenn Lagasse ret = errno_to_be_err(err); 1110f169c0eaSGlenn Lagasse (void) fclose(cap_fp); 1111f169c0eaSGlenn Lagasse goto done; 1112f169c0eaSGlenn Lagasse } 1113f169c0eaSGlenn Lagasse 1114f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, cap_fp)) { 1115f169c0eaSGlenn Lagasse (void) fputs(line, zpool_cap_fp); 1116f169c0eaSGlenn Lagasse } 1117f169c0eaSGlenn Lagasse 1118f169c0eaSGlenn Lagasse (void) fclose(zpool_cap_fp); 1119f169c0eaSGlenn Lagasse (void) fclose(cap_fp); 1120f169c0eaSGlenn Lagasse 1121f169c0eaSGlenn Lagasse done: 1122a63c99a2SToomas Soome if (be_mounted) 1123a63c99a2SToomas Soome (void) _be_unmount(bt->obe_name, 0); 1124a63c99a2SToomas Soome 1125f169c0eaSGlenn Lagasse if (pool_mounted) { 1126a21e1692SToomas Soome err = be_unmount_pool(zhp, tmp_mntpnt, orig_mntpnt); 1127f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS) 1128a21e1692SToomas Soome ret = err; 1129f169c0eaSGlenn Lagasse free(orig_mntpnt); 1130a21e1692SToomas Soome free(tmp_mntpnt); 1131a21e1692SToomas Soome zfs_close(zhp); 1132f169c0eaSGlenn Lagasse } 1133a63c99a2SToomas Soome return (ret); 1134a63c99a2SToomas Soome } 1135a63c99a2SToomas Soome 1136a63c99a2SToomas Soome /* 1137a63c99a2SToomas Soome * Function: be_is_install_needed 1138a63c99a2SToomas Soome * Description: Check detached version files to detect if bootloader 1139a63c99a2SToomas Soome * install/update is needed. 1140a63c99a2SToomas Soome * 1141a63c99a2SToomas Soome * Parameters: 1142a63c99a2SToomas Soome * bt - The transaction data for the BE we're activating. 1143a63c99a2SToomas Soome * update - set B_TRUE is update is needed. 1144a63c99a2SToomas Soome * Return: 1145a63c99a2SToomas Soome * BE_SUCCESS - Success 1146a63c99a2SToomas Soome * be_errno_t - Failure 1147a63c99a2SToomas Soome * 1148a63c99a2SToomas Soome * Scope: 1149a63c99a2SToomas Soome * Private 1150a63c99a2SToomas Soome */ 1151a63c99a2SToomas Soome static int 1152a63c99a2SToomas Soome be_is_install_needed(be_transaction_data_t *bt, boolean_t *update) 1153a63c99a2SToomas Soome { 1154a63c99a2SToomas Soome int ret = BE_SUCCESS; 1155a63c99a2SToomas Soome char *cur_vers = NULL, *new_vers = NULL; 1156a63c99a2SToomas Soome 1157a63c99a2SToomas Soome assert(bt != NULL); 1158a63c99a2SToomas Soome assert(update != NULL); 1159a63c99a2SToomas Soome 1160a63c99a2SToomas Soome if (!be_has_grub()) { 1161a63c99a2SToomas Soome /* 1162a63c99a2SToomas Soome * no detached versioning, let installboot to manage 1163a63c99a2SToomas Soome * versioning. 1164a63c99a2SToomas Soome */ 1165a63c99a2SToomas Soome *update = B_TRUE; 1166a63c99a2SToomas Soome return (ret); 1167a63c99a2SToomas Soome } 1168a63c99a2SToomas Soome 1169a63c99a2SToomas Soome *update = B_FALSE; /* set default */ 1170a63c99a2SToomas Soome 1171a63c99a2SToomas Soome /* 1172a63c99a2SToomas Soome * We need to check to see if the version number from 1173a63c99a2SToomas Soome * the BE being activated is greater than the current 1174a63c99a2SToomas Soome * one. 1175a63c99a2SToomas Soome */ 1176a63c99a2SToomas Soome ret = be_get_grub_vers(bt, &cur_vers, &new_vers); 1177a63c99a2SToomas Soome if (ret != BE_SUCCESS) { 1178a63c99a2SToomas Soome be_print_err(gettext("be_activate: failed to get grub " 1179a63c99a2SToomas Soome "versions from capability files.\n")); 1180a63c99a2SToomas Soome return (ret); 1181a63c99a2SToomas Soome } 1182a63c99a2SToomas Soome /* update if we have both versions and can compare */ 1183a63c99a2SToomas Soome if (cur_vers != NULL) { 1184a63c99a2SToomas Soome if (new_vers != NULL) { 1185a63c99a2SToomas Soome if (atof(cur_vers) < atof(new_vers)) 1186a63c99a2SToomas Soome *update = B_TRUE; 1187a63c99a2SToomas Soome free(new_vers); 1188a63c99a2SToomas Soome } 1189a63c99a2SToomas Soome free(cur_vers); 1190a63c99a2SToomas Soome } else if (new_vers != NULL) { 1191a63c99a2SToomas Soome /* we only got new version - update */ 1192a63c99a2SToomas Soome *update = B_TRUE; 1193a63c99a2SToomas Soome free(new_vers); 1194a63c99a2SToomas Soome } 1195a63c99a2SToomas Soome return (ret); 1196a63c99a2SToomas Soome } 1197a63c99a2SToomas Soome 1198a63c99a2SToomas Soome /* 1199a63c99a2SToomas Soome * Function: be_do_installboot 1200a63c99a2SToomas Soome * Description: This function runs installgrub/installboot using the boot 1201a63c99a2SToomas Soome * loader files from the BE we're activating and installing 1202a63c99a2SToomas Soome * them on the pool the BE lives in. 1203a63c99a2SToomas Soome * 1204a63c99a2SToomas Soome * Parameters: 1205a63c99a2SToomas Soome * bt - The transaction data for the BE we're activating. 1206c7c0ceafSToomas Soome * flags - flags for bootloader install 1207a63c99a2SToomas Soome * Return: 1208a63c99a2SToomas Soome * BE_SUCCESS - Success 1209a63c99a2SToomas Soome * be_errno_t - Failure 1210a63c99a2SToomas Soome * 1211a63c99a2SToomas Soome * Scope: 1212a63c99a2SToomas Soome * Private 1213a63c99a2SToomas Soome */ 1214a63c99a2SToomas Soome static int 1215c7c0ceafSToomas Soome be_do_installboot(be_transaction_data_t *bt, uint16_t flags) 1216a63c99a2SToomas Soome { 1217a63c99a2SToomas Soome zpool_handle_t *zphp = NULL; 1218a63c99a2SToomas Soome zfs_handle_t *zhp = NULL; 1219a63c99a2SToomas Soome nvlist_t **child, *nv, *config; 1220a63c99a2SToomas Soome uint_t c, children = 0; 1221a63c99a2SToomas Soome char *tmp_mntpt = NULL; 1222a63c99a2SToomas Soome char stage1[MAXPATHLEN]; 1223a63c99a2SToomas Soome char stage2[MAXPATHLEN]; 1224a63c99a2SToomas Soome char *vname; 1225a63c99a2SToomas Soome int ret = BE_SUCCESS; 1226a63c99a2SToomas Soome boolean_t be_mounted = B_FALSE; 1227a63c99a2SToomas Soome boolean_t update = B_FALSE; 12281a47de4eSToomas Soome boolean_t verbose = B_FALSE; 1229a63c99a2SToomas Soome 1230a63c99a2SToomas Soome /* 1231a63c99a2SToomas Soome * check versions. This call is to support detached 1232a63c99a2SToomas Soome * version implementation like grub. Embedded versioning is 1233a63c99a2SToomas Soome * checked by actual installer. 1234a63c99a2SToomas Soome */ 1235c7c0ceafSToomas Soome if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) { 1236a63c99a2SToomas Soome ret = be_is_install_needed(bt, &update); 1237a63c99a2SToomas Soome if (ret != BE_SUCCESS || update == B_FALSE) 1238a63c99a2SToomas Soome return (ret); 1239c7c0ceafSToomas Soome } 12401a47de4eSToomas Soome verbose = do_print; 1241a63c99a2SToomas Soome 1242a63c99a2SToomas Soome if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) == 1243a63c99a2SToomas Soome NULL) { 1244a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to " 1245a63c99a2SToomas Soome "open BE root dataset (%s): %s\n"), bt->obe_root_ds, 1246a63c99a2SToomas Soome libzfs_error_description(g_zfs)); 1247a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs); 1248a63c99a2SToomas Soome return (ret); 1249a63c99a2SToomas Soome } 1250a63c99a2SToomas Soome if (!zfs_is_mounted(zhp, &tmp_mntpt)) { 1251a63c99a2SToomas Soome if ((ret = _be_mount(bt->obe_name, &tmp_mntpt, 1252a63c99a2SToomas Soome BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 1253a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to " 1254a63c99a2SToomas Soome "mount BE (%s)\n"), bt->obe_name); 1255a63c99a2SToomas Soome ZFS_CLOSE(zhp); 1256a63c99a2SToomas Soome return (ret); 1257a63c99a2SToomas Soome } 1258a63c99a2SToomas Soome be_mounted = B_TRUE; 1259a63c99a2SToomas Soome } 1260a63c99a2SToomas Soome ZFS_CLOSE(zhp); 1261a63c99a2SToomas Soome 12621a47de4eSToomas Soome if (be_is_isa("i386")) { 1263a63c99a2SToomas Soome if (be_has_grub()) { 1264a63c99a2SToomas Soome (void) snprintf(stage1, sizeof (stage1), "%s%s", 1265a63c99a2SToomas Soome tmp_mntpt, BE_GRUB_STAGE_1); 1266a63c99a2SToomas Soome (void) snprintf(stage2, sizeof (stage2), "%s%s", 1267a63c99a2SToomas Soome tmp_mntpt, BE_GRUB_STAGE_2); 1268a63c99a2SToomas Soome } else { 12691a47de4eSToomas Soome (void) snprintf(stage1, sizeof (stage1), "%s%s", 12701a47de4eSToomas Soome tmp_mntpt, BE_LOADER_STAGE_1); 12711a47de4eSToomas Soome (void) snprintf(stage2, sizeof (stage2), "%s%s", 12721a47de4eSToomas Soome tmp_mntpt, BE_LOADER_STAGE_2); 12731a47de4eSToomas Soome } 12741a47de4eSToomas Soome } else if (be_is_isa("sparc")) { 1275a63c99a2SToomas Soome char *platform = be_get_platform(); 1276a63c99a2SToomas Soome 1277a63c99a2SToomas Soome if (platform == NULL) { 12781a47de4eSToomas Soome be_print_err(gettext("be_do_installboot: " 12791a47de4eSToomas Soome "failed to detect system platform name\n")); 1280a63c99a2SToomas Soome if (be_mounted) 1281a63c99a2SToomas Soome (void) _be_unmount(bt->obe_name, 0); 1282a63c99a2SToomas Soome free(tmp_mntpt); 1283a63c99a2SToomas Soome return (BE_ERR_BOOTFILE_INST); 1284a63c99a2SToomas Soome } 1285a63c99a2SToomas Soome stage1[0] = '\0'; /* sparc has no stage1 */ 1286a63c99a2SToomas Soome (void) snprintf(stage2, sizeof (stage2), 1287a63c99a2SToomas Soome "%s/usr/platform/%s%s", tmp_mntpt, 1288a63c99a2SToomas Soome platform, BE_SPARC_BOOTBLK); 12891a47de4eSToomas Soome } else { 12901a47de4eSToomas Soome be_print_err(gettext("be_do_installboot: unsupported " 12911a47de4eSToomas Soome "architecture.\n")); 12921a47de4eSToomas Soome return (BE_ERR_BOOTFILE_INST); 1293a63c99a2SToomas Soome } 1294a63c99a2SToomas Soome 1295a63c99a2SToomas Soome if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) { 1296a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to open " 1297a63c99a2SToomas Soome "pool (%s): %s\n"), bt->obe_zpool, 1298a63c99a2SToomas Soome libzfs_error_description(g_zfs)); 1299a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs); 1300a63c99a2SToomas Soome if (be_mounted) 1301a63c99a2SToomas Soome (void) _be_unmount(bt->obe_name, 0); 1302a63c99a2SToomas Soome free(tmp_mntpt); 1303a63c99a2SToomas Soome return (ret); 1304a63c99a2SToomas Soome } 1305a63c99a2SToomas Soome 1306a63c99a2SToomas Soome if ((config = zpool_get_config(zphp, NULL)) == NULL) { 1307a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to get zpool " 1308a63c99a2SToomas Soome "configuration information. %s\n"), 1309a63c99a2SToomas Soome libzfs_error_description(g_zfs)); 1310a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs); 1311a63c99a2SToomas Soome goto done; 1312a63c99a2SToomas Soome } 1313a63c99a2SToomas Soome 1314a63c99a2SToomas Soome /* 1315a63c99a2SToomas Soome * Get the vdev tree 1316a63c99a2SToomas Soome */ 1317a63c99a2SToomas Soome if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) { 1318a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to get vdev " 1319a63c99a2SToomas Soome "tree: %s\n"), libzfs_error_description(g_zfs)); 1320a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs); 1321a63c99a2SToomas Soome goto done; 1322a63c99a2SToomas Soome } 1323a63c99a2SToomas Soome 1324a63c99a2SToomas Soome if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child, 1325a63c99a2SToomas Soome &children) != 0) { 1326a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to traverse " 1327a63c99a2SToomas Soome "the vdev tree: %s\n"), libzfs_error_description(g_zfs)); 1328a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs); 1329a63c99a2SToomas Soome goto done; 1330a63c99a2SToomas Soome } 1331a63c99a2SToomas Soome for (c = 0; c < children; c++) { 1332a63c99a2SToomas Soome uint_t i, nchildren = 0; 1333a63c99a2SToomas Soome nvlist_t **nvchild; 13341a47de4eSToomas Soome 13351a47de4eSToomas Soome /* ensure update on child status */ 13361a47de4eSToomas Soome vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose); 1337a63c99a2SToomas Soome if (vname == NULL) { 1338a63c99a2SToomas Soome be_print_err(gettext( 1339a63c99a2SToomas Soome "be_do_installboot: " 1340a63c99a2SToomas Soome "failed to get device name: %s\n"), 1341a63c99a2SToomas Soome libzfs_error_description(g_zfs)); 1342a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs); 1343a63c99a2SToomas Soome goto done; 13441a47de4eSToomas Soome } else if (verbose == B_TRUE) { 13451a47de4eSToomas Soome be_print_err(gettext("be_do_installboot: " 13461a47de4eSToomas Soome "device %s\n"), vname); 1347a63c99a2SToomas Soome } 1348a63c99a2SToomas Soome free(vname); 1349a63c99a2SToomas Soome 13501a47de4eSToomas Soome ret = nvlist_lookup_nvlist_array(child[c], 13511a47de4eSToomas Soome ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren); 13521a47de4eSToomas Soome if (ret != 0) { 13531a47de4eSToomas Soome if (ret != ENOENT) { 1354a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: " 1355a63c99a2SToomas Soome "failed to traverse the vdev tree: %s\n"), 1356a63c99a2SToomas Soome libzfs_error_description(g_zfs)); 1357a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs); 1358a63c99a2SToomas Soome goto done; 1359a63c99a2SToomas Soome } 13601a47de4eSToomas Soome nchildren = 0; /* This is leaf device. */ 13611a47de4eSToomas Soome } 1362a63c99a2SToomas Soome 13631a47de4eSToomas Soome if (nchildren != 0) { 1364a63c99a2SToomas Soome for (i = 0; i < nchildren; i++) { 13651a47de4eSToomas Soome /* ensure update on child status */ 13661a47de4eSToomas Soome vname = zpool_vdev_name(g_zfs, zphp, 13671a47de4eSToomas Soome nvchild[i], verbose); 13681a47de4eSToomas Soome if (vname == NULL) { 13691a47de4eSToomas Soome be_print_err(gettext( 13701a47de4eSToomas Soome "be_do_installboot: " 13711a47de4eSToomas Soome "failed to get device name: %s\n"), 13721a47de4eSToomas Soome libzfs_error_description(g_zfs)); 13731a47de4eSToomas Soome ret = zfs_err_to_be_err(g_zfs); 13741a47de4eSToomas Soome goto done; 13751a47de4eSToomas Soome } else if (verbose == B_TRUE) { 13761a47de4eSToomas Soome be_print_err(gettext( 13771a47de4eSToomas Soome "be_do_installboot: device %s\n"), 13781a47de4eSToomas Soome vname); 13791a47de4eSToomas Soome } 13801a47de4eSToomas Soome free(vname); 1381a63c99a2SToomas Soome ret = be_do_installboot_helper(zphp, nvchild[i], 1382c7c0ceafSToomas Soome stage1, stage2, flags); 1383a63c99a2SToomas Soome if (ret != BE_SUCCESS) 1384a63c99a2SToomas Soome goto done; 1385a63c99a2SToomas Soome } 1386a63c99a2SToomas Soome } else { 1387a63c99a2SToomas Soome ret = be_do_installboot_helper(zphp, child[c], stage1, 1388c7c0ceafSToomas Soome stage2, flags); 1389a63c99a2SToomas Soome if (ret != BE_SUCCESS) 1390a63c99a2SToomas Soome goto done; 1391a63c99a2SToomas Soome } 1392a63c99a2SToomas Soome } 1393a63c99a2SToomas Soome 1394a63c99a2SToomas Soome if (be_has_grub()) { 1395a63c99a2SToomas Soome ret = be_do_copy_grub_cap(bt); 1396a63c99a2SToomas Soome } 1397a63c99a2SToomas Soome 1398a63c99a2SToomas Soome done: 1399f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1400f169c0eaSGlenn Lagasse if (be_mounted) 1401f169c0eaSGlenn Lagasse (void) _be_unmount(bt->obe_name, 0); 1402f169c0eaSGlenn Lagasse zpool_close(zphp); 1403f169c0eaSGlenn Lagasse free(tmp_mntpt); 1404f169c0eaSGlenn Lagasse return (ret); 1405f169c0eaSGlenn Lagasse } 1406f169c0eaSGlenn Lagasse 1407f169c0eaSGlenn Lagasse /* 1408f169c0eaSGlenn Lagasse * Function: be_promote_zone_ds 1409f169c0eaSGlenn Lagasse * Description: This function finds the zones for the BE being activated 1410f169c0eaSGlenn Lagasse * and the active zonepath dataset for each zone. Then each 1411f169c0eaSGlenn Lagasse * active zonepath dataset is promoted. 1412f169c0eaSGlenn Lagasse * 1413f169c0eaSGlenn Lagasse * Parameters: 1414f169c0eaSGlenn Lagasse * be_name - the name of the global zone BE that we need to 1415f169c0eaSGlenn Lagasse * find the zones for. 1416f169c0eaSGlenn Lagasse * be_root_ds - the root dataset for be_name. 1417f169c0eaSGlenn Lagasse * Return: 1418f169c0eaSGlenn Lagasse * BE_SUCCESS - Success 1419f169c0eaSGlenn Lagasse * be_errno_t - Failure 1420f169c0eaSGlenn Lagasse * 1421f169c0eaSGlenn Lagasse * Scope: 1422f169c0eaSGlenn Lagasse * Private 1423f169c0eaSGlenn Lagasse */ 1424f169c0eaSGlenn Lagasse static int 1425f169c0eaSGlenn Lagasse be_promote_zone_ds(char *be_name, char *be_root_ds) 1426f169c0eaSGlenn Lagasse { 1427f169c0eaSGlenn Lagasse char *zone_ds = NULL; 1428f169c0eaSGlenn Lagasse char *temp_mntpt = NULL; 1429f169c0eaSGlenn Lagasse char origin[MAXPATHLEN]; 1430f169c0eaSGlenn Lagasse char zoneroot_ds[MAXPATHLEN]; 1431f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL; 1432f169c0eaSGlenn Lagasse zfs_handle_t *z_zhp = NULL; 1433f169c0eaSGlenn Lagasse zoneList_t zone_list = NULL; 1434f169c0eaSGlenn Lagasse zoneBrandList_t *brands = NULL; 1435f169c0eaSGlenn Lagasse boolean_t be_mounted = B_FALSE; 1436f169c0eaSGlenn Lagasse int zone_index = 0; 1437f169c0eaSGlenn Lagasse int err = BE_SUCCESS; 1438f169c0eaSGlenn Lagasse 1439f169c0eaSGlenn Lagasse /* 1440f169c0eaSGlenn Lagasse * Get the supported zone brands so we can pass that 1441f169c0eaSGlenn Lagasse * to z_get_nonglobal_zone_list_by_brand. Currently 1442f169c0eaSGlenn Lagasse * only the ipkg and labeled brand zones are supported 1443f169c0eaSGlenn Lagasse * 1444f169c0eaSGlenn Lagasse */ 1445f169c0eaSGlenn Lagasse if ((brands = be_get_supported_brandlist()) == NULL) { 1446f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: no supported " 1447f169c0eaSGlenn Lagasse "brands\n")); 1448f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1449f169c0eaSGlenn Lagasse } 1450f169c0eaSGlenn Lagasse 1451f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_ds, 1452f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 1453f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: Failed to open " 1454f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), be_root_ds, 1455f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1456f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 1457f169c0eaSGlenn Lagasse z_free_brand_list(brands); 1458f169c0eaSGlenn Lagasse return (err); 1459f169c0eaSGlenn Lagasse } 1460f169c0eaSGlenn Lagasse 1461f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &temp_mntpt)) { 1462f169c0eaSGlenn Lagasse if ((err = _be_mount(be_name, &temp_mntpt, 1463f169c0eaSGlenn Lagasse BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) { 1464f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: failed to " 1465f169c0eaSGlenn Lagasse "mount the BE for zones procesing.\n")); 1466f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1467f169c0eaSGlenn Lagasse z_free_brand_list(brands); 1468f169c0eaSGlenn Lagasse return (err); 1469f169c0eaSGlenn Lagasse } 1470f169c0eaSGlenn Lagasse be_mounted = B_TRUE; 1471f169c0eaSGlenn Lagasse } 1472f169c0eaSGlenn Lagasse 1473f169c0eaSGlenn Lagasse /* 1474f169c0eaSGlenn Lagasse * Set the zone root to the temp mount point for the BE we just mounted. 1475f169c0eaSGlenn Lagasse */ 1476f169c0eaSGlenn Lagasse z_set_zone_root(temp_mntpt); 1477f169c0eaSGlenn Lagasse 1478f169c0eaSGlenn Lagasse /* 1479f169c0eaSGlenn Lagasse * Get all the zones based on the brands we're looking for. If no zones 1480f169c0eaSGlenn Lagasse * are found that we're interested in unmount the BE and move on. 1481f169c0eaSGlenn Lagasse */ 1482f169c0eaSGlenn Lagasse if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) { 1483f169c0eaSGlenn Lagasse if (be_mounted) 1484f169c0eaSGlenn Lagasse (void) _be_unmount(be_name, 0); 1485f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1486f169c0eaSGlenn Lagasse z_free_brand_list(brands); 1487f169c0eaSGlenn Lagasse free(temp_mntpt); 1488f169c0eaSGlenn Lagasse return (BE_SUCCESS); 1489f169c0eaSGlenn Lagasse } 1490f169c0eaSGlenn Lagasse for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index) 1491f169c0eaSGlenn Lagasse != NULL; zone_index++) { 1492f169c0eaSGlenn Lagasse char *zone_path = NULL; 1493f169c0eaSGlenn Lagasse 1494f169c0eaSGlenn Lagasse /* Skip zones that aren't at least installed */ 1495f169c0eaSGlenn Lagasse if (z_zlist_get_current_state(zone_list, zone_index) < 1496f169c0eaSGlenn Lagasse ZONE_STATE_INSTALLED) 1497f169c0eaSGlenn Lagasse continue; 1498f169c0eaSGlenn Lagasse 1499f169c0eaSGlenn Lagasse if (((zone_path = 1500f169c0eaSGlenn Lagasse z_zlist_get_zonepath(zone_list, zone_index)) == NULL) || 1501f169c0eaSGlenn Lagasse ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) || 1502f169c0eaSGlenn Lagasse !be_zone_supported(zone_ds)) 1503f169c0eaSGlenn Lagasse continue; 1504f169c0eaSGlenn Lagasse 1505f169c0eaSGlenn Lagasse if (be_find_active_zone_root(zhp, zone_ds, 1506f169c0eaSGlenn Lagasse zoneroot_ds, sizeof (zoneroot_ds)) != 0) { 1507f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: " 1508f169c0eaSGlenn Lagasse "Zone does not have an active root " 1509f169c0eaSGlenn Lagasse "dataset, skipping this zone.\n")); 1510f169c0eaSGlenn Lagasse continue; 1511f169c0eaSGlenn Lagasse } 1512f169c0eaSGlenn Lagasse 1513f169c0eaSGlenn Lagasse if ((z_zhp = zfs_open(g_zfs, zoneroot_ds, 1514f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 1515f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: " 1516f169c0eaSGlenn Lagasse "Failed to open dataset " 1517f169c0eaSGlenn Lagasse "(%s): %s\n"), zoneroot_ds, 1518f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1519f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs); 1520f169c0eaSGlenn Lagasse goto done; 1521f169c0eaSGlenn Lagasse } 1522f169c0eaSGlenn Lagasse 1523f169c0eaSGlenn Lagasse if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin, 1524f169c0eaSGlenn Lagasse sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) { 1525f169c0eaSGlenn Lagasse ZFS_CLOSE(z_zhp); 1526f169c0eaSGlenn Lagasse continue; 1527f169c0eaSGlenn Lagasse } 1528f169c0eaSGlenn Lagasse 1529f169c0eaSGlenn Lagasse /* 1530f169c0eaSGlenn Lagasse * We don't need to close the zfs handle at this 1531f169c0eaSGlenn Lagasse * point because the callback funtion 1532f169c0eaSGlenn Lagasse * be_promote_ds_callback() will close it for us. 1533f169c0eaSGlenn Lagasse */ 1534f169c0eaSGlenn Lagasse if (be_promote_ds_callback(z_zhp, NULL) != 0) { 1535f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: " 1536f169c0eaSGlenn Lagasse "failed to activate the " 1537f169c0eaSGlenn Lagasse "datasets for %s: %s\n"), 1538f169c0eaSGlenn Lagasse zoneroot_ds, 1539f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1540f169c0eaSGlenn Lagasse err = BE_ERR_PROMOTE; 1541f169c0eaSGlenn Lagasse goto done; 1542f169c0eaSGlenn Lagasse } 1543f169c0eaSGlenn Lagasse } 1544f169c0eaSGlenn Lagasse done: 1545f169c0eaSGlenn Lagasse if (be_mounted) 1546f169c0eaSGlenn Lagasse (void) _be_unmount(be_name, 0); 1547f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1548f169c0eaSGlenn Lagasse free(temp_mntpt); 1549f169c0eaSGlenn Lagasse z_free_brand_list(brands); 1550f169c0eaSGlenn Lagasse z_free_zone_list(zone_list); 1551f169c0eaSGlenn Lagasse return (err); 1552f169c0eaSGlenn Lagasse } 1553f169c0eaSGlenn Lagasse 1554f169c0eaSGlenn Lagasse /* 1555f169c0eaSGlenn Lagasse * Function: be_promote_ds_callback 1556f169c0eaSGlenn Lagasse * Description: This function is used to promote the datasets for the BE 1557f169c0eaSGlenn Lagasse * being activated as well as the datasets for the zones BE 1558f169c0eaSGlenn Lagasse * being activated. 1559f169c0eaSGlenn Lagasse * 1560f169c0eaSGlenn Lagasse * Parameters: 1561f169c0eaSGlenn Lagasse * zhp - the zfs handle for zone BE being activated. 1562f169c0eaSGlenn Lagasse * data - not used. 1563f169c0eaSGlenn Lagasse * Return: 1564f169c0eaSGlenn Lagasse * 0 - Success 1565f169c0eaSGlenn Lagasse * be_errno_t - Failure 1566f169c0eaSGlenn Lagasse * 1567f169c0eaSGlenn Lagasse * Scope: 1568f169c0eaSGlenn Lagasse * Private 1569f169c0eaSGlenn Lagasse */ 1570f169c0eaSGlenn Lagasse static int 1571f169c0eaSGlenn Lagasse /* LINTED */ 1572f169c0eaSGlenn Lagasse be_promote_ds_callback(zfs_handle_t *zhp, void *data) 1573f169c0eaSGlenn Lagasse { 1574f169c0eaSGlenn Lagasse char origin[MAXPATHLEN]; 1575f169c0eaSGlenn Lagasse char *sub_dataset = NULL; 1576f169c0eaSGlenn Lagasse int ret = 0; 1577f169c0eaSGlenn Lagasse 1578f169c0eaSGlenn Lagasse if (zhp != NULL) { 1579f169c0eaSGlenn Lagasse sub_dataset = strdup(zfs_get_name(zhp)); 1580f169c0eaSGlenn Lagasse if (sub_dataset == NULL) { 1581f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM; 1582f169c0eaSGlenn Lagasse goto done; 1583f169c0eaSGlenn Lagasse } 1584f169c0eaSGlenn Lagasse } else { 1585f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_ds_callback: " 1586f169c0eaSGlenn Lagasse "Invalid zfs handle passed into function\n")); 1587f169c0eaSGlenn Lagasse ret = BE_ERR_INVAL; 1588f169c0eaSGlenn Lagasse goto done; 1589f169c0eaSGlenn Lagasse } 1590f169c0eaSGlenn Lagasse 1591f169c0eaSGlenn Lagasse /* 1592f169c0eaSGlenn Lagasse * This loop makes sure that we promote the dataset to the 1593f169c0eaSGlenn Lagasse * top of the tree so that it is no longer a decendent of any 1594f169c0eaSGlenn Lagasse * dataset. The ZFS close and then open is used to make sure that 1595f169c0eaSGlenn Lagasse * the promotion is updated before we move on. 1596f169c0eaSGlenn Lagasse */ 1597f169c0eaSGlenn Lagasse while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin, 1598f169c0eaSGlenn Lagasse sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) { 1599f169c0eaSGlenn Lagasse if (zfs_promote(zhp) != 0) { 1600f169c0eaSGlenn Lagasse if (libzfs_errno(g_zfs) != EZFS_EXISTS) { 1601f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_ds_callback: " 1602f169c0eaSGlenn Lagasse "promote of %s failed: %s\n"), 1603f169c0eaSGlenn Lagasse zfs_get_name(zhp), 1604f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1605f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1606f169c0eaSGlenn Lagasse goto done; 1607f169c0eaSGlenn Lagasse } else { 1608f169c0eaSGlenn Lagasse /* 1609f169c0eaSGlenn Lagasse * If the call to zfs_promote returns the 1610f169c0eaSGlenn Lagasse * error EZFS_EXISTS we've hit a snapshot name 1611f169c0eaSGlenn Lagasse * collision. This means we're probably 1612f169c0eaSGlenn Lagasse * attemping to promote a zone dataset above a 1613f169c0eaSGlenn Lagasse * parent dataset that belongs to another zone 1614f169c0eaSGlenn Lagasse * which this zone was cloned from. 1615f169c0eaSGlenn Lagasse * 1616f169c0eaSGlenn Lagasse * TODO: If this is a zone dataset at some 1617f169c0eaSGlenn Lagasse * point we should skip this if the zone 1618f169c0eaSGlenn Lagasse * paths for the dataset and the snapshot 1619f169c0eaSGlenn Lagasse * don't match. 1620f169c0eaSGlenn Lagasse */ 1621f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_ds_callback: " 1622f169c0eaSGlenn Lagasse "promote of %s failed due to snapshot " 1623f169c0eaSGlenn Lagasse "name collision: %s\n"), zfs_get_name(zhp), 1624f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1625f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1626f169c0eaSGlenn Lagasse goto done; 1627f169c0eaSGlenn Lagasse } 1628f169c0eaSGlenn Lagasse } 1629f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1630f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, sub_dataset, 1631f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) { 1632f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_ds_callback: " 1633f169c0eaSGlenn Lagasse "Failed to open dataset (%s): %s\n"), sub_dataset, 1634f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs)); 1635f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs); 1636f169c0eaSGlenn Lagasse goto done; 1637f169c0eaSGlenn Lagasse } 1638f169c0eaSGlenn Lagasse } 1639f169c0eaSGlenn Lagasse 1640f169c0eaSGlenn Lagasse /* Iterate down this dataset's children and promote them */ 1641f169c0eaSGlenn Lagasse ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL); 1642f169c0eaSGlenn Lagasse 1643f169c0eaSGlenn Lagasse done: 1644f169c0eaSGlenn Lagasse free(sub_dataset); 1645f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp); 1646f169c0eaSGlenn Lagasse return (ret); 1647f169c0eaSGlenn Lagasse } 1648