1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <fcntl.h>
30*0Sstevel@tonic-gate #include <libdevinfo.h>
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <stdlib.h>
33*0Sstevel@tonic-gate #include <string.h>
34*0Sstevel@tonic-gate #include <sys/sunddi.h>
35*0Sstevel@tonic-gate #include <sys/types.h>
36*0Sstevel@tonic-gate #include <sys/stat.h>
37*0Sstevel@tonic-gate #include <dirent.h>
38*0Sstevel@tonic-gate #include <unistd.h>
39*0Sstevel@tonic-gate #include <sys/dkio.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include "libdiskmgt.h"
42*0Sstevel@tonic-gate #include "disks_private.h"
43*0Sstevel@tonic-gate #include "partition.h"
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #ifdef sparc
46*0Sstevel@tonic-gate #define	les(val)	((((val)&0xFF)<<8)|(((val)>>8)&0xFF))
47*0Sstevel@tonic-gate #define	lel(val)	(((unsigned)(les((val)&0x0000FFFF))<<16) | \
48*0Sstevel@tonic-gate 			    (les((unsigned)((val)&0xffff0000)>>16)))
49*0Sstevel@tonic-gate #else
50*0Sstevel@tonic-gate #define	les(val)	(val)
51*0Sstevel@tonic-gate #define	lel(val)	(val)
52*0Sstevel@tonic-gate #endif
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #define	ISIZE		FD_NUMPART * sizeof (struct ipart)
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate static int	desc_ok(descriptor_t *dp);
57*0Sstevel@tonic-gate static int	get_attrs(descriptor_t *dp, struct ipart *iparts,
58*0Sstevel@tonic-gate 		    nvlist_t *attrs);
59*0Sstevel@tonic-gate static int	get_parts(disk_t *disk, struct ipart *iparts, char *opath,
60*0Sstevel@tonic-gate 		    int opath_len);
61*0Sstevel@tonic-gate static int	open_disk(disk_t *diskp, char *opath, int len);
62*0Sstevel@tonic-gate static int	has_slices(descriptor_t *desc, int *errp);
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate descriptor_t **
65*0Sstevel@tonic-gate partition_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type,
66*0Sstevel@tonic-gate     int *errp)
67*0Sstevel@tonic-gate {
68*0Sstevel@tonic-gate 	if (!desc_ok(desc)) {
69*0Sstevel@tonic-gate 	    *errp = ENODEV;
70*0Sstevel@tonic-gate 	    return (NULL);
71*0Sstevel@tonic-gate 	}
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	switch (type) {
74*0Sstevel@tonic-gate 	case DM_MEDIA:
75*0Sstevel@tonic-gate 	    return (media_get_assocs(desc, errp));
76*0Sstevel@tonic-gate 	case DM_SLICE:
77*0Sstevel@tonic-gate 	    if (!has_slices(desc, errp)) {
78*0Sstevel@tonic-gate 		if (*errp != 0) {
79*0Sstevel@tonic-gate 		    return (NULL);
80*0Sstevel@tonic-gate 		}
81*0Sstevel@tonic-gate 		return (libdiskmgt_empty_desc_array(errp));
82*0Sstevel@tonic-gate 	    }
83*0Sstevel@tonic-gate 	    return (slice_get_assocs(desc, errp));
84*0Sstevel@tonic-gate 	}
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate 	*errp = EINVAL;
87*0Sstevel@tonic-gate 	return (NULL);
88*0Sstevel@tonic-gate }
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate /*
91*0Sstevel@tonic-gate  * This is called by media/slice to get the associated partitions.
92*0Sstevel@tonic-gate  * For a media desc. we just get all the partitions, but for a slice desc.
93*0Sstevel@tonic-gate  * we just get the active solaris partition.
94*0Sstevel@tonic-gate  */
95*0Sstevel@tonic-gate descriptor_t **
96*0Sstevel@tonic-gate partition_get_assocs(descriptor_t *desc, int *errp)
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	descriptor_t	**partitions;
99*0Sstevel@tonic-gate 	int		pos;
100*0Sstevel@tonic-gate 	int		i;
101*0Sstevel@tonic-gate 	struct ipart	iparts[FD_NUMPART];
102*0Sstevel@tonic-gate 	char		pname[MAXPATHLEN];
103*0Sstevel@tonic-gate 	int		conv_flag = 0;
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	if (get_parts(desc->p.disk, iparts, pname, sizeof (pname)) != 0) {
106*0Sstevel@tonic-gate 	    return (libdiskmgt_empty_desc_array(errp));
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate 	/* allocate the array for the descriptors */
110*0Sstevel@tonic-gate 	partitions = (descriptor_t **)calloc(FD_NUMPART + 1,
111*0Sstevel@tonic-gate 	    sizeof (descriptor_t *));
112*0Sstevel@tonic-gate 	if (partitions == NULL) {
113*0Sstevel@tonic-gate 	    *errp = ENOMEM;
114*0Sstevel@tonic-gate 	    return (NULL);
115*0Sstevel@tonic-gate 	}
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate #ifdef i386
118*0Sstevel@tonic-gate 	{
119*0Sstevel@tonic-gate 	    /* convert part. name (e.g. c0d0p0) */
120*0Sstevel@tonic-gate 	    int	len;
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 	    len = strlen(pname);
123*0Sstevel@tonic-gate 	    if (len > 1 && *(pname + (len - 2)) == 'p') {
124*0Sstevel@tonic-gate 		conv_flag = 1;
125*0Sstevel@tonic-gate 		*(pname + (len - 1)) = 0;
126*0Sstevel@tonic-gate 	    }
127*0Sstevel@tonic-gate 	}
128*0Sstevel@tonic-gate #endif
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	/*
131*0Sstevel@tonic-gate 	 * If this is a slice desc. we need the first active solaris partition
132*0Sstevel@tonic-gate 	 * and if there isn't one then we need the first solaris partition.
133*0Sstevel@tonic-gate 	 */
134*0Sstevel@tonic-gate 	if (desc->type == DM_SLICE) {
135*0Sstevel@tonic-gate 	    for (i = 0; i < FD_NUMPART; i++) {
136*0Sstevel@tonic-gate 		if (iparts[i].bootid == ACTIVE &&
137*0Sstevel@tonic-gate 		    (iparts[i].systid == SUNIXOS ||
138*0Sstevel@tonic-gate 		    iparts[i].systid == SUNIXOS2)) {
139*0Sstevel@tonic-gate 			break;
140*0Sstevel@tonic-gate 		}
141*0Sstevel@tonic-gate 	    }
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	    /* no active solaris part., try to get the first solaris part. */
144*0Sstevel@tonic-gate 	    if (i >= FD_NUMPART) {
145*0Sstevel@tonic-gate 		for (i = 0; i < FD_NUMPART; i++) {
146*0Sstevel@tonic-gate 		    if (iparts[i].systid == SUNIXOS ||
147*0Sstevel@tonic-gate 			iparts[i].systid == SUNIXOS2) {
148*0Sstevel@tonic-gate 			    break;
149*0Sstevel@tonic-gate 		    }
150*0Sstevel@tonic-gate 		}
151*0Sstevel@tonic-gate 	    }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	    if (i < FD_NUMPART) {
154*0Sstevel@tonic-gate 		/* we found a solaris partition to use */
155*0Sstevel@tonic-gate 		char	part_name[MAXPATHLEN];
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 		if (conv_flag) {
158*0Sstevel@tonic-gate 		    /* convert part. name (e.g. c0d0p0) */
159*0Sstevel@tonic-gate 		    (void) snprintf(part_name, sizeof (part_name), "%s%d",
160*0Sstevel@tonic-gate 			pname, i);
161*0Sstevel@tonic-gate 		} else {
162*0Sstevel@tonic-gate 		    (void) snprintf(part_name, sizeof (part_name), "%d", i);
163*0Sstevel@tonic-gate 		}
164*0Sstevel@tonic-gate 
165*0Sstevel@tonic-gate 		/* the media name comes from the slice desc. */
166*0Sstevel@tonic-gate 		partitions[0] = cache_get_desc(DM_PARTITION, desc->p.disk,
167*0Sstevel@tonic-gate 		    part_name, desc->secondary_name, errp);
168*0Sstevel@tonic-gate 		if (*errp != 0) {
169*0Sstevel@tonic-gate 		    cache_free_descriptors(partitions);
170*0Sstevel@tonic-gate 		    return (NULL);
171*0Sstevel@tonic-gate 		}
172*0Sstevel@tonic-gate 		partitions[1] = NULL;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 		return (partitions);
175*0Sstevel@tonic-gate 
176*0Sstevel@tonic-gate 	    }
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	    return (libdiskmgt_empty_desc_array(errp));
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	/* Must be for media, so get all the parts. */
182*0Sstevel@tonic-gate 
183*0Sstevel@tonic-gate 	pos = 0;
184*0Sstevel@tonic-gate 	for (i = 0; i < FD_NUMPART; i++) {
185*0Sstevel@tonic-gate 	    if (iparts[i].systid != 0) {
186*0Sstevel@tonic-gate 		char	part_name[MAXPATHLEN];
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 		if (conv_flag) {
189*0Sstevel@tonic-gate 		    /* convert part. name (e.g. c0d0p0) */
190*0Sstevel@tonic-gate 		    (void) snprintf(part_name, sizeof (part_name), "%s%d",
191*0Sstevel@tonic-gate 			pname, i);
192*0Sstevel@tonic-gate 		} else {
193*0Sstevel@tonic-gate 		    (void) snprintf(part_name, sizeof (part_name), "%d", i);
194*0Sstevel@tonic-gate 		}
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 		/* the media name comes from the media desc. */
197*0Sstevel@tonic-gate 		partitions[pos] = cache_get_desc(DM_PARTITION, desc->p.disk,
198*0Sstevel@tonic-gate 		    part_name, desc->name, errp);
199*0Sstevel@tonic-gate 		if (*errp != 0) {
200*0Sstevel@tonic-gate 		    cache_free_descriptors(partitions);
201*0Sstevel@tonic-gate 		    return (NULL);
202*0Sstevel@tonic-gate 		}
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate 		pos++;
205*0Sstevel@tonic-gate 	    }
206*0Sstevel@tonic-gate 	}
207*0Sstevel@tonic-gate 	partitions[pos] = NULL;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	*errp = 0;
210*0Sstevel@tonic-gate 	return (partitions);
211*0Sstevel@tonic-gate }
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate nvlist_t *
214*0Sstevel@tonic-gate partition_get_attributes(descriptor_t *dp, int *errp)
215*0Sstevel@tonic-gate {
216*0Sstevel@tonic-gate 	nvlist_t	*attrs = NULL;
217*0Sstevel@tonic-gate 	struct ipart	iparts[FD_NUMPART];
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 	if (!desc_ok(dp)) {
220*0Sstevel@tonic-gate 	    *errp = ENODEV;
221*0Sstevel@tonic-gate 	    return (NULL);
222*0Sstevel@tonic-gate 	}
223*0Sstevel@tonic-gate 
224*0Sstevel@tonic-gate 	if ((*errp = get_parts(dp->p.disk, iparts, NULL, 0)) != 0) {
225*0Sstevel@tonic-gate 	    return (NULL);
226*0Sstevel@tonic-gate 	}
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate 	if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) {
229*0Sstevel@tonic-gate 	    *errp = ENOMEM;
230*0Sstevel@tonic-gate 	    return (NULL);
231*0Sstevel@tonic-gate 	}
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate 	if ((*errp = get_attrs(dp, iparts, attrs)) != 0) {
234*0Sstevel@tonic-gate 	    nvlist_free(attrs);
235*0Sstevel@tonic-gate 	    attrs = NULL;
236*0Sstevel@tonic-gate 	}
237*0Sstevel@tonic-gate 
238*0Sstevel@tonic-gate 	return (attrs);
239*0Sstevel@tonic-gate }
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate /*
242*0Sstevel@tonic-gate  * Look for the partition by the partition number (which is not too useful).
243*0Sstevel@tonic-gate  */
244*0Sstevel@tonic-gate descriptor_t *
245*0Sstevel@tonic-gate partition_get_descriptor_by_name(char *name, int *errp)
246*0Sstevel@tonic-gate {
247*0Sstevel@tonic-gate 	descriptor_t	**partitions;
248*0Sstevel@tonic-gate 	int		i;
249*0Sstevel@tonic-gate 	descriptor_t	*partition = NULL;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	partitions = cache_get_descriptors(DM_PARTITION, errp);
252*0Sstevel@tonic-gate 	if (*errp != 0) {
253*0Sstevel@tonic-gate 	    return (NULL);
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	for (i = 0; partitions[i]; i++) {
257*0Sstevel@tonic-gate 	    if (libdiskmgt_str_eq(name, partitions[i]->name)) {
258*0Sstevel@tonic-gate 		partition = partitions[i];
259*0Sstevel@tonic-gate 	    } else {
260*0Sstevel@tonic-gate 		/* clean up the unused descriptors */
261*0Sstevel@tonic-gate 		cache_free_descriptor(partitions[i]);
262*0Sstevel@tonic-gate 	    }
263*0Sstevel@tonic-gate 	}
264*0Sstevel@tonic-gate 	free(partitions);
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate 	if (partition == NULL) {
267*0Sstevel@tonic-gate 	    *errp = ENODEV;
268*0Sstevel@tonic-gate 	}
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	return (partition);
271*0Sstevel@tonic-gate }
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate /* ARGSUSED */
274*0Sstevel@tonic-gate descriptor_t **
275*0Sstevel@tonic-gate partition_get_descriptors(int filter[], int *errp)
276*0Sstevel@tonic-gate {
277*0Sstevel@tonic-gate 	return (cache_get_descriptors(DM_PARTITION, errp));
278*0Sstevel@tonic-gate }
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate char *
281*0Sstevel@tonic-gate partition_get_name(descriptor_t *desc)
282*0Sstevel@tonic-gate {
283*0Sstevel@tonic-gate 	return (desc->name);
284*0Sstevel@tonic-gate }
285*0Sstevel@tonic-gate 
286*0Sstevel@tonic-gate /* ARGSUSED */
287*0Sstevel@tonic-gate nvlist_t *
288*0Sstevel@tonic-gate partition_get_stats(descriptor_t *dp, int stat_type, int *errp)
289*0Sstevel@tonic-gate {
290*0Sstevel@tonic-gate 	/* There are no stat types defined for partitions */
291*0Sstevel@tonic-gate 	*errp = EINVAL;
292*0Sstevel@tonic-gate 	return (NULL);
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate 
295*0Sstevel@tonic-gate /* ARGSUSED */
296*0Sstevel@tonic-gate int
297*0Sstevel@tonic-gate partition_has_fdisk(disk_t *dp, int fd)
298*0Sstevel@tonic-gate {
299*0Sstevel@tonic-gate 	char		bootsect[512 * 3]; /* 3 sectors to be safe */
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate #ifdef sparc
302*0Sstevel@tonic-gate 	if (dp->drv_type == DM_DT_FIXED) {
303*0Sstevel@tonic-gate 	    /* on sparc, only removable media can have fdisk parts. */
304*0Sstevel@tonic-gate 	    return (0);
305*0Sstevel@tonic-gate 	}
306*0Sstevel@tonic-gate #endif
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	/*
309*0Sstevel@tonic-gate 	 * We assume the caller already made sure media was inserted and
310*0Sstevel@tonic-gate 	 * spun up.
311*0Sstevel@tonic-gate 	 */
312*0Sstevel@tonic-gate 
313*0Sstevel@tonic-gate 	if ((ioctl(fd, DKIOCGMBOOT, bootsect) < 0) && (errno != ENOTTY)) {
314*0Sstevel@tonic-gate 	    return (0);
315*0Sstevel@tonic-gate 	}
316*0Sstevel@tonic-gate 
317*0Sstevel@tonic-gate 	return (1);
318*0Sstevel@tonic-gate }
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate /*
321*0Sstevel@tonic-gate  * A partition descriptor points to a disk, the name is the partition number
322*0Sstevel@tonic-gate  * and the secondary name is the media name.
323*0Sstevel@tonic-gate  */
324*0Sstevel@tonic-gate int
325*0Sstevel@tonic-gate partition_make_descriptors()
326*0Sstevel@tonic-gate {
327*0Sstevel@tonic-gate 	int		error;
328*0Sstevel@tonic-gate 	disk_t		*dp;
329*0Sstevel@tonic-gate 
330*0Sstevel@tonic-gate 	dp = cache_get_disklist();
331*0Sstevel@tonic-gate 	while (dp != NULL) {
332*0Sstevel@tonic-gate 	    struct ipart	iparts[FD_NUMPART];
333*0Sstevel@tonic-gate 	    char		pname[MAXPATHLEN];
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 	    if (get_parts(dp, iparts, pname, sizeof (pname)) == 0) {
336*0Sstevel@tonic-gate 		int	i;
337*0Sstevel@tonic-gate 		char	mname[MAXPATHLEN];
338*0Sstevel@tonic-gate 		int	conv_flag = 0;
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate #ifdef i386
341*0Sstevel@tonic-gate 		/* convert part. name (e.g. c0d0p0) */
342*0Sstevel@tonic-gate 		int	len;
343*0Sstevel@tonic-gate 
344*0Sstevel@tonic-gate 		len = strlen(pname);
345*0Sstevel@tonic-gate 		if (len > 1 && *(pname + (len - 2)) == 'p') {
346*0Sstevel@tonic-gate 		    conv_flag = 1;
347*0Sstevel@tonic-gate 		    *(pname + (len - 1)) = 0;
348*0Sstevel@tonic-gate 		}
349*0Sstevel@tonic-gate #endif
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 		mname[0] = 0;
352*0Sstevel@tonic-gate 		(void) media_read_name(dp, mname, sizeof (mname));
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate 		for (i = 0; i < FD_NUMPART; i++) {
355*0Sstevel@tonic-gate 		    if (iparts[i].systid != 0) {
356*0Sstevel@tonic-gate 			char	part_name[MAXPATHLEN];
357*0Sstevel@tonic-gate 
358*0Sstevel@tonic-gate 			if (conv_flag) {
359*0Sstevel@tonic-gate 			    /* convert part. name (e.g. c0d0p0) */
360*0Sstevel@tonic-gate 			    (void) snprintf(part_name, sizeof (part_name),
361*0Sstevel@tonic-gate 				"%s%d", pname, i);
362*0Sstevel@tonic-gate 			} else {
363*0Sstevel@tonic-gate 			    (void) snprintf(part_name, sizeof (part_name),
364*0Sstevel@tonic-gate 				"%d", i);
365*0Sstevel@tonic-gate 			}
366*0Sstevel@tonic-gate 
367*0Sstevel@tonic-gate 			cache_load_desc(DM_PARTITION, dp, part_name, mname,
368*0Sstevel@tonic-gate 			    &error);
369*0Sstevel@tonic-gate 			if (error != 0) {
370*0Sstevel@tonic-gate 			    return (error);
371*0Sstevel@tonic-gate 			}
372*0Sstevel@tonic-gate 		    }
373*0Sstevel@tonic-gate 		}
374*0Sstevel@tonic-gate 	    }
375*0Sstevel@tonic-gate 	    dp = dp->next;
376*0Sstevel@tonic-gate 	}
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	return (0);
379*0Sstevel@tonic-gate }
380*0Sstevel@tonic-gate 
381*0Sstevel@tonic-gate static int
382*0Sstevel@tonic-gate get_attrs(descriptor_t *dp, struct ipart *iparts, nvlist_t *attrs)
383*0Sstevel@tonic-gate {
384*0Sstevel@tonic-gate 	char		*p;
385*0Sstevel@tonic-gate 	int		part_num;
386*0Sstevel@tonic-gate 
387*0Sstevel@tonic-gate 	/*
388*0Sstevel@tonic-gate 	 * We already made sure the media was loaded and ready in the
389*0Sstevel@tonic-gate 	 * get_parts call within partition_get_attributes.
390*0Sstevel@tonic-gate 	 */
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	p = strrchr(dp->name, 'p');
393*0Sstevel@tonic-gate 	if (p == NULL) {
394*0Sstevel@tonic-gate 	    p = dp->name;
395*0Sstevel@tonic-gate 	} else {
396*0Sstevel@tonic-gate 	    p++;
397*0Sstevel@tonic-gate 	}
398*0Sstevel@tonic-gate 	part_num = atoi(p);
399*0Sstevel@tonic-gate 	if (part_num >= FD_NUMPART || iparts[part_num].systid == 0) {
400*0Sstevel@tonic-gate 	    return (ENODEV);
401*0Sstevel@tonic-gate 	}
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 	/* we found the partition */
404*0Sstevel@tonic-gate 
405*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_BOOTID,
406*0Sstevel@tonic-gate 	    (unsigned int)iparts[part_num].bootid) != 0) {
407*0Sstevel@tonic-gate 	    return (ENOMEM);
408*0Sstevel@tonic-gate 	}
409*0Sstevel@tonic-gate 
410*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_PTYPE,
411*0Sstevel@tonic-gate 	    (unsigned int)iparts[part_num].systid) != 0) {
412*0Sstevel@tonic-gate 	    return (ENOMEM);
413*0Sstevel@tonic-gate 	}
414*0Sstevel@tonic-gate 
415*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_BHEAD,
416*0Sstevel@tonic-gate 	    (unsigned int)iparts[part_num].beghead) != 0) {
417*0Sstevel@tonic-gate 	    return (ENOMEM);
418*0Sstevel@tonic-gate 	}
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_BSECT,
421*0Sstevel@tonic-gate 	    (unsigned int)((iparts[part_num].begsect) & 0x3f)) != 0) {
422*0Sstevel@tonic-gate 	    return (ENOMEM);
423*0Sstevel@tonic-gate 	}
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_BCYL, (unsigned int)
426*0Sstevel@tonic-gate 	    ((iparts[part_num].begcyl & 0xff) |
427*0Sstevel@tonic-gate 	    ((iparts[part_num].begsect & 0xc0) << 2))) != 0) {
428*0Sstevel@tonic-gate 	    return (ENOMEM);
429*0Sstevel@tonic-gate 	}
430*0Sstevel@tonic-gate 
431*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_EHEAD,
432*0Sstevel@tonic-gate 	    (unsigned int)iparts[part_num].endhead) != 0) {
433*0Sstevel@tonic-gate 	    return (ENOMEM);
434*0Sstevel@tonic-gate 	}
435*0Sstevel@tonic-gate 
436*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_ESECT,
437*0Sstevel@tonic-gate 	    (unsigned int)((iparts[part_num].endsect) & 0x3f)) != 0) {
438*0Sstevel@tonic-gate 	    return (ENOMEM);
439*0Sstevel@tonic-gate 	}
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_ECYL, (unsigned int)
442*0Sstevel@tonic-gate 	    ((iparts[part_num].endcyl & 0xff) |
443*0Sstevel@tonic-gate 	    ((iparts[part_num].endsect & 0xc0) << 2))) != 0) {
444*0Sstevel@tonic-gate 	    return (ENOMEM);
445*0Sstevel@tonic-gate 	}
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_RELSECT,
448*0Sstevel@tonic-gate 	    (unsigned int)iparts[part_num].relsect) != 0) {
449*0Sstevel@tonic-gate 	    return (ENOMEM);
450*0Sstevel@tonic-gate 	}
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	if (nvlist_add_uint32(attrs, DM_NSECTORS,
453*0Sstevel@tonic-gate 	    (unsigned int)iparts[part_num].numsect) != 0) {
454*0Sstevel@tonic-gate 	    return (ENOMEM);
455*0Sstevel@tonic-gate 	}
456*0Sstevel@tonic-gate 
457*0Sstevel@tonic-gate 	return (0);
458*0Sstevel@tonic-gate }
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate static int
461*0Sstevel@tonic-gate get_parts(disk_t *disk, struct ipart *iparts, char *opath, int opath_len)
462*0Sstevel@tonic-gate {
463*0Sstevel@tonic-gate 	int		fd;
464*0Sstevel@tonic-gate 	struct dk_minfo	minfo;
465*0Sstevel@tonic-gate 	struct mboot	bootblk;
466*0Sstevel@tonic-gate 	char		bootsect[512];
467*0Sstevel@tonic-gate 	int		i;
468*0Sstevel@tonic-gate 
469*0Sstevel@tonic-gate 	/* Can't use drive_open_disk since we need the partition dev name. */
470*0Sstevel@tonic-gate 	if ((fd = open_disk(disk, opath, opath_len)) < 0) {
471*0Sstevel@tonic-gate 	    return (ENODEV);
472*0Sstevel@tonic-gate 	}
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 	/* First make sure media is inserted and spun up. */
475*0Sstevel@tonic-gate 	if (!media_read_info(fd, &minfo)) {
476*0Sstevel@tonic-gate #ifdef i386
477*0Sstevel@tonic-gate 	    /* XXX Work around bug 4725434 */
478*0Sstevel@tonic-gate 	    if (disk->removable) {
479*0Sstevel@tonic-gate #endif
480*0Sstevel@tonic-gate 	    (void) close(fd);
481*0Sstevel@tonic-gate 	    return (ENODEV);
482*0Sstevel@tonic-gate #ifdef i386
483*0Sstevel@tonic-gate 	    }
484*0Sstevel@tonic-gate #endif
485*0Sstevel@tonic-gate 	}
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 	if (!partition_has_fdisk(disk, fd)) {
488*0Sstevel@tonic-gate 	    (void) close(fd);
489*0Sstevel@tonic-gate 	    return (ENOTTY);
490*0Sstevel@tonic-gate 	}
491*0Sstevel@tonic-gate 
492*0Sstevel@tonic-gate 	if (lseek(fd, 0, 0) == -1) {
493*0Sstevel@tonic-gate 	    (void) close(fd);
494*0Sstevel@tonic-gate 	    return (ENODEV);
495*0Sstevel@tonic-gate 	}
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	if (read(fd, bootsect, 512) != 512) {
498*0Sstevel@tonic-gate 	    (void) close(fd);
499*0Sstevel@tonic-gate 	    return (ENODEV);
500*0Sstevel@tonic-gate 	}
501*0Sstevel@tonic-gate 	(void) close(fd);
502*0Sstevel@tonic-gate 
503*0Sstevel@tonic-gate 	(void) memcpy(&bootblk, bootsect, sizeof (bootblk));
504*0Sstevel@tonic-gate 
505*0Sstevel@tonic-gate 	if (les(bootblk.signature) != MBB_MAGIC)  {
506*0Sstevel@tonic-gate 	    return (ENOTTY);
507*0Sstevel@tonic-gate 	}
508*0Sstevel@tonic-gate 
509*0Sstevel@tonic-gate 	(void) memcpy(iparts, bootblk.parts, ISIZE);
510*0Sstevel@tonic-gate 
511*0Sstevel@tonic-gate 	for (i = 0; i < FD_NUMPART; i++) {
512*0Sstevel@tonic-gate 	    if (iparts[i].systid != 0) {
513*0Sstevel@tonic-gate 		iparts[i].relsect = lel(iparts[i].relsect);
514*0Sstevel@tonic-gate 		iparts[i].numsect = lel(iparts[i].numsect);
515*0Sstevel@tonic-gate 	    }
516*0Sstevel@tonic-gate 	}
517*0Sstevel@tonic-gate 
518*0Sstevel@tonic-gate 	return (0);
519*0Sstevel@tonic-gate }
520*0Sstevel@tonic-gate /* return 1 if the partition descriptor is still valid, 0 if not. */
521*0Sstevel@tonic-gate static int
522*0Sstevel@tonic-gate desc_ok(descriptor_t *dp)
523*0Sstevel@tonic-gate {
524*0Sstevel@tonic-gate 	/* First verify the media name for removable media */
525*0Sstevel@tonic-gate 	if (dp->p.disk->removable) {
526*0Sstevel@tonic-gate 	    char	mname[MAXPATHLEN];
527*0Sstevel@tonic-gate 
528*0Sstevel@tonic-gate 	    if (!media_read_name(dp->p.disk, mname, sizeof (mname))) {
529*0Sstevel@tonic-gate 		return (0);
530*0Sstevel@tonic-gate 	    }
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	    if (mname[0] == 0) {
533*0Sstevel@tonic-gate 		return (libdiskmgt_str_eq(dp->secondary_name, NULL));
534*0Sstevel@tonic-gate 	    } else {
535*0Sstevel@tonic-gate 		return (libdiskmgt_str_eq(dp->secondary_name, mname));
536*0Sstevel@tonic-gate 	    }
537*0Sstevel@tonic-gate 	}
538*0Sstevel@tonic-gate 
539*0Sstevel@tonic-gate 	/*
540*0Sstevel@tonic-gate 	 * We could verify the partition is still there but this is kind of
541*0Sstevel@tonic-gate 	 * expensive and other code down the line will do that (e.g. see
542*0Sstevel@tonic-gate 	 * get_attrs).
543*0Sstevel@tonic-gate 	 */
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	return (1);
546*0Sstevel@tonic-gate }
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate /*
549*0Sstevel@tonic-gate  * Return 1 if partition has slices, 0 if not.
550*0Sstevel@tonic-gate  */
551*0Sstevel@tonic-gate static int
552*0Sstevel@tonic-gate has_slices(descriptor_t *desc, int *errp)
553*0Sstevel@tonic-gate {
554*0Sstevel@tonic-gate 	int		pnum;
555*0Sstevel@tonic-gate 	int		i;
556*0Sstevel@tonic-gate 	char		*p;
557*0Sstevel@tonic-gate 	struct ipart	iparts[FD_NUMPART];
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 	if (get_parts(desc->p.disk, iparts, NULL, 0) != 0) {
560*0Sstevel@tonic-gate 	    *errp = ENODEV;
561*0Sstevel@tonic-gate 	    return (0);
562*0Sstevel@tonic-gate 	}
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	p = strrchr(desc->name, 'p');
565*0Sstevel@tonic-gate 	if (p == NULL) {
566*0Sstevel@tonic-gate 	    p = desc->name;
567*0Sstevel@tonic-gate 	} else {
568*0Sstevel@tonic-gate 	    p++;
569*0Sstevel@tonic-gate 	}
570*0Sstevel@tonic-gate 	pnum = atoi(p);
571*0Sstevel@tonic-gate 
572*0Sstevel@tonic-gate 	/*
573*0Sstevel@tonic-gate 	 * Slices are associated with the active solaris partition or if there
574*0Sstevel@tonic-gate 	 * is no active solaris partition, then the first solaris partition.
575*0Sstevel@tonic-gate 	 */
576*0Sstevel@tonic-gate 
577*0Sstevel@tonic-gate 	*errp = 0;
578*0Sstevel@tonic-gate 	if (iparts[pnum].bootid == ACTIVE &&
579*0Sstevel@tonic-gate 	    (iparts[pnum].systid == SUNIXOS ||
580*0Sstevel@tonic-gate 	    iparts[pnum].systid == SUNIXOS2)) {
581*0Sstevel@tonic-gate 		return (1);
582*0Sstevel@tonic-gate 	} else {
583*0Sstevel@tonic-gate 	    int	active = 0;
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate 	    /* Check if there are no active solaris partitions. */
586*0Sstevel@tonic-gate 	    for (i = 0; i < FD_NUMPART; i++) {
587*0Sstevel@tonic-gate 		if (iparts[i].bootid == ACTIVE &&
588*0Sstevel@tonic-gate 		    (iparts[i].systid == SUNIXOS ||
589*0Sstevel@tonic-gate 		    iparts[i].systid == SUNIXOS2)) {
590*0Sstevel@tonic-gate 			active = 1;
591*0Sstevel@tonic-gate 			break;
592*0Sstevel@tonic-gate 		}
593*0Sstevel@tonic-gate 	    }
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 	    if (!active) {
596*0Sstevel@tonic-gate 		/* Check if this is the first solaris partition. */
597*0Sstevel@tonic-gate 		for (i = 0; i < FD_NUMPART; i++) {
598*0Sstevel@tonic-gate 		    if (iparts[i].systid == SUNIXOS ||
599*0Sstevel@tonic-gate 			iparts[i].systid == SUNIXOS2) {
600*0Sstevel@tonic-gate 			    break;
601*0Sstevel@tonic-gate 		    }
602*0Sstevel@tonic-gate 		}
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 		if (i < FD_NUMPART && i == pnum) {
605*0Sstevel@tonic-gate 		    return (1);
606*0Sstevel@tonic-gate 		}
607*0Sstevel@tonic-gate 	    }
608*0Sstevel@tonic-gate 	}
609*0Sstevel@tonic-gate 
610*0Sstevel@tonic-gate 	return (0);
611*0Sstevel@tonic-gate }
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate static int
614*0Sstevel@tonic-gate open_disk(disk_t *diskp, char *opath, int len)
615*0Sstevel@tonic-gate {
616*0Sstevel@tonic-gate 	char	rmmedia_devpath[MAXPATHLEN];
617*0Sstevel@tonic-gate 
618*0Sstevel@tonic-gate 	if (diskp->removable && media_get_volm_path(diskp, rmmedia_devpath,
619*0Sstevel@tonic-gate 	    sizeof (rmmedia_devpath))) {
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	    int		fd;
622*0Sstevel@tonic-gate 	    struct stat	buf;
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	    if (rmmedia_devpath[0] == 0) {
625*0Sstevel@tonic-gate 		/* removable but no media */
626*0Sstevel@tonic-gate 		return (-1);
627*0Sstevel@tonic-gate 	    }
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	    if ((fd = open(rmmedia_devpath, O_RDONLY|O_NDELAY)) < 0) {
630*0Sstevel@tonic-gate 		return (-1);
631*0Sstevel@tonic-gate 	    }
632*0Sstevel@tonic-gate 
633*0Sstevel@tonic-gate 	    if (fstat(fd, &buf) != 0) {
634*0Sstevel@tonic-gate 		(void) close(fd);
635*0Sstevel@tonic-gate 		return (-1);
636*0Sstevel@tonic-gate 	    }
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	    if (buf.st_mode & S_IFCHR) {
639*0Sstevel@tonic-gate 		/* opened, is device, so done */
640*0Sstevel@tonic-gate 		if (opath != NULL) {
641*0Sstevel@tonic-gate 		    (void) strlcpy(opath, rmmedia_devpath, len);
642*0Sstevel@tonic-gate 		}
643*0Sstevel@tonic-gate 		return (fd);
644*0Sstevel@tonic-gate 
645*0Sstevel@tonic-gate 	    } else if (buf.st_mode & S_IFDIR) {
646*0Sstevel@tonic-gate 		/* disk w/ slices so handle the directory */
647*0Sstevel@tonic-gate 		DIR		*dirp;
648*0Sstevel@tonic-gate 		struct dirent	*dentp;
649*0Sstevel@tonic-gate 		int		dfd;
650*0Sstevel@tonic-gate #ifdef _LP64
651*0Sstevel@tonic-gate 		struct dirent	*result;
652*0Sstevel@tonic-gate #endif
653*0Sstevel@tonic-gate 
654*0Sstevel@tonic-gate 		/* each device file in the dir represents a slice */
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 		if ((dirp = fdopendir(fd)) == NULL) {
657*0Sstevel@tonic-gate 		    (void) close(fd);
658*0Sstevel@tonic-gate 		    return (-1);
659*0Sstevel@tonic-gate 		}
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 		if ((dentp = (struct dirent *)malloc(sizeof (struct dirent) +
662*0Sstevel@tonic-gate 		    _PC_NAME_MAX + 1)) == NULL) {
663*0Sstevel@tonic-gate 		    /* out of memory */
664*0Sstevel@tonic-gate 		    (void) close(fd);
665*0Sstevel@tonic-gate 		    return (-1);
666*0Sstevel@tonic-gate 		}
667*0Sstevel@tonic-gate #ifdef _LP64
668*0Sstevel@tonic-gate 		while (readdir_r(dirp, dentp, &result) != NULL) {
669*0Sstevel@tonic-gate #else
670*0Sstevel@tonic-gate 		while (readdir_r(dirp, dentp) != NULL) {
671*0Sstevel@tonic-gate #endif
672*0Sstevel@tonic-gate 		    char	slice_path[MAXPATHLEN];
673*0Sstevel@tonic-gate 
674*0Sstevel@tonic-gate 		    if (libdiskmgt_str_eq(".", dentp->d_name) ||
675*0Sstevel@tonic-gate 			libdiskmgt_str_eq("..", dentp->d_name)) {
676*0Sstevel@tonic-gate 			continue;
677*0Sstevel@tonic-gate 		    }
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate 		    (void) snprintf(slice_path, sizeof (slice_path), "%s/%s",
680*0Sstevel@tonic-gate 			rmmedia_devpath, dentp->d_name);
681*0Sstevel@tonic-gate 
682*0Sstevel@tonic-gate 		    if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) < 0) {
683*0Sstevel@tonic-gate 			continue;
684*0Sstevel@tonic-gate 		    }
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 		    if (fstat(dfd, &buf) == 0 && (buf.st_mode & S_IFCHR)) {
687*0Sstevel@tonic-gate 			/* opened, is device, so done */
688*0Sstevel@tonic-gate 			free(dentp);
689*0Sstevel@tonic-gate 			(void) close(fd);
690*0Sstevel@tonic-gate 			if (opath != NULL) {
691*0Sstevel@tonic-gate 			    (void) strlcpy(opath, slice_path, len);
692*0Sstevel@tonic-gate 			}
693*0Sstevel@tonic-gate 			return (dfd);
694*0Sstevel@tonic-gate 		    }
695*0Sstevel@tonic-gate 
696*0Sstevel@tonic-gate 		    /* not a device, keep looking */
697*0Sstevel@tonic-gate 		    (void) close(dfd);
698*0Sstevel@tonic-gate 		}
699*0Sstevel@tonic-gate 
700*0Sstevel@tonic-gate 		/* did not find a device under the rmmedia_path */
701*0Sstevel@tonic-gate 		free(dentp);
702*0Sstevel@tonic-gate 		(void) close(fd);
703*0Sstevel@tonic-gate 	    }
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 	    /* didn't find a device under volume management control */
706*0Sstevel@tonic-gate 	    return (-1);
707*0Sstevel@tonic-gate 	}
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 	/*
710*0Sstevel@tonic-gate 	 * Not removable media under volume management control so just open the
711*0Sstevel@tonic-gate 	 * first devpath.
712*0Sstevel@tonic-gate 	 */
713*0Sstevel@tonic-gate 	if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) {
714*0Sstevel@tonic-gate #ifdef sparc
715*0Sstevel@tonic-gate 	    if (opath != NULL) {
716*0Sstevel@tonic-gate 		(void) strlcpy(opath, diskp->aliases->devpaths->devpath, len);
717*0Sstevel@tonic-gate 	    }
718*0Sstevel@tonic-gate 	    return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY));
719*0Sstevel@tonic-gate #else
720*0Sstevel@tonic-gate 	    /* On intel we need to open partition device (e.g. c0d0p0). */
721*0Sstevel@tonic-gate 	    char	part_dev[MAXPATHLEN];
722*0Sstevel@tonic-gate 	    char	*p;
723*0Sstevel@tonic-gate 
724*0Sstevel@tonic-gate 	    (void) strlcpy(part_dev, diskp->aliases->devpaths->devpath,
725*0Sstevel@tonic-gate 		sizeof (part_dev));
726*0Sstevel@tonic-gate 	    p = strrchr(part_dev, '/');
727*0Sstevel@tonic-gate 	    if (p == NULL) {
728*0Sstevel@tonic-gate 		p = strrchr(part_dev, 's');
729*0Sstevel@tonic-gate 		if (p != NULL) {
730*0Sstevel@tonic-gate 		    *p = 'p';
731*0Sstevel@tonic-gate 		}
732*0Sstevel@tonic-gate 	    } else {
733*0Sstevel@tonic-gate 		char *ps;
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate 		*p = 0;
736*0Sstevel@tonic-gate 		ps = strrchr((p + 1), 's');
737*0Sstevel@tonic-gate 		if (ps != NULL) {
738*0Sstevel@tonic-gate 		    *ps = 'p';
739*0Sstevel@tonic-gate 		}
740*0Sstevel@tonic-gate 		*p = '/';
741*0Sstevel@tonic-gate 	    }
742*0Sstevel@tonic-gate 
743*0Sstevel@tonic-gate 	    if (opath != NULL) {
744*0Sstevel@tonic-gate 		(void) strlcpy(opath, part_dev, len);
745*0Sstevel@tonic-gate 	    }
746*0Sstevel@tonic-gate 	    return (open(part_dev, O_RDONLY|O_NDELAY));
747*0Sstevel@tonic-gate #endif
748*0Sstevel@tonic-gate 	}
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate 	return (-1);
751*0Sstevel@tonic-gate }
752