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