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