1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright (c) 2012 by Delphix. All rights reserved. 25 */ 26 27 #include <assert.h> 28 #include <libintl.h> 29 #include <libnvpair.h> 30 #include <libzfs.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <unistd.h> 37 38 #include <libbe.h> 39 #include <libbe_priv.h> 40 41 /* ******************************************************************** */ 42 /* Public Functions */ 43 /* ******************************************************************** */ 44 45 /* 46 * Function: be_rename 47 * Description: Renames the BE from the original name to the new name 48 * passed in through be_attrs. Also the entries in vfstab and 49 * menu.lst are updated with the new name. 50 * Parameters: 51 * be_attrs - pointer to nvlist_t of attributes being passed in. 52 * The following attribute values are used by 53 * this function: 54 * 55 * BE_ATTR_ORIG_BE_NAME *required 56 * BE_ATTR_NEW_BE_NAME *required 57 * Return: 58 * BE_SUCCESS - Success 59 * be_errno_t - Failure 60 * Scope: 61 * Public 62 */ 63 64 int 65 be_rename(nvlist_t *be_attrs) 66 { 67 be_transaction_data_t bt = { 0 }; 68 be_transaction_data_t cbt = { 0 }; 69 be_fs_list_data_t fld = { 0 }; 70 zfs_handle_t *zhp = NULL; 71 char root_ds[MAXPATHLEN]; 72 char be_root_container[MAXPATHLEN]; 73 char *mp = NULL; 74 int zret = 0, ret = BE_SUCCESS; 75 76 /* Initialize libzfs handle */ 77 if (!be_zfs_init()) 78 return (BE_ERR_INIT); 79 80 /* Get original BE name to rename from */ 81 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name) 82 != 0) { 83 be_print_err(gettext("be_rename: failed to " 84 "lookup BE_ATTR_ORIG_BE_NAME attribute\n")); 85 be_zfs_fini(); 86 return (BE_ERR_INVAL); 87 } 88 89 /* Get new BE name to rename to */ 90 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name) 91 != 0) { 92 be_print_err(gettext("be_rename: failed to " 93 "lookup BE_ATTR_NEW_BE_NAME attribute\n")); 94 be_zfs_fini(); 95 return (BE_ERR_INVAL); 96 } 97 98 /* 99 * Get the currently active BE and check to see if this 100 * is an attempt to rename the currently active BE. 101 */ 102 if (be_find_current_be(&cbt) != BE_SUCCESS) { 103 be_print_err(gettext("be_rename: failed to find the currently " 104 "active BE\n")); 105 be_zfs_fini(); 106 return (BE_ERR_CURR_BE_NOT_FOUND); 107 } 108 109 if (strncmp(bt.obe_name, cbt.obe_name, 110 MAX(strlen(bt.obe_name), strlen(cbt.obe_name))) == 0) { 111 be_print_err(gettext("be_rename: This is an attempt to rename " 112 "the currently active BE, which is not supported\n")); 113 be_zfs_fini(); 114 free(cbt.obe_name); 115 return (BE_ERR_RENAME_ACTIVE); 116 } 117 118 /* Validate original BE name */ 119 if (!be_valid_be_name(bt.obe_name)) { 120 be_print_err(gettext("be_rename: " 121 "invalid BE name %s\n"), bt.obe_name); 122 be_zfs_fini(); 123 return (BE_ERR_INVAL); 124 } 125 126 /* Validate new BE name */ 127 if (!be_valid_be_name(bt.nbe_name)) { 128 be_print_err(gettext("be_rename: invalid BE name %s\n"), 129 bt.nbe_name); 130 be_zfs_fini(); 131 return (BE_ERR_INVAL); 132 } 133 134 /* Find which zpool the BE is in */ 135 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 136 be_print_err(gettext("be_rename: failed to " 137 "find zpool for BE (%s)\n"), bt.obe_name); 138 be_zfs_fini(); 139 return (BE_ERR_BE_NOENT); 140 } else if (zret < 0) { 141 be_print_err(gettext("be_rename: zpool_iter failed: %s\n"), 142 libzfs_error_description(g_zfs)); 143 ret = zfs_err_to_be_err(g_zfs); 144 be_zfs_fini(); 145 return (ret); 146 } 147 148 /* New BE will reside in the same zpool as orig BE */ 149 bt.nbe_zpool = bt.obe_zpool; 150 151 be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds, sizeof (root_ds)); 152 bt.obe_root_ds = strdup(root_ds); 153 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, root_ds, sizeof (root_ds)); 154 bt.nbe_root_ds = strdup(root_ds); 155 156 /* 157 * Generate a list of file systems from the BE that are legacy 158 * mounted before renaming. We use this list to determine which 159 * entries in the vfstab we need to update after we've renamed the BE. 160 */ 161 if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL, 162 &fld)) != BE_SUCCESS) { 163 be_print_err(gettext("be_rename: failed to " 164 "get legacy mounted file system list for %s\n"), 165 bt.obe_name); 166 goto done; 167 } 168 169 /* Get handle to BE's root dataset */ 170 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) 171 == NULL) { 172 be_print_err(gettext("be_rename: failed to " 173 "open BE root dataset (%s): %s\n"), 174 bt.obe_root_ds, libzfs_error_description(g_zfs)); 175 ret = zfs_err_to_be_err(g_zfs); 176 goto done; 177 } 178 179 /* Rename of BE's root dataset. */ 180 if (zfs_rename(zhp, bt.nbe_root_ds, B_FALSE, B_FALSE) != 0) { 181 be_print_err(gettext("be_rename: failed to " 182 "rename dataset (%s): %s\n"), bt.obe_root_ds, 183 libzfs_error_description(g_zfs)); 184 ret = zfs_err_to_be_err(g_zfs); 185 goto done; 186 } 187 188 /* Refresh handle to BE's root dataset after the rename */ 189 ZFS_CLOSE(zhp); 190 if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds, ZFS_TYPE_FILESYSTEM)) 191 == NULL) { 192 be_print_err(gettext("be_rename: failed to " 193 "open BE root dataset (%s): %s\n"), 194 bt.obe_root_ds, libzfs_error_description(g_zfs)); 195 ret = zfs_err_to_be_err(g_zfs); 196 goto done; 197 } 198 199 /* If BE is already mounted, get its mountpoint */ 200 if (zfs_is_mounted(zhp, &mp) && mp == NULL) { 201 be_print_err(gettext("be_rename: failed to " 202 "get altroot of mounted BE %s: %s\n"), 203 bt.nbe_name, libzfs_error_description(g_zfs)); 204 ret = zfs_err_to_be_err(g_zfs); 205 goto done; 206 } 207 208 /* Update BE's vfstab */ 209 210 /* 211 * Since the new and old BEs reside in the same pool (see above), 212 * the same variable can be used for the container for both. 213 */ 214 be_make_root_container_ds(bt.obe_zpool, be_root_container, 215 sizeof (be_root_container)); 216 217 if ((ret = be_update_vfstab(bt.nbe_name, be_root_container, 218 be_root_container, &fld, mp)) != BE_SUCCESS) { 219 be_print_err(gettext("be_rename: " 220 "failed to update new BE's vfstab (%s)\n"), bt.nbe_name); 221 goto done; 222 } 223 224 /* Update this BE's GRUB menu entry */ 225 if (getzoneid() == GLOBAL_ZONEID && (ret = be_update_menu(bt.obe_name, 226 bt.nbe_name, bt.obe_zpool, NULL)) != BE_SUCCESS) { 227 be_print_err(gettext("be_rename: " 228 "failed to update grub menu entry from %s to %s\n"), 229 bt.obe_name, bt.nbe_name); 230 } 231 232 done: 233 be_free_fs_list(&fld); 234 235 ZFS_CLOSE(zhp); 236 237 be_zfs_fini(); 238 239 free(bt.obe_root_ds); 240 free(bt.nbe_root_ds); 241 return (ret); 242 } 243