Home | History | Annotate | Download | only in common
      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