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