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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /*LINTLIBRARY*/ 28 29 30 #include <stdio.h> 31 #include <errno.h> 32 #include <memory.h> 33 #include <unistd.h> 34 #include <sys/types.h> 35 #include <sys/param.h> 36 #include <sys/dkio.h> 37 #include <sys/vtoc.h> 38 #include <strings.h> 39 #include <limits.h> 40 41 /* 42 * To copy each field of vtoc individually for copying extvtoc 43 * to 32 bit vtoc and vs. 44 * Currently bootinfo and timestamp are not really supported. 45 */ 46 47 #define libadm_vtoc_copy(vs, vd) \ 48 { \ 49 int i; \ 50 vd->v_bootinfo[0] = (unsigned)vs->v_bootinfo[0]; \ 51 vd->v_bootinfo[1] = (unsigned)vs->v_bootinfo[1]; \ 52 vd->v_bootinfo[2] = (unsigned)vs->v_bootinfo[2]; \ 53 vd->v_sanity = (unsigned)vs->v_sanity; \ 54 vd->v_version = (unsigned)vs->v_version; \ 55 bcopy(vs->v_volume, vd->v_volume, LEN_DKL_VVOL); \ 56 vd->v_sectorsz = vs->v_sectorsz; \ 57 vd->v_nparts = vs->v_nparts; \ 58 vd->v_version = (unsigned)vs->v_version; \ 59 for (i = 0; i < 10; i++) \ 60 vd->v_reserved[i] = (unsigned)vs->v_reserved[i];\ 61 for (i = 0; i < V_NUMPAR; i++) { \ 62 vd->v_part[i].p_tag = vs->v_part[i].p_tag; \ 63 vd->v_part[i].p_flag = vs->v_part[i].p_flag; \ 64 vd->v_part[i].p_start = (unsigned)vs->v_part[i].p_start;\ 65 vd->v_part[i].p_size = (unsigned)vs->v_part[i].p_size; \ 66 } \ 67 for (i = 0; i < V_NUMPAR; i++) \ 68 if ((sizeof (vd->timestamp[i]) != sizeof (vs->timestamp[i])) &&\ 69 (vs->timestamp[i] > INT32_MAX)) \ 70 vd->timestamp[i] = INT32_MAX; \ 71 else \ 72 vd->timestamp[i] = (unsigned)vs->timestamp[i]; \ 73 bcopy(vs->v_asciilabel, vd->v_asciilabel, LEN_DKL_ASCII); \ 74 } 75 76 77 /* 78 * Read VTOC - return partition number. 79 */ 80 int 81 read_vtoc(int fd, struct vtoc *vtoc) 82 { 83 struct dk_cinfo dki_info; 84 85 /* 86 * Read the vtoc. 87 */ 88 if (ioctl(fd, DKIOCGVTOC, (caddr_t)vtoc) == -1) { 89 switch (errno) { 90 case EIO: 91 return (VT_EIO); 92 case EINVAL: 93 return (VT_EINVAL); 94 case ENOTSUP: 95 /* GPT labeled or disk > 1TB with no extvtoc support */ 96 return (VT_ENOTSUP); 97 case EOVERFLOW: 98 return (VT_EOVERFLOW); 99 default: 100 return (VT_ERROR); 101 } 102 } 103 104 /* 105 * Sanity-check the vtoc. 106 */ 107 if (vtoc->v_sanity != VTOC_SANE) { 108 return (VT_EINVAL); 109 } 110 111 /* 112 * Convert older-style vtoc's. 113 */ 114 switch (vtoc->v_version) { 115 case 0: 116 /* 117 * No vtoc information. Install default 118 * nparts/sectorsz and version. We are 119 * assuming that the driver returns the 120 * current partition information correctly. 121 */ 122 123 vtoc->v_version = V_VERSION; 124 if (vtoc->v_nparts == 0) 125 vtoc->v_nparts = V_NUMPAR; 126 if (vtoc->v_sectorsz == 0) 127 vtoc->v_sectorsz = DEV_BSIZE; 128 129 break; 130 131 case V_VERSION: 132 break; 133 134 default: 135 return (VT_EINVAL); 136 } 137 138 /* 139 * Return partition number for this file descriptor. 140 */ 141 if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) { 142 switch (errno) { 143 case EIO: 144 return (VT_EIO); 145 case EINVAL: 146 return (VT_EINVAL); 147 default: 148 return (VT_ERROR); 149 } 150 } 151 if (dki_info.dki_partition > V_NUMPAR) { 152 return (VT_EINVAL); 153 } 154 return ((int)dki_info.dki_partition); 155 } 156 157 /* 158 * Write VTOC 159 */ 160 int 161 write_vtoc(int fd, struct vtoc *vtoc) 162 { 163 int i; 164 /* 165 * Sanity-check the vtoc 166 */ 167 if (vtoc->v_sanity != VTOC_SANE || vtoc->v_nparts > V_NUMPAR) { 168 return (-1); 169 } 170 171 /* 172 * since many drivers won't allow opening a device make sure 173 * all partitions aren't being set to zero. If all are zero then 174 * we have no way to set them to something else 175 */ 176 177 for (i = 0; i < (int)vtoc->v_nparts; i++) 178 if (vtoc->v_part[i].p_size > 0) 179 break; 180 if (i == (int)vtoc->v_nparts) 181 return (-1); 182 183 /* 184 * Write the vtoc 185 */ 186 if (ioctl(fd, DKIOCSVTOC, (caddr_t)vtoc) == -1) { 187 switch (errno) { 188 case EIO: 189 return (VT_EIO); 190 case EINVAL: 191 return (VT_EINVAL); 192 case ENOTSUP: 193 /* GPT labeled or disk > 1TB with no extvtoc support */ 194 return (VT_ENOTSUP); 195 case EOVERFLOW: 196 return (VT_EOVERFLOW); 197 default: 198 return (VT_ERROR); 199 } 200 } 201 return (0); 202 } 203 204 int 205 read_extvtoc(int fd, struct extvtoc *extvtoc) 206 { 207 struct dk_cinfo dki_info; 208 struct vtoc oldvtoc; 209 struct vtoc *oldvtocp = &oldvtoc; 210 int ret; 211 212 /* 213 * Read the vtoc. 214 */ 215 if (ioctl(fd, DKIOCGEXTVTOC, (caddr_t)extvtoc) == -1) { 216 switch (errno) { 217 case EIO: 218 return (VT_EIO); 219 case EINVAL: 220 return (VT_EINVAL); 221 /* for disks > 1TB */ 222 case ENOTSUP: 223 return (VT_ENOTSUP); 224 case EOVERFLOW: 225 return (VT_EOVERFLOW); 226 case ENOTTY: 227 228 if ((ret = read_vtoc(fd, oldvtocp)) < 0) 229 return (ret); 230 231 #ifdef _LP64 232 /* 233 * 64-bit vtoc and extvtoc have the same field sizes 234 * and offsets. 235 */ 236 bcopy(oldvtocp, extvtoc, sizeof (struct extvtoc)); 237 #else 238 bzero(extvtoc, sizeof (struct extvtoc)); 239 libadm_vtoc_copy(oldvtocp, extvtoc); 240 #endif 241 return (ret); 242 243 244 default: 245 return (VT_ERROR); 246 } 247 } 248 249 /* 250 * Sanity-check the vtoc. 251 */ 252 if (extvtoc->v_sanity != VTOC_SANE) { 253 return (VT_EINVAL); 254 } 255 256 switch (extvtoc->v_version) { 257 case 0: 258 /* 259 * For pre-version 1 vtoc keep same functionality 260 * as read_vtoc. 261 */ 262 263 extvtoc->v_version = V_VERSION; 264 if (extvtoc->v_nparts == 0) 265 extvtoc->v_nparts = V_NUMPAR; 266 if (extvtoc->v_sectorsz == 0) 267 extvtoc->v_sectorsz = DEV_BSIZE; 268 269 break; 270 271 case V_VERSION: 272 break; 273 274 default: 275 return (VT_EINVAL); 276 } 277 278 /* 279 * Return partition number for this file descriptor. 280 */ 281 if (ioctl(fd, DKIOCINFO, (caddr_t)&dki_info) == -1) { 282 switch (errno) { 283 case EIO: 284 return (VT_EIO); 285 case EINVAL: 286 return (VT_EINVAL); 287 default: 288 return (VT_ERROR); 289 } 290 } 291 if (dki_info.dki_partition > V_NUMPAR) { 292 return (VT_EINVAL); 293 } 294 return ((int)dki_info.dki_partition); 295 } 296 297 /* 298 * Write ext VTOC. 299 */ 300 int 301 write_extvtoc(int fd, struct extvtoc *extvtoc) 302 { 303 int i; 304 struct vtoc oldvtoc; 305 struct vtoc *oldvtocp = &oldvtoc; 306 /* 307 * Sanity-check the vtoc 308 */ 309 if (extvtoc->v_sanity != VTOC_SANE || extvtoc->v_nparts > V_NUMPAR) { 310 return (-1); 311 } 312 313 /* 314 * since many drivers won't allow opening a device make sure 315 * all partitions aren't being set to zero. If all are zero then 316 * we have no way to set them to something else 317 */ 318 319 for (i = 0; i < (int)extvtoc->v_nparts; i++) 320 if (extvtoc->v_part[i].p_size > 0) 321 break; 322 if (i == (int)extvtoc->v_nparts) 323 return (-1); 324 325 /* 326 * Write the extvtoc 327 */ 328 if (ioctl(fd, DKIOCSEXTVTOC, (caddr_t)extvtoc) == -1) { 329 switch (errno) { 330 case EIO: 331 return (VT_EIO); 332 case EINVAL: 333 return (VT_EINVAL); 334 /* for disks > 1TB */ 335 case ENOTSUP: 336 return (VT_ENOTSUP); 337 case EOVERFLOW: 338 return (VT_EOVERFLOW); 339 case ENOTTY: 340 #ifdef _LP64 341 /* 342 * 64-bit vtoc and extvtoc have the same field sizes 343 * and offsets. 344 */ 345 bcopy(extvtoc, oldvtocp, sizeof (struct vtoc)); 346 #else 347 bzero(oldvtocp, sizeof (struct vtoc)); 348 libadm_vtoc_copy(extvtoc, oldvtocp); 349 350 #endif 351 return (write_vtoc(fd, &oldvtoc)); 352 353 default: 354 return (VT_ERROR); 355 } 356 } 357 358 return (0); 359 } 360