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
read_vtoc(int fd,struct vtoc * vtoc)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
write_vtoc(int fd,struct vtoc * vtoc)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
read_extvtoc(int fd,struct extvtoc * extvtoc)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
write_extvtoc(int fd,struct extvtoc * extvtoc)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