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