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