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 *mp = NULL; 73 int zret = 0, ret = BE_SUCCESS; 74 75 /* Initialize libzfs handle */ 76 if (!be_zfs_init()) 77 return (BE_ERR_INIT); 78 79 /* Get original BE name to rename from */ 80 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &bt.obe_name) 81 != 0) { 82 be_print_err(gettext("be_rename: failed to " 83 "lookup BE_ATTR_ORIG_BE_NAME attribute\n")); 84 be_zfs_fini(); 85 return (BE_ERR_INVAL); 86 } 87 88 /* Get new BE name to rename to */ 89 if (nvlist_lookup_string(be_attrs, BE_ATTR_NEW_BE_NAME, &bt.nbe_name) 90 != 0) { 91 be_print_err(gettext("be_rename: failed to " 92 "lookup BE_ATTR_NEW_BE_NAME attribute\n")); 93 be_zfs_fini(); 94 return (BE_ERR_INVAL); 95 } 96 97 /* 98 * Get the currently active BE and check to see if this 99 * is an attempt to rename the currently active BE. 100 */ 101 if (be_find_current_be(&cbt) != BE_SUCCESS) { 102 be_print_err(gettext("be_rename: failed to find the currently " 103 "active BE\n")); 104 be_zfs_fini(); 105 return (BE_ERR_CURR_BE_NOT_FOUND); 106 } 107 108 if (strncmp(bt.obe_name, cbt.obe_name, 109 MAX(strlen(bt.obe_name), strlen(cbt.obe_name))) == 0) { 110 be_print_err(gettext("be_rename: This is an attempt to rename " 111 "the currently active BE, which is not supported\n")); 112 be_zfs_fini(); 113 free(cbt.obe_name); 114 return (BE_ERR_RENAME_ACTIVE); 115 } 116 117 /* Validate original BE name */ 118 if (!be_valid_be_name(bt.obe_name)) { 119 be_print_err(gettext("be_rename: " 120 "invalid BE name %s\n"), bt.obe_name); 121 be_zfs_fini(); 122 return (BE_ERR_INVAL); 123 } 124 125 /* Validate new BE name */ 126 if (!be_valid_be_name(bt.nbe_name)) { 127 be_print_err(gettext("be_rename: invalid BE name %s\n"), 128 bt.nbe_name); 129 be_zfs_fini(); 130 return (BE_ERR_INVAL); 131 } 132 133 /* Find which zpool the BE is in */ 134 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &bt)) == 0) { 135 be_print_err(gettext("be_rename: failed to " 136 "find zpool for BE (%s)\n"), bt.obe_name); 137 be_zfs_fini(); 138 return (BE_ERR_BE_NOENT); 139 } else if (zret < 0) { 140 be_print_err(gettext("be_rename: zpool_iter failed: %s\n"), 141 libzfs_error_description(g_zfs)); 142 ret = zfs_err_to_be_err(g_zfs); 143 be_zfs_fini(); 144 return (ret); 145 } 146 147 /* New BE will reside in the same zpool as orig BE */ 148 bt.nbe_zpool = bt.obe_zpool; 149 150 be_make_root_ds(bt.obe_zpool, bt.obe_name, root_ds, sizeof (root_ds)); 151 bt.obe_root_ds = strdup(root_ds); 152 be_make_root_ds(bt.nbe_zpool, bt.nbe_name, root_ds, sizeof (root_ds)); 153 bt.nbe_root_ds = strdup(root_ds); 154 155 /* 156 * Generate a list of file systems from the BE that are legacy 157 * mounted before renaming. We use this list to determine which 158 * entries in the vfstab we need to update after we've renamed the BE. 159 */ 160 if ((ret = be_get_legacy_fs(bt.obe_name, bt.obe_root_ds, NULL, NULL, 161 &fld)) != BE_SUCCESS) { 162 be_print_err(gettext("be_rename: failed to " 163 "get legacy mounted file system list for %s\n"), 164 bt.obe_name); 165 goto done; 166 } 167 168 /* Get handle to BE's root dataset */ 169 if ((zhp = zfs_open(g_zfs, bt.obe_root_ds, ZFS_TYPE_FILESYSTEM)) 170 == NULL) { 171 be_print_err(gettext("be_rename: failed to " 172 "open BE root dataset (%s): %s\n"), 173 bt.obe_root_ds, libzfs_error_description(g_zfs)); 174 ret = zfs_err_to_be_err(g_zfs); 175 goto done; 176 } 177 178 /* Rename of BE's root dataset. */ 179 if (zfs_rename(zhp, bt.nbe_root_ds, B_FALSE, B_FALSE) != 0) { 180 be_print_err(gettext("be_rename: failed to " 181 "rename dataset (%s): %s\n"), bt.obe_root_ds, 182 libzfs_error_description(g_zfs)); 183 ret = zfs_err_to_be_err(g_zfs); 184 goto done; 185 } 186 187 /* Refresh handle to BE's root dataset after the rename */ 188 ZFS_CLOSE(zhp); 189 if ((zhp = zfs_open(g_zfs, bt.nbe_root_ds, ZFS_TYPE_FILESYSTEM)) 190 == NULL) { 191 be_print_err(gettext("be_rename: failed to " 192 "open BE root dataset (%s): %s\n"), 193 bt.obe_root_ds, libzfs_error_description(g_zfs)); 194 ret = zfs_err_to_be_err(g_zfs); 195 goto done; 196 } 197 198 /* If BE is already mounted, get its mountpoint */ 199 if (zfs_is_mounted(zhp, &mp) && mp == NULL) { 200 be_print_err(gettext("be_rename: failed to " 201 "get altroot of mounted BE %s: %s\n"), 202 bt.nbe_name, libzfs_error_description(g_zfs)); 203 ret = zfs_err_to_be_err(g_zfs); 204 goto done; 205 } 206 207 /* Update BE's vfstab */ 208 if ((ret = be_update_vfstab(bt.nbe_name, bt.obe_zpool, bt.nbe_zpool, 209 &fld, mp)) != BE_SUCCESS) { 210 be_print_err(gettext("be_rename: " 211 "failed to update new BE's vfstab (%s)\n"), bt.nbe_name); 212 goto done; 213 } 214 215 /* Update this BE's GRUB menu entry */ 216 if (getzoneid() == GLOBAL_ZONEID && (ret = be_update_menu(bt.obe_name, 217 bt.nbe_name, bt.obe_zpool, NULL)) != BE_SUCCESS) { 218 be_print_err(gettext("be_rename: " 219 "failed to update grub menu entry from %s to %s\n"), 220 bt.obe_name, bt.nbe_name); 221 } 222 223 done: 224 be_free_fs_list(&fld); 225 226 ZFS_CLOSE(zhp); 227 228 be_zfs_fini(); 229 230 free(bt.obe_root_ds); 231 free(bt.nbe_root_ds); 232 return (ret); 233 } 234