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 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2017 The MathWorks, Inc. All rights reserved.
24 */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <ctype.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <sys/param.h>
37 #include <sys/systeminfo.h>
38 #include <sys/efi_partition.h>
39 #include <sys/byteorder.h>
40
41 #include <sys/vtoc.h>
42 #include <sys/tty.h>
43 #include <sys/dktp/fdisk.h>
44 #include <sys/dkio.h>
45 #include <sys/mnttab.h>
46 #include "libfdisk.h"
47
48 #define DEFAULT_PATH_PREFIX "/dev/rdsk/"
49
50 static void fdisk_free_ld_nodes(ext_part_t *epp);
51 static void fdisk_ext_place_in_sorted_list(ext_part_t *epp,
52 logical_drive_t *newld);
53 static void fdisk_ext_remove_from_sorted_list(ext_part_t *epp,
54 logical_drive_t *delld);
55 static int fdisk_ext_overlapping_parts(ext_part_t *epp, uint32_t begsec,
56 uint32_t endsec);
57 static int fdisk_read_extpart(ext_part_t *epp);
58 static void fdisk_set_CHS_values(ext_part_t *epp, struct ipart *part);
59 static int fdisk_init_master_part_table(ext_part_t *epp);
60 static struct ipart *fdisk_alloc_part_table();
61 static int fdisk_read_master_part_table(ext_part_t *epp);
62
63 static int
fdisk_init_disk_geom(ext_part_t * epp)64 fdisk_init_disk_geom(ext_part_t *epp)
65 {
66 struct dk_geom disk_geom;
67 struct dk_minfo disk_info;
68 int no_virtgeom_ioctl = 0, no_physgeom_ioctl = 0;
69
70 /* Get disk's HBA (virtual) geometry */
71 errno = 0;
72 if (ioctl(epp->dev_fd, DKIOCG_VIRTGEOM, &disk_geom)) {
73 if (errno == ENOTTY) {
74 no_virtgeom_ioctl = 1;
75 } else if (errno == EINVAL) {
76 /*
77 * This means that the ioctl exists, but
78 * is invalid for this disk, meaning the
79 * disk doesn't have an HBA geometry
80 * (like, say, it's larger than 8GB).
81 */
82 epp->disk_geom.virt_cyl = epp->disk_geom.virt_heads =
83 epp->disk_geom.virt_sec = 0;
84 } else {
85 return (FDISK_ENOVGEOM);
86 }
87 } else {
88 /* save virtual geometry values obtained by ioctl */
89 epp->disk_geom.virt_cyl = disk_geom.dkg_ncyl;
90 epp->disk_geom.virt_heads = disk_geom.dkg_nhead;
91 epp->disk_geom.virt_sec = disk_geom.dkg_nsect;
92 }
93
94 errno = 0;
95 if (ioctl(epp->dev_fd, DKIOCG_PHYGEOM, &disk_geom)) {
96 if (errno == ENOTTY) {
97 no_physgeom_ioctl = 1;
98 } else {
99 return (FDISK_ENOPGEOM);
100 }
101 }
102 /*
103 * Call DKIOCGGEOM if the ioctls for physical and virtual
104 * geometry fail. Get both from this generic call.
105 */
106 if (no_virtgeom_ioctl && no_physgeom_ioctl) {
107 errno = 0;
108 if (ioctl(epp->dev_fd, DKIOCGGEOM, &disk_geom)) {
109 return (FDISK_ENOLGEOM);
110 }
111 }
112
113 epp->disk_geom.phys_cyl = disk_geom.dkg_ncyl;
114 epp->disk_geom.phys_heads = disk_geom.dkg_nhead;
115 epp->disk_geom.phys_sec = disk_geom.dkg_nsect;
116 epp->disk_geom.alt_cyl = disk_geom.dkg_acyl;
117
118 /*
119 * If DKIOCGMEDIAINFO ioctl succeeds, set the dki_lbsize as the
120 * size of the sector, else default to 512
121 */
122 if (ioctl(epp->dev_fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) < 0) {
123 /* ioctl failed, falling back to default value of 512 bytes */
124 epp->disk_geom.sectsize = 512;
125 } else {
126 epp->disk_geom.sectsize = ((disk_info.dki_lbsize) ?
127 disk_info.dki_lbsize : 512);
128 }
129
130 /*
131 * if hba geometry was not set by DKIOC_VIRTGEOM
132 * or we got an invalid hba geometry
133 * then set hba geometry based on max values
134 */
135 if (no_virtgeom_ioctl || disk_geom.dkg_ncyl == 0 ||
136 disk_geom.dkg_nhead == 0 || disk_geom.dkg_nsect == 0 ||
137 disk_geom.dkg_ncyl > MAX_CYL || disk_geom.dkg_nhead > MAX_HEAD ||
138 disk_geom.dkg_nsect > MAX_SECT) {
139 epp->disk_geom.virt_sec = MAX_SECT;
140 epp->disk_geom.virt_heads = MAX_HEAD + 1;
141 epp->disk_geom.virt_cyl = (epp->disk_geom.phys_cyl *
142 epp->disk_geom.phys_heads * epp->disk_geom.phys_sec) /
143 (epp->disk_geom.virt_sec * epp->disk_geom.virt_heads);
144 }
145 return (FDISK_SUCCESS);
146 }
147
148 /*
149 * Initialise important members of the ext_part_t structure and
150 * other data structures vital to functionality of libfdisk
151 */
152 int
libfdisk_init(ext_part_t ** epp,char * devstr,struct ipart * parttab,int opflag)153 libfdisk_init(ext_part_t **epp, char *devstr, struct ipart *parttab, int opflag)
154 {
155 ext_part_t *temp;
156 struct stat sbuf;
157 int rval = FDISK_SUCCESS;
158 int found_bad_magic = 0;
159
160 if ((temp = calloc(1, sizeof (ext_part_t))) == NULL) {
161 *epp = NULL;
162 return (ENOMEM);
163 }
164
165 (void) strncpy(temp->device_name, devstr,
166 sizeof (temp->device_name));
167
168 /* Try to stat the node as provided */
169 if (stat(temp->device_name, &sbuf) != 0) {
170
171 /* Prefix /dev/rdsk/ and stat again */
172 (void) snprintf(temp->device_name, sizeof (temp->device_name),
173 "%s%s", DEFAULT_PATH_PREFIX, devstr);
174
175 if (stat(temp->device_name, &sbuf) != 0) {
176
177 /*
178 * In case of an EFI labeled disk, the device name
179 * could be cN[tN]dN. There is no pN. So we add "p0"
180 * at the end if we do not find it and stat again.
181 */
182 if (strrchr(temp->device_name, 'p') == NULL) {
183 (void) strcat(temp->device_name, "p0");
184 }
185
186 if (stat(temp->device_name, &sbuf) != 0) {
187
188 /* Failed all options, give up */
189 rval = EINVAL;
190 goto fail;
191 }
192 }
193 }
194
195 /* Make sure the device is a raw device */
196 if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
197 rval = EINVAL;
198 goto fail;
199 }
200
201 temp->ld_head = NULL;
202 temp->sorted_ld_head = NULL;
203
204 if ((temp->dev_fd = open(temp->device_name, O_RDWR, 0666)) < 0) {
205 rval = EINVAL;
206 goto fail;
207 }
208
209 if ((temp->mtable = parttab) == NULL) {
210 if ((rval = fdisk_init_master_part_table(temp)) !=
211 FDISK_SUCCESS) {
212 /*
213 * When we have no fdisk magic 0xAA55 on the disk,
214 * we return FDISK_EBADMAGIC after successfully
215 * obtaining the disk geometry.
216 */
217 if (rval != FDISK_EBADMAGIC)
218 goto fail;
219 else
220 found_bad_magic = 1;
221 }
222 }
223
224 temp->op_flag = opflag;
225
226 if ((rval = fdisk_init_disk_geom(temp)) != FDISK_SUCCESS) {
227 goto fail;
228 }
229
230 *epp = temp;
231
232 if (found_bad_magic != 0) {
233 return (FDISK_EBADMAGIC);
234 }
235
236 if (opflag & FDISK_READ_DISK) {
237 rval = fdisk_read_extpart(*epp);
238 }
239 return (rval);
240
241 fail:
242 *epp = NULL;
243 free(temp);
244 return (rval);
245 }
246
247 int
libfdisk_reset(ext_part_t * epp)248 libfdisk_reset(ext_part_t *epp)
249 {
250 int rval = FDISK_SUCCESS;
251
252 fdisk_free_ld_nodes(epp);
253 epp->first_ebr_is_null = 1;
254 epp->corrupt_logical_drives = 0;
255 epp->logical_drive_count = 0;
256 epp->invalid_bb_sig[0] = 0;
257 if (epp->op_flag & FDISK_READ_DISK) {
258 rval = fdisk_read_extpart(epp);
259 }
260 return (rval);
261 }
262
263 void
libfdisk_fini(ext_part_t ** epp)264 libfdisk_fini(ext_part_t **epp)
265 {
266 if (*epp == NULL)
267 return;
268
269 fdisk_free_ld_nodes(*epp);
270 (void) close((*epp)->dev_fd);
271 free(*epp);
272 *epp = NULL;
273 }
274
275 int
fdisk_is_linux_swap(ext_part_t * epp,uint32_t part_start,uint64_t * lsm_offset)276 fdisk_is_linux_swap(ext_part_t *epp, uint32_t part_start, uint64_t *lsm_offset)
277 {
278 int i;
279 int rval = -1;
280 off_t seek_offset;
281 uint32_t linux_pg_size;
282 char *buf, *linux_swap_magic;
283 int sec_sz = fdisk_get_disk_geom(epp, PHYSGEOM, SSIZE);
284 off_t label_offset;
285
286 /*
287 * Known linux kernel page sizes
288 * The linux swap magic is found as the last 10 bytes of a disk chunk
289 * at the beginning of the linux swap partition whose size is that of
290 * kernel page size.
291 */
292 uint32_t linux_pg_size_arr[] = {4096, };
293
294 if ((buf = calloc(1, sec_sz)) == NULL) {
295 return (ENOMEM);
296 }
297
298 /*
299 * Check if there is a sane Solaris VTOC
300 * If there is a valid vtoc, no need to lookup
301 * for the linux swap signature.
302 */
303 label_offset = (part_start + DK_LABEL_LOC) * sec_sz;
304 if (lseek(epp->dev_fd, label_offset, SEEK_SET) < 0) {
305 rval = EIO;
306 goto done;
307 }
308
309 if ((rval = read(epp->dev_fd, buf, sec_sz)) < sec_sz) {
310 rval = EIO;
311 goto done;
312 }
313
314
315 if ((((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) &&
316 (((struct dk_label *)buf)->dkl_vtoc.v_sanity == VTOC_SANE)) {
317 rval = -1;
318 goto done;
319 }
320
321 /* No valid vtoc, so check for linux swap signature */
322 linux_swap_magic = buf + sec_sz - LINUX_SWAP_MAGIC_LENGTH;
323
324 for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
325 linux_pg_size = linux_pg_size_arr[i];
326 seek_offset = linux_pg_size/sec_sz - 1;
327 seek_offset += part_start;
328 seek_offset *= sec_sz;
329
330 if (lseek(epp->dev_fd, seek_offset, SEEK_SET) < 0) {
331 rval = EIO;
332 break;
333 }
334
335 if ((rval = read(epp->dev_fd, buf, sec_sz)) < sec_sz) {
336 rval = EIO;
337 break;
338 }
339
340 if ((strncmp(linux_swap_magic, "SWAP-SPACE",
341 LINUX_SWAP_MAGIC_LENGTH) == 0) ||
342 (strncmp(linux_swap_magic, "SWAPSPACE2",
343 LINUX_SWAP_MAGIC_LENGTH) == 0)) {
344 /* Found a linux swap */
345 rval = 0;
346 if (lsm_offset != NULL)
347 *lsm_offset = (uint64_t)seek_offset;
348 break;
349 }
350 }
351
352 done:
353 free(buf);
354 return (rval);
355 }
356
357 int
fdisk_get_solaris_part(ext_part_t * epp,int * pnum,uint32_t * begsec,uint32_t * numsec)358 fdisk_get_solaris_part(ext_part_t *epp, int *pnum, uint32_t *begsec,
359 uint32_t *numsec)
360 {
361 logical_drive_t *temp = fdisk_get_ld_head(epp);
362 uint32_t part_start;
363 int pno;
364 int rval = -1;
365
366 for (pno = 5; temp != NULL; temp = temp->next, pno++) {
367 if (fdisk_is_solaris_part(LE_8(temp->parts[0].systid))) {
368 part_start = temp->abs_secnum + temp->logdrive_offset;
369 if ((temp->parts[0].systid == SUNIXOS) &&
370 (fdisk_is_linux_swap(epp, part_start,
371 NULL) == 0)) {
372 continue;
373 }
374 *pnum = pno;
375 *begsec = part_start;
376 *numsec = temp->numsect;
377 rval = FDISK_SUCCESS;
378 }
379 }
380 return (rval);
381 }
382
383 int
fdisk_get_part_info(ext_part_t * epp,int pnum,uchar_t * sysid,uint32_t * begsec,uint32_t * numsec)384 fdisk_get_part_info(ext_part_t *epp, int pnum, uchar_t *sysid, uint32_t *begsec,
385 uint32_t *numsec)
386 {
387 logical_drive_t *temp = fdisk_get_ld_head(epp);
388 int pno;
389
390 if ((pnum < 5) || (pnum >= MAX_EXT_PARTS + 5)) {
391 return (EINVAL);
392 }
393
394 for (pno = 5; (pno < pnum) && (temp != NULL); temp = temp->next, pno++)
395 ;
396
397 if (temp == NULL) {
398 return (EINVAL);
399 }
400
401 *sysid = LE_8(temp->parts[0].systid);
402 *begsec = temp->abs_secnum + temp->logdrive_offset;
403 *numsec = temp->numsect;
404 return (FDISK_SUCCESS);
405 }
406
407 /*
408 * Allocate a node of type logical_drive_t and return the pointer to it
409 */
410 static logical_drive_t *
fdisk_alloc_ld_node()411 fdisk_alloc_ld_node()
412 {
413 logical_drive_t *temp;
414
415 if ((temp = calloc(1, sizeof (logical_drive_t))) == NULL) {
416 return (NULL);
417 }
418 temp->next = NULL;
419 return (temp);
420 }
421
422 /*
423 * Free all the logical_drive_t's allocated during the run
424 */
425 static void
fdisk_free_ld_nodes(ext_part_t * epp)426 fdisk_free_ld_nodes(ext_part_t *epp)
427 {
428 logical_drive_t *temp;
429
430 for (temp = epp->ld_head; temp != NULL; ) {
431 temp = epp->ld_head -> next;
432 free(epp->ld_head);
433 epp->ld_head = temp;
434 }
435 epp->ld_head = NULL;
436 epp->sorted_ld_head = NULL;
437 }
438
439 /*
440 * Find the first free sector within the extended partition
441 */
442 int
fdisk_ext_find_first_free_sec(ext_part_t * epp,uint32_t * first_free_sec)443 fdisk_ext_find_first_free_sec(ext_part_t *epp, uint32_t *first_free_sec)
444 {
445 logical_drive_t *temp;
446 uint32_t last_free_sec;
447
448 *first_free_sec = epp->ext_beg_sec;
449
450 if (epp->ld_head == NULL) {
451 return (FDISK_SUCCESS);
452 }
453
454 /*
455 * When the first logical drive is out of order, we need to adjust
456 * first_free_sec accordingly. In this case, the first extended
457 * partition sector is not free even though the actual logical drive
458 * does not occupy space from the beginning of the extended partition.
459 * The next free sector would be the second sector of the extended
460 * partition.
461 */
462 if (epp->ld_head->abs_secnum > epp->ext_beg_sec +
463 MAX_LOGDRIVE_OFFSET) {
464 (*first_free_sec)++;
465 }
466
467 while (*first_free_sec <= epp->ext_end_sec) {
468 for (temp = epp->sorted_ld_head; temp != NULL; temp =
469 temp->sorted_next) {
470 if (temp->abs_secnum == *first_free_sec) {
471 *first_free_sec = temp->abs_secnum +
472 temp->logdrive_offset + temp->numsect;
473 }
474 }
475
476 last_free_sec = fdisk_ext_find_last_free_sec(epp,
477 *first_free_sec);
478
479 if ((last_free_sec - *first_free_sec) < MAX_LOGDRIVE_OFFSET) {
480 /*
481 * Minimum size of a partition assumed to be atleast one
482 * sector.
483 */
484 *first_free_sec = last_free_sec + 1;
485 continue;
486 }
487
488 break;
489 }
490
491 if (*first_free_sec > epp->ext_end_sec) {
492 return (FDISK_EOOBOUND);
493 }
494
495 return (FDISK_SUCCESS);
496 }
497
498 /*
499 * Find the last free sector within the extended partition given, a beginning
500 * sector (so that the range - "begsec to last_free_sec" is contiguous)
501 */
502 uint32_t
fdisk_ext_find_last_free_sec(ext_part_t * epp,uint32_t begsec)503 fdisk_ext_find_last_free_sec(ext_part_t *epp, uint32_t begsec)
504 {
505 logical_drive_t *temp;
506 uint32_t last_free_sec;
507
508 last_free_sec = epp->ext_end_sec;
509 for (temp = epp->sorted_ld_head; temp != NULL;
510 temp = temp->sorted_next) {
511 if (temp->abs_secnum > begsec) {
512 last_free_sec = temp->abs_secnum - 1;
513 break;
514 }
515 }
516 return (last_free_sec);
517 }
518
519 /*
520 * Place the given ext_part_t structure in a sorted list, sorted in the
521 * ascending order of their beginning sectors.
522 */
523 static void
fdisk_ext_place_in_sorted_list(ext_part_t * epp,logical_drive_t * newld)524 fdisk_ext_place_in_sorted_list(ext_part_t *epp, logical_drive_t *newld)
525 {
526 logical_drive_t *pre, *cur;
527
528 if (newld->abs_secnum < epp->sorted_ld_head->abs_secnum) {
529 newld->sorted_next = epp->sorted_ld_head;
530 epp->sorted_ld_head = newld;
531 return;
532 }
533 pre = cur = epp->sorted_ld_head;
534
535 for (; cur != NULL; pre = cur, cur = cur->sorted_next) {
536 if (newld->abs_secnum < cur->abs_secnum) {
537 break;
538 }
539 }
540
541 newld->sorted_next = cur;
542 pre->sorted_next = newld;
543 }
544
545 static void
fdisk_ext_remove_from_sorted_list(ext_part_t * epp,logical_drive_t * delld)546 fdisk_ext_remove_from_sorted_list(ext_part_t *epp, logical_drive_t *delld)
547 {
548 logical_drive_t *pre, *cur;
549
550 if (delld == epp->sorted_ld_head) {
551 epp->sorted_ld_head = delld->sorted_next;
552 return;
553 }
554
555 pre = cur = epp->sorted_ld_head;
556
557 for (; cur != NULL; pre = cur, cur = cur->sorted_next) {
558 if (cur->abs_secnum == delld->abs_secnum) {
559 /* Found */
560 break;
561 }
562 }
563
564 pre->sorted_next = cur->sorted_next;
565 }
566
567 static int
fdisk_ext_overlapping_parts(ext_part_t * epp,uint32_t begsec,uint32_t endsec)568 fdisk_ext_overlapping_parts(ext_part_t *epp, uint32_t begsec, uint32_t endsec)
569 {
570 logical_drive_t *temp;
571 uint32_t firstsec, lastsec, last_free_sec;
572
573 for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
574 firstsec = temp->abs_secnum;
575 lastsec = firstsec + temp->logdrive_offset + temp->numsect - 1;
576 if ((begsec >= firstsec) &&
577 (begsec <= lastsec)) {
578 return (1);
579 }
580 }
581
582 /*
583 * Find the maximum possible end sector value
584 * given a beginning sector value
585 */
586 last_free_sec = fdisk_ext_find_last_free_sec(epp, begsec);
587
588 if (endsec > last_free_sec) {
589 return (1);
590 }
591 return (0);
592 }
593
594 /*
595 * Check if the logical drive boundaries are sane
596 */
597 int
fdisk_validate_logical_drive(ext_part_t * epp,uint32_t begsec,uint32_t offset,uint32_t numsec)598 fdisk_validate_logical_drive(ext_part_t *epp, uint32_t begsec,
599 uint32_t offset, uint32_t numsec)
600 {
601 uint32_t endsec;
602
603 endsec = begsec + offset + numsec - 1;
604 if (begsec < epp->ext_beg_sec ||
605 begsec > epp->ext_end_sec ||
606 endsec < epp->ext_beg_sec ||
607 endsec > epp->ext_end_sec ||
608 endsec < begsec ||
609 fdisk_ext_overlapping_parts(epp, begsec, endsec)) {
610 return (1);
611 }
612
613 return (0);
614 }
615
616 /*
617 * Procedure to walk through the extended partitions and build a Singly
618 * Linked List out of the data.
619 */
620 static int
fdisk_read_extpart(ext_part_t * epp)621 fdisk_read_extpart(ext_part_t *epp)
622 {
623 struct ipart *fdp, *ext_fdp;
624 int i = 0, j = 0, ext_part_found = 0, lpart = 5;
625 off_t secnum, offset;
626 logical_drive_t *temp, *ep_ptr;
627 unsigned char *ext_buf;
628 int sectsize = epp->disk_geom.sectsize;
629
630 if ((ext_buf = (uchar_t *)malloc(sectsize)) == NULL) {
631 return (ENOMEM);
632 }
633 fdp = epp->mtable;
634
635 for (i = 0; (i < FD_NUMPART) && (!ext_part_found); i++, fdp++) {
636 if (fdisk_is_dos_extended(LE_8(fdp->systid))) {
637 ext_part_found = 1;
638 secnum = LE_32(fdp->relsect);
639 offset = secnum * sectsize;
640 epp->ext_beg_sec = secnum;
641 epp->ext_end_sec = secnum + LE_32(fdp->numsect) - 1;
642 epp->ext_beg_cyl =
643 FDISK_SECT_TO_CYL(epp, epp->ext_beg_sec);
644 epp->ext_end_cyl =
645 FDISK_SECT_TO_CYL(epp, epp->ext_end_sec);
646
647 /*LINTED*/
648 while (B_TRUE) {
649 if (lseek(epp->dev_fd, offset, SEEK_SET) < 0) {
650 return (EIO);
651 }
652 if (read(epp->dev_fd, ext_buf, sectsize) <
653 sectsize) {
654 return (EIO);
655 }
656 /*LINTED*/
657 ext_fdp = (struct ipart *)
658 (&ext_buf[FDISK_PART_TABLE_START]);
659 if ((LE_32(ext_fdp->relsect) == 0) &&
660 (epp->logical_drive_count == 0)) {
661 /* No logical drives defined */
662 epp->first_ebr_is_null = 0;
663 return (FDISK_ENOLOGDRIVE);
664 }
665
666 temp = fdisk_alloc_ld_node();
667 temp->abs_secnum = secnum;
668 temp->logdrive_offset =
669 LE_32(ext_fdp->relsect);
670 temp ->numsect = LE_32(ext_fdp->numsect);
671 if (epp->ld_head == NULL) {
672 /* adding first logical drive */
673 if (temp->logdrive_offset >
674 MAX_LOGDRIVE_OFFSET) {
675 /* out of order */
676 temp->abs_secnum +=
677 temp->logdrive_offset;
678 temp->logdrive_offset = 0;
679 }
680 }
681 temp->begcyl =
682 FDISK_SECT_TO_CYL(epp, temp->abs_secnum);
683 temp->endcyl = FDISK_SECT_TO_CYL(epp,
684 temp->abs_secnum +
685 temp->logdrive_offset +
686 temp->numsect - 1);
687
688 /*
689 * Check for sanity of logical drives
690 */
691 if (fdisk_validate_logical_drive(epp,
692 temp->abs_secnum, temp->logdrive_offset,
693 temp->numsect)) {
694 epp->corrupt_logical_drives = 1;
695 free(temp);
696 return (FDISK_EBADLOGDRIVE);
697 }
698
699 temp->parts[0] = *ext_fdp;
700 ext_fdp++;
701 temp->parts[1] = *ext_fdp;
702
703 if (epp->ld_head == NULL) {
704 epp->ld_head = temp;
705 epp->sorted_ld_head = temp;
706 ep_ptr = temp;
707 epp->logical_drive_count = 1;
708 } else {
709 ep_ptr->next = temp;
710 ep_ptr = temp;
711 fdisk_ext_place_in_sorted_list(epp,
712 temp);
713 epp->logical_drive_count++;
714 }
715
716 /*LINTED*/
717 if (LE_16((*(uint16_t *)&ext_buf[510])) !=
718 MBB_MAGIC) {
719 epp->invalid_bb_sig[j++] = lpart;
720 temp->modified = FDISK_MINOR_WRITE;
721 }
722
723 if (LE_32(ext_fdp->relsect) == 0)
724 break;
725 else {
726 secnum = LE_32(fdp->relsect) +
727 LE_32(ext_fdp->relsect);
728 offset = secnum * sectsize;
729 }
730 lpart++;
731 }
732 }
733 }
734 return (FDISK_SUCCESS);
735 }
736
737 static int
fdisk_init_master_part_table(ext_part_t * epp)738 fdisk_init_master_part_table(ext_part_t *epp)
739 {
740 int rval;
741 if ((epp->mtable = fdisk_alloc_part_table()) == NULL) {
742 return (ENOMEM);
743 }
744 rval = fdisk_read_master_part_table(epp);
745 if (rval) {
746 return (rval);
747 }
748 return (FDISK_SUCCESS);
749 }
750
751 static struct ipart *
fdisk_alloc_part_table()752 fdisk_alloc_part_table()
753 {
754 int size = sizeof (struct ipart);
755 struct ipart *table;
756
757 if ((table = calloc(4, size)) == NULL) {
758 return (NULL);
759 }
760
761 return (table);
762 }
763
764 /*
765 * Reads the master fdisk partition table from the device assuming that it has
766 * a valid table.
767 * MBR is supposed to be of 512 bytes no matter what the device block size is.
768 */
769 static int
fdisk_read_master_part_table(ext_part_t * epp)770 fdisk_read_master_part_table(ext_part_t *epp)
771 {
772 struct dk_minfo_ext dkmp_ext;
773 struct dk_minfo dkmp;
774 uchar_t *buf;
775 int sectsize;
776 int size = sizeof (struct ipart);
777 int cpcnt = FD_NUMPART * size;
778
779 if (lseek(epp->dev_fd, 0, SEEK_SET) < 0) {
780 return (EIO);
781 }
782 if (ioctl(epp->dev_fd, DKIOCGMEDIAINFOEXT, &dkmp_ext) < 0) {
783 if (ioctl(epp->dev_fd, DKIOCGMEDIAINFO, &dkmp) < 0) {
784 return (EIO);
785 }
786 sectsize = dkmp.dki_lbsize;
787 } else {
788 sectsize = dkmp_ext.dki_lbsize;
789 }
790 if (sectsize < 512) {
791 return (EIO);
792 }
793 buf = calloc(sectsize, sizeof (uchar_t));
794 if (buf == NULL) {
795 return (ENOMEM);
796 }
797 if (read(epp->dev_fd, buf, sectsize) < sectsize) {
798 free(buf);
799 return (EIO);
800 }
801
802 /*LINTED*/
803 if (LE_16((*(uint16_t *)&buf[510])) != MBB_MAGIC) {
804 bzero(epp->mtable, cpcnt);
805 free(buf);
806 return (FDISK_EBADMAGIC);
807 }
808
809 bcopy(&buf[FDISK_PART_TABLE_START], epp->mtable, cpcnt);
810 free(buf);
811
812 return (FDISK_SUCCESS);
813 }
814
815 int
fdisk_ext_part_exists(ext_part_t * epp)816 fdisk_ext_part_exists(ext_part_t *epp)
817 {
818 int i;
819 struct ipart *part_table = epp->mtable;
820
821 if (part_table == NULL) {
822 /* No extended partition found */
823 return (0);
824 }
825
826 for (i = 0; i < FD_NUMPART; i++) {
827 if (fdisk_is_dos_extended(LE_8(part_table[i].systid))) {
828 break;
829 }
830 }
831
832 if (i == FD_NUMPART) {
833 /* No extended partition found */
834 return (0);
835 }
836 return (1);
837 }
838
839 int
fdisk_ext_validate_part_start(ext_part_t * epp,uint32_t begcyl,uint32_t * begsec)840 fdisk_ext_validate_part_start(ext_part_t *epp, uint32_t begcyl,
841 uint32_t *begsec)
842 {
843 logical_drive_t *temp;
844 uint32_t first_free_sec;
845 uint32_t first_free_cyl;
846 int rval;
847
848 rval = fdisk_ext_find_first_free_sec(epp, &first_free_sec);
849 if (rval != FDISK_SUCCESS) {
850 return (rval);
851 }
852
853 first_free_cyl = FDISK_SECT_TO_CYL(epp, first_free_sec);
854 if (begcyl == first_free_cyl) {
855 *begsec = first_free_sec;
856 return (FDISK_SUCCESS);
857 }
858
859 /* Check if the cylinder number is beyond the extended partition */
860 if ((begcyl < epp->ext_beg_cyl) || (begcyl > epp->ext_end_cyl)) {
861 return (FDISK_EOOBOUND);
862 }
863
864 for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
865 if ((begcyl >= temp->begcyl) &&
866 (begcyl <= temp->endcyl)) {
867 return (FDISK_EOVERLAP);
868 }
869 }
870 *begsec = FDISK_CYL_TO_SECT(epp, begcyl);
871
872 return (FDISK_SUCCESS);
873 }
874
875 void
fdisk_change_logical_drive_id(ext_part_t * epp,int pno,uchar_t partid)876 fdisk_change_logical_drive_id(ext_part_t *epp, int pno, uchar_t partid)
877 {
878 logical_drive_t *temp;
879 int i;
880
881 i = FD_NUMPART + 1;
882 for (temp = epp->ld_head; i < pno; temp = temp->next, i++)
883 ;
884
885 temp->parts[0].systid = LE_8(partid);
886 temp->modified = FDISK_MAJOR_WRITE;
887 }
888
889 /*
890 * A couple of special scenarios :
891 * 1. Since the first logical drive's EBR is always at the beginning of the
892 * extended partition, any specification that starts the first logical drive
893 * out of order will need to address the following issue :
894 * If the beginning of the drive is not coinciding with the beginning of the
895 * extended partition and :
896 * a) The start is within MAX_LOGDRIVE_OFFSET, the offset changes from the
897 * default of 63 to less than 63.
898 * logdrive_offset is updated to keep track of the space between
899 * the beginning of the logical drive and extended partition. abs_secnum
900 * points to the beginning of the extended partition.
901 * b) The start is greater than MAX_LOGDRIVE_OFFSET, the offset changes from
902 * the default of 63 to greater than 63.
903 * logdrive_offset is set to 0. abs_secnum points to the beginning of the
904 * logical drive, which is at an offset from the extended partition.
905 */
906 void
fdisk_add_logical_drive(ext_part_t * epp,uint32_t begsec,uint32_t endsec,uchar_t partid)907 fdisk_add_logical_drive(ext_part_t *epp, uint32_t begsec, uint32_t endsec,
908 uchar_t partid)
909 {
910 logical_drive_t *temp, *pre, *cur;
911 struct ipart *part;
912
913 temp = fdisk_alloc_ld_node();
914 temp->abs_secnum = begsec;
915 temp->logdrive_offset = MAX_LOGDRIVE_OFFSET;
916 temp->numsect = endsec - begsec + 1 - MAX_LOGDRIVE_OFFSET;
917 temp->begcyl = FDISK_SECT_TO_CYL(epp, begsec);
918 temp->endcyl = FDISK_SECT_TO_CYL(epp, endsec);
919 temp->modified = FDISK_MAJOR_WRITE;
920
921 part = &temp->parts[0];
922 part->bootid = 0;
923 part->systid = LE_8(partid);
924 part->relsect = MAX_LOGDRIVE_OFFSET;
925 part->numsect = LE_32(temp->numsect);
926
927 fdisk_set_CHS_values(epp, part);
928
929 if (epp->ld_head == NULL) {
930 epp->corrupt_logical_drives = 0;
931 if (begsec != epp->ext_beg_sec) {
932 part->relsect = LE_32(begsec - epp->ext_beg_sec);
933 temp->numsect = endsec - begsec + 1;
934 part->numsect = LE_32(temp->numsect);
935 if (LE_32(part->relsect) > MAX_LOGDRIVE_OFFSET) {
936 temp->logdrive_offset = 0;
937 } else {
938 temp->abs_secnum = epp->ext_beg_sec;
939 temp->logdrive_offset = LE_32(part->relsect);
940 }
941 }
942 epp->first_ebr_is_null = 0;
943 epp->ld_head = temp;
944 epp->sorted_ld_head = temp;
945 epp->logical_drive_count = 1;
946 return;
947 }
948
949 if (temp->abs_secnum == epp->ext_beg_sec) {
950 part->relsect = LE_32(LE_32(part->relsect) - 1);
951 temp->logdrive_offset--;
952 temp->abs_secnum++;
953 }
954
955 for (pre = cur = epp->ld_head; cur != NULL; pre = cur, cur = cur->next)
956 ;
957
958 part = &pre->parts[1];
959 part->bootid = 0;
960 part->systid = LE_8(EXTDOS);
961 part->relsect = LE_32(temp->abs_secnum - epp->ext_beg_sec);
962 part->numsect = LE_32(temp->numsect + temp->logdrive_offset);
963
964 fdisk_set_CHS_values(epp, part);
965
966 pre->next = temp;
967 pre->modified = FDISK_MAJOR_WRITE;
968 epp->logical_drive_count++;
969 fdisk_ext_place_in_sorted_list(epp, temp);
970 }
971
972 /*
973 * There are 2 cases that need to be handled.
974 * 1. Deleting the first extended partition :
975 * The peculiarity of this case is that the offset of the first extended
976 * partition is always indicated by the entry in the master boot record.
977 * (MBR). This never changes, unless the extended partition itself is
978 * deleted. Hence, the location of the first EBR is fixed.
979 * It is only the logical drive which is deleted. This first EBR now gives
980 * information of the next logical drive and the info about the subsequent
981 * extended partition. Hence the "relsect" of the first EBR is modified to
982 * point to the next logical drive.
983 *
984 * 2. Deleting an intermediate extended partition.
985 * This is quite normal and follows the semantics of a normal linked list
986 * delete operation. The node being deleted has the information about the
987 * logical drive that it houses and the location and the size of the next
988 * extended partition. This informationis transferred to the node previous
989 * to the node being deleted.
990 *
991 */
992
993 void
fdisk_delete_logical_drive(ext_part_t * epp,int pno)994 fdisk_delete_logical_drive(ext_part_t *epp, int pno)
995 {
996 logical_drive_t *pre, *cur;
997 int i;
998
999 i = FD_NUMPART + 1;
1000 pre = cur = epp->ld_head;
1001 for (; i < pno; i++) {
1002 pre = cur;
1003 cur = cur->next;
1004 }
1005
1006 if (cur == epp->ld_head) {
1007 /* Deleting the first logical drive */
1008 if (cur->next == NULL) {
1009 /* Deleting the only logical drive left */
1010 free(cur);
1011 epp->ld_head = NULL;
1012 epp->sorted_ld_head = NULL;
1013 epp->logical_drive_count = 0;
1014 epp->first_ebr_is_null = 1;
1015 } else {
1016 pre = epp->ld_head;
1017 cur = pre->next;
1018 cur->parts[0].relsect =
1019 LE_32(LE_32(cur->parts[0].relsect) +
1020 LE_32(pre->parts[1].relsect));
1021 /* Corner case when partitions are out of order */
1022 if ((pre->abs_secnum != epp->ext_beg_sec) &&
1023 (cur->abs_secnum == epp->ext_beg_sec + 1)) {
1024 cur->logdrive_offset++;
1025 cur->abs_secnum = epp->ext_beg_sec;
1026 } else {
1027 cur->abs_secnum = LE_32(cur->parts[0].relsect) +
1028 epp->ext_beg_sec;
1029 cur->logdrive_offset = 0;
1030 }
1031 fdisk_ext_remove_from_sorted_list(epp, pre);
1032 epp->ld_head = cur;
1033 epp->ld_head->modified = FDISK_MAJOR_WRITE;
1034 epp->logical_drive_count--;
1035 free(pre);
1036 }
1037 } else {
1038 pre->parts[1] = cur->parts[1];
1039 pre->next = cur->next;
1040 fdisk_ext_remove_from_sorted_list(epp, cur);
1041 pre->modified = FDISK_MAJOR_WRITE;
1042 free(cur);
1043 epp->logical_drive_count--;
1044 }
1045 }
1046
1047 static void
fdisk_set_CHS_values(ext_part_t * epp,struct ipart * part)1048 fdisk_set_CHS_values(ext_part_t *epp, struct ipart *part)
1049 {
1050 uint32_t lba, cy, hd, sc;
1051 uint32_t sectors = epp->disk_geom.virt_sec;
1052 uint32_t heads = epp->disk_geom.virt_heads;
1053
1054 lba = LE_32(part->relsect) + epp->ext_beg_sec;
1055 if (lba >= heads * sectors * MAX_CYL) {
1056 /*
1057 * the lba address cannot be expressed in CHS value
1058 * so store the maximum CHS field values in the CHS fields.
1059 */
1060 cy = MAX_CYL + 1;
1061 hd = MAX_HEAD;
1062 sc = MAX_SECT;
1063 } else {
1064 cy = lba / sectors / heads;
1065 hd = lba / sectors % heads;
1066 sc = lba % sectors + 1;
1067 }
1068
1069 part->begcyl = cy & 0xff;
1070 part->beghead = (uchar_t)hd;
1071 part->begsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
1072
1073 /*
1074 * This code is identical to the code above
1075 * except that it works on ending CHS values
1076 */
1077 lba += LE_32(part->numsect - 1);
1078 if (lba >= heads * sectors * MAX_CYL) {
1079 cy = MAX_CYL + 1;
1080 hd = MAX_HEAD;
1081 sc = MAX_SECT;
1082 } else {
1083 cy = lba / sectors / heads;
1084 hd = lba / sectors % heads;
1085 sc = lba % sectors + 1;
1086 }
1087 part->endcyl = cy & 0xff;
1088 part->endhead = (uchar_t)hd;
1089 part->endsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
1090 }
1091
1092 static int
read_modify_write_ebr(ext_part_t * epp,unsigned char * ebr_buf,struct ipart * ebr_tab,uint32_t sec_offset)1093 read_modify_write_ebr(ext_part_t *epp, unsigned char *ebr_buf,
1094 struct ipart *ebr_tab, uint32_t sec_offset)
1095 {
1096 off_t seek_offset;
1097 int sectsize = epp->disk_geom.sectsize;
1098
1099 seek_offset = (off_t)sec_offset * sectsize;
1100
1101 if (lseek(epp->dev_fd, seek_offset, SEEK_SET) < 0) {
1102 return (EIO);
1103 }
1104 if (read(epp->dev_fd, ebr_buf, sectsize) < sectsize) {
1105 return (EIO);
1106 }
1107
1108 bzero(&ebr_buf[FDISK_PART_TABLE_START], 4 * sizeof (struct ipart));
1109 if (ebr_tab != NULL) {
1110 bcopy(ebr_tab, &ebr_buf[FDISK_PART_TABLE_START],
1111 2 * sizeof (struct ipart));
1112 }
1113 ebr_buf[510] = 0x55;
1114 ebr_buf[511] = 0xAA;
1115 if (lseek(epp->dev_fd, seek_offset, SEEK_SET) < 0) {
1116 return (EIO);
1117 }
1118 if (write(epp->dev_fd, ebr_buf, sectsize) < sectsize) {
1119 return (EIO);
1120 }
1121 return (0);
1122 }
1123
1124 /*
1125 * XXX - ZFS mounts not detected. Needs to come in as a feature.
1126 * Currently only /etc/mnttab entries are being checked
1127 */
1128 int
fdisk_mounted_logical_drives(ext_part_t * epp)1129 fdisk_mounted_logical_drives(ext_part_t *epp)
1130 {
1131 char *part_str, *canonp;
1132 char compare_pdev_str[PATH_MAX];
1133 char compare_sdev_str[PATH_MAX];
1134 FILE *fp;
1135 struct mnttab mt;
1136 int part;
1137 int look_for_mounted_slices = 0;
1138 uint32_t begsec, numsec;
1139
1140 /*
1141 * Do not check for mounted logical drives for
1142 * devices other than /dev/rdsk/
1143 */
1144 if (strstr(epp->device_name, DEFAULT_PATH_PREFIX) == NULL) {
1145 return (0);
1146 }
1147
1148 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1149 return (ENOENT);
1150 }
1151
1152 canonp = epp->device_name + strlen(DEFAULT_PATH_PREFIX);
1153 (void) snprintf(compare_pdev_str, PATH_MAX, "%s%s", "/dev/dsk/",
1154 canonp);
1155 part_str = strrchr(compare_pdev_str, 'p');
1156 *(part_str + 1) = '\0';
1157 (void) strcpy(compare_sdev_str, compare_pdev_str);
1158 part_str = strrchr(compare_sdev_str, 'p');
1159 *part_str = 's';
1160
1161 if (fdisk_get_solaris_part(epp, &part, &begsec, &numsec) ==
1162 FDISK_SUCCESS) {
1163 if (part > FD_NUMPART) {
1164 /*
1165 * Solaris partition is on a logical drive. Look for
1166 * mounted slices.
1167 */
1168 look_for_mounted_slices = 1;
1169 }
1170 }
1171
1172 while (getmntent(fp, &mt) == 0) {
1173 if (strstr(mt.mnt_special, compare_pdev_str) == NULL) {
1174 if (strstr(mt.mnt_special, compare_sdev_str) == NULL) {
1175 continue;
1176 } else {
1177 if (look_for_mounted_slices) {
1178 return (FDISK_EMOUNTED);
1179 }
1180 }
1181 }
1182
1183 /*
1184 * Get the partition number that is mounted, which would be
1185 * found just beyond the last 'p' in the device string.
1186 * For example, in /dev/dsk/c0t0d0p12, partition number 12
1187 * is just beyond the last 'p'.
1188 */
1189 part_str = strrchr(mt.mnt_special, 'p');
1190 if (part_str != NULL) {
1191 part_str++;
1192 part = atoi(part_str);
1193 /* Extended partition numbers start from 5 */
1194 if (part >= 5) {
1195 return (FDISK_EMOUNTED);
1196 }
1197 }
1198 }
1199 return (0);
1200 }
1201
1202 int
fdisk_commit_ext_part(ext_part_t * epp)1203 fdisk_commit_ext_part(ext_part_t *epp)
1204 {
1205 logical_drive_t *temp;
1206 int wflag = 0; /* write flag */
1207 int rval;
1208 int sectsize = epp->disk_geom.sectsize;
1209 unsigned char *ebr_buf;
1210 int ld_count;
1211 uint32_t abs_secnum;
1212 int check_mounts = 0;
1213
1214 if ((ebr_buf = (unsigned char *)malloc(sectsize)) == NULL) {
1215 return (ENOMEM);
1216 }
1217
1218 if (epp->first_ebr_is_null) {
1219 /*
1220 * Indicator that the extended partition as a whole was
1221 * modifies (either created or deleted. Must check for mounts
1222 * and must commit
1223 */
1224 check_mounts = 1;
1225 }
1226
1227 /*
1228 * Pass1 through the logical drives to make sure that commit of minor
1229 * written block dont get held up due to mounts.
1230 */
1231 for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
1232 if (temp == epp->ld_head) {
1233 abs_secnum = epp->ext_beg_sec;
1234 } else {
1235 abs_secnum = temp->abs_secnum;
1236 }
1237 if (temp->modified == FDISK_MINOR_WRITE) {
1238 rval = read_modify_write_ebr(epp, ebr_buf,
1239 temp->parts, abs_secnum);
1240 if (rval) {
1241 goto error;
1242 }
1243 temp->modified = 0;
1244 } else if (temp->modified == FDISK_MAJOR_WRITE) {
1245 check_mounts = 1;
1246 }
1247 }
1248
1249 if (!check_mounts) {
1250 goto skip_check_mounts;
1251 }
1252
1253 if ((rval = fdisk_mounted_logical_drives(epp)) != 0) {
1254 /* One/more extended partitions are mounted */
1255 if (ebr_buf) {
1256 free(ebr_buf);
1257 }
1258 return (rval);
1259 }
1260
1261 skip_check_mounts:
1262
1263 if (epp->first_ebr_is_null) {
1264 rval = read_modify_write_ebr(epp, ebr_buf, NULL,
1265 epp->ext_beg_sec);
1266 if (rval) {
1267 goto error;
1268 }
1269 wflag = 1;
1270 ld_count = 0;
1271 } else {
1272 if (epp->logical_drive_count == 0) {
1273 /*
1274 * Can hit this case when there is just an extended
1275 * partition with no logical drives, and the user
1276 * committed without making any changes
1277 * We dont have anything to commit. Return success
1278 */
1279 if (ebr_buf) {
1280 free(ebr_buf);
1281 }
1282 return (FDISK_SUCCESS);
1283 }
1284
1285 /*
1286 * Make sure that the first EBR is written with the first
1287 * logical drive's data, which might not be the first in disk
1288 * order.
1289 */
1290 for (temp = epp->ld_head, ld_count = 0; temp != NULL;
1291 temp = temp->next, ld_count++) {
1292 if (ld_count == 0) {
1293 abs_secnum = epp->ext_beg_sec;
1294 } else {
1295 abs_secnum = temp->abs_secnum;
1296 }
1297 if (temp->modified) {
1298 rval = read_modify_write_ebr(epp, ebr_buf,
1299 temp->parts, abs_secnum);
1300 if (rval) {
1301 if (ld_count) {
1302 /*
1303 * There was atleast one
1304 * write to the disk before
1305 * this failure. Make sure that
1306 * the kernel is notified.
1307 * Issue the ioctl.
1308 */
1309 break;
1310 }
1311 goto error;
1312 }
1313 if ((!wflag) && (temp->modified ==
1314 FDISK_MAJOR_WRITE)) {
1315 wflag = 1;
1316 }
1317 }
1318 }
1319
1320 if (wflag == 0) {
1321 /* No changes made */
1322 rval = FDISK_SUCCESS;
1323 goto error;
1324 }
1325 }
1326
1327 /* Issue ioctl to the driver to update extended partition info */
1328 rval = ioctl(epp->dev_fd, DKIOCSETEXTPART);
1329
1330 /*
1331 * Certain devices ex:lofi do not support DKIOCSETEXTPART.
1332 * Extended partitions are still created on these devices.
1333 */
1334 if (errno == ENOTTY)
1335 rval = FDISK_SUCCESS;
1336
1337 error:
1338 if (ebr_buf) {
1339 free(ebr_buf);
1340 }
1341 return (rval);
1342 }
1343
1344 int
fdisk_init_ext_part(ext_part_t * epp,uint32_t rsect,uint32_t nsect)1345 fdisk_init_ext_part(ext_part_t *epp, uint32_t rsect, uint32_t nsect)
1346 {
1347 epp->first_ebr_is_null = 1;
1348 epp->corrupt_logical_drives = 0;
1349 epp->logical_drive_count = 0;
1350 epp->ext_beg_sec = rsect;
1351 epp->ext_end_sec = rsect + nsect - 1;
1352 epp->ext_beg_cyl = FDISK_SECT_TO_CYL(epp, epp->ext_beg_sec);
1353 epp->ext_end_cyl = FDISK_SECT_TO_CYL(epp, epp->ext_end_sec);
1354 epp->invalid_bb_sig[0] = 0;
1355 return (0);
1356 }
1357
1358 int
fdisk_delete_ext_part(ext_part_t * epp)1359 fdisk_delete_ext_part(ext_part_t *epp)
1360 {
1361 epp->first_ebr_is_null = 1;
1362 /* Clear the logical drive information */
1363 fdisk_free_ld_nodes(epp);
1364 epp->logical_drive_count = 0;
1365 epp->corrupt_logical_drives = 0;
1366 epp->invalid_bb_sig[0] = 0;
1367 return (0);
1368 }
1369
1370 int
fdisk_get_disk_geom(ext_part_t * epp,int type,int what)1371 fdisk_get_disk_geom(ext_part_t *epp, int type, int what)
1372 {
1373 switch (type) {
1374 case PHYSGEOM:
1375 switch (what) {
1376 case NCYL:
1377 return ((int)epp->disk_geom.phys_cyl);
1378 case NHEADS:
1379 return ((int)epp->disk_geom.phys_heads);
1380 case NSECTPT:
1381 return ((int)epp->disk_geom.phys_sec);
1382 case SSIZE:
1383 return ((int)epp->disk_geom.sectsize);
1384 case ACYL:
1385 return ((int)epp->disk_geom.alt_cyl);
1386 default:
1387 return (EINVAL);
1388 }
1389 case VIRTGEOM:
1390 switch (what) {
1391 case NCYL:
1392 return ((int)epp->disk_geom.virt_cyl);
1393 case NHEADS:
1394 return ((int)epp->disk_geom.virt_heads);
1395 case NSECTPT:
1396 return ((int)epp->disk_geom.virt_sec);
1397 case SSIZE:
1398 return ((int)epp->disk_geom.sectsize);
1399 case ACYL:
1400 return ((int)epp->disk_geom.alt_cyl);
1401 default:
1402 return (EINVAL);
1403 }
1404 default:
1405 return (EINVAL);
1406 }
1407 }
1408
1409 int
fdisk_invalid_bb_sig(ext_part_t * epp,uchar_t ** bbsig_arr)1410 fdisk_invalid_bb_sig(ext_part_t *epp, uchar_t **bbsig_arr)
1411 {
1412 *bbsig_arr = &(epp->invalid_bb_sig[0]);
1413 return (epp->invalid_bb_sig[0]);
1414 }
1415