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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <libdevinfo.h>
31 #include <sys/sunddi.h>
32 #include <sys/types.h>
38 #if defined(i386) || defined(__amd64)
39 #include <sys/dktp/fdisk.h>
43 #include "libdiskmgt.h"
44 #include "disks_private.h"
45 #include "partition.h"
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)))
52 #define les(val) (val)
53 #define lel(val) (val)
56 #define TOTAL_NUMPART (FD_NUMPART + MAX_EXT_PARTS)
58 #define ISIZE FD_NUMPART * sizeof (struct ipart)
60 static int desc_ok(descriptor_t
*dp
);
61 static int get_attrs(descriptor_t
*dp
, struct ipart
*iparts
,
63 static int get_parts(disk_t
*disk
, struct ipart
*iparts
, char *opath
,
65 static int open_disk(disk_t
*diskp
, char *opath
, int len
);
66 static int has_slices(descriptor_t
*desc
, int *errp
);
69 partition_get_assoc_descriptors(descriptor_t
*desc
, dm_desc_type_t type
,
79 return (media_get_assocs(desc
, errp
));
81 if (!has_slices(desc
, errp
)) {
85 return (libdiskmgt_empty_desc_array(errp
));
87 return (slice_get_assocs(desc
, errp
));
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.
100 partition_get_assocs(descriptor_t
*desc
, int *errp
)
102 descriptor_t
**partitions
;
105 struct ipart iparts
[TOTAL_NUMPART
];
106 char pname
[MAXPATHLEN
];
108 #if defined(i386) || defined(__amd64)
112 if (get_parts(desc
->p
.disk
, iparts
, pname
, sizeof (pname
)) != 0) {
113 return (libdiskmgt_empty_desc_array(errp
));
116 /* allocate the array for the descriptors */
117 partitions
= (descriptor_t
**)calloc(TOTAL_NUMPART
+ 1,
118 sizeof (descriptor_t
*));
119 if (partitions
== NULL
) {
124 #if defined(i386) || defined(__amd64)
125 /* convert part. name (e.g. c0d0p1) */
127 if (len
> 1 && *(pname
+ (len
- 2)) == 'p') {
129 *(pname
+ (len
- 1)) = 0;
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.
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
)) {
147 * no active solaris part.,*try to get the first solaris part.
149 if (i
>= TOTAL_NUMPART
) {
150 for (i
= 0; i
< TOTAL_NUMPART
; i
++) {
151 if (iparts
[i
].systid
== SUNIXOS
||
152 iparts
[i
].systid
== SUNIXOS2
) {
158 if (i
< TOTAL_NUMPART
) {
159 /* we found a solaris partition to use */
160 char part_name
[MAXPATHLEN
];
163 /* convert part. name (e.g. c0d0p1) */
164 (void) snprintf(part_name
, sizeof (part_name
),
167 (void) snprintf(part_name
, sizeof (part_name
),
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
,
176 cache_free_descriptors(partitions
);
179 partitions
[1] = NULL
;
184 return (libdiskmgt_empty_desc_array(errp
));
187 /* Must be for media, so get all the parts. */
190 for (i
= 0; i
< TOTAL_NUMPART
; i
++) {
191 if (iparts
[i
].systid
!= UNUSED
) {
192 char part_name
[MAXPATHLEN
];
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.
202 /* convert part. name (e.g. c0d0p1) */
203 (void) snprintf(part_name
, sizeof (part_name
),
206 (void) snprintf(part_name
, sizeof (part_name
),
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
);
214 cache_free_descriptors(partitions
);
221 partitions
[pos
] = NULL
;
228 partition_get_attributes(descriptor_t
*dp
, int *errp
)
230 nvlist_t
*attrs
= NULL
;
231 struct ipart iparts
[TOTAL_NUMPART
];
238 if ((*errp
= get_parts(dp
->p
.disk
, iparts
, NULL
, 0)) != 0) {
242 if (nvlist_alloc(&attrs
, NVATTRS
, 0) != 0) {
247 if ((*errp
= get_attrs(dp
, iparts
, attrs
)) != 0) {
256 * Look for the partition by the partition number (which is not too useful).
259 partition_get_descriptor_by_name(char *name
, int *errp
)
261 descriptor_t
**partitions
;
263 descriptor_t
*partition
= NULL
;
265 partitions
= cache_get_descriptors(DM_PARTITION
, errp
);
270 for (i
= 0; partitions
[i
]; i
++) {
271 if (libdiskmgt_str_eq(name
, partitions
[i
]->name
)) {
272 partition
= partitions
[i
];
274 /* clean up the unused descriptors */
275 cache_free_descriptor(partitions
[i
]);
280 if (partition
== NULL
) {
289 partition_get_descriptors(int filter
[], int *errp
)
291 return (cache_get_descriptors(DM_PARTITION
, errp
));
295 partition_get_name(descriptor_t
*desc
)
302 partition_get_stats(descriptor_t
*dp
, int stat_type
, int *errp
)
304 /* There are no stat types defined for partitions */
311 partition_has_fdisk(disk_t
*dp
, int fd
)
313 char bootsect
[512 * 3]; /* 3 sectors to be safe */
316 if (dp
->drv_type
== DM_DT_FIXED
) {
317 /* on sparc, only removable media can have fdisk parts. */
323 * We assume the caller already made sure media was inserted and
327 if ((ioctl(fd
, DKIOCGMBOOT
, bootsect
) < 0) && (errno
!= ENOTTY
)) {
335 * partition_make_descriptors
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.
346 * Returns: 0 on success
347 * Error value on failure
352 partition_make_descriptors()
357 dp
= cache_get_disklist();
359 struct ipart iparts
[TOTAL_NUMPART
];
360 char pname
[MAXPATHLEN
];
362 if (get_parts(dp
, iparts
, pname
, sizeof (pname
)) == 0) {
364 char mname
[MAXPATHLEN
];
366 #if defined(i386) || defined(__amd64)
367 /* convert part. name (e.g. c0d0p1) */
371 if (len
> 1 && *(pname
+ (len
- 2)) == 'p') {
373 *(pname
+ (len
- 1)) = 0;
378 (void) media_read_name(dp
, mname
, sizeof (mname
));
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.
387 for (i
= 0; i
< TOTAL_NUMPART
; i
++) {
388 if (iparts
[i
].systid
!= UNUSED
) {
389 char part_name
[MAXPATHLEN
];
393 * convert partition name
396 (void) snprintf(part_name
,
400 (void) snprintf(part_name
,
405 cache_load_desc(DM_PARTITION
, dp
,
406 part_name
, mname
, &error
);
420 get_attrs(descriptor_t
*dp
, struct ipart
*iparts
, nvlist_t
*attrs
)
426 * We already made sure the media was loaded and ready in the
427 * get_parts call within partition_get_attributes.
430 p
= strrchr(dp
->name
, 'p');
437 if (part_num
> TOTAL_NUMPART
||
438 iparts
[part_num
- 1].systid
== UNUSED
) {
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.
447 #if defined(i386) || defined(__amd64)
448 if (part_num
> FD_NUMPART
) {
449 if (nvlist_add_uint32(attrs
, DM_PARTITION_TYPE
,
453 } else if (fdisk_is_dos_extended(iparts
[part_num
- 1].systid
)) {
454 if (nvlist_add_uint32(attrs
, DM_PARTITION_TYPE
,
460 if (nvlist_add_uint32(attrs
, DM_PARTITION_TYPE
,
468 if (nvlist_add_uint32(attrs
, DM_PARTITION_TYPE
,
475 if (nvlist_add_uint32(attrs
, DM_BOOTID
,
476 (unsigned int)iparts
[part_num
- 1].bootid
) != 0) {
480 if (nvlist_add_uint32(attrs
, DM_PTYPE
,
481 (unsigned int)iparts
[part_num
- 1].systid
) != 0) {
485 if (nvlist_add_uint32(attrs
, DM_BHEAD
,
486 (unsigned int)iparts
[part_num
- 1].beghead
) != 0) {
490 if (nvlist_add_uint32(attrs
, DM_BSECT
,
491 (unsigned int)((iparts
[part_num
- 1].begsect
) & 0x3f)) != 0) {
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) {
501 if (nvlist_add_uint32(attrs
, DM_EHEAD
,
502 (unsigned int)iparts
[part_num
- 1].endhead
) != 0) {
506 if (nvlist_add_uint32(attrs
, DM_ESECT
,
507 (unsigned int)((iparts
[part_num
- 1].endsect
) & 0x3f)) != 0) {
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) {
517 if (nvlist_add_uint32(attrs
, DM_RELSECT
,
518 (unsigned int)iparts
[part_num
- 1].relsect
) != 0) {
522 if (nvlist_add_uint32(attrs
, DM_NSECTORS
,
523 (unsigned int)iparts
[part_num
- 1].numsect
) != 0) {
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
538 * disk -The disk device to be evaluated for partitions
539 * iparts -The structure that holds information about
541 * opath -The device path
542 * opath_len -Buffer size used with opath
544 * 0 on Successful completion
545 * Error Value on failure
549 get_parts(disk_t
*disk
, struct ipart
*iparts
, char *opath
, int opath_len
)
552 struct dk_minfo minfo
;
553 struct mboot bootblk
;
557 #if defined(i386) || defined(__amd64)
559 ext_part_t
*epp
; /* extended partition structure */
560 char *device
; /* name of fixed disk drive */
562 logical_drive_t
*log_drv
; /* logical drive structure */
566 /* Can't use drive_open_disk since we need the partition dev name. */
567 if ((fd
= open_disk(disk
, opath
, opath_len
)) < 0) {
571 /* First make sure media is inserted and spun up. */
572 if (!media_read_info(fd
, &minfo
)) {
577 if (!partition_has_fdisk(disk
, fd
)) {
582 if (lseek(fd
, 0, 0) == -1) {
587 if (read(fd
, bootsect
, 512) != 512) {
593 (void) memcpy(&bootblk
, bootsect
, sizeof (bootblk
));
595 if (les(bootblk
.signature
) != MBB_MAGIC
) {
600 * Initialize the memory space to clear unknown garbage
601 * that might create confusing results.
603 for (i
= 0; i
< TOTAL_NUMPART
; i
++) {
604 (void) memset(&iparts
[i
], 0, sizeof (struct ipart
));
605 iparts
[i
].systid
= UNUSED
;
608 (void) memcpy(iparts
, bootblk
.parts
, ISIZE
);
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
616 for (i
= 0; i
< FD_NUMPART
; i
++) {
617 if (iparts
[i
].systid
== UNUSED
)
620 iparts
[i
].relsect
= lel(iparts
[i
].relsect
);
621 iparts
[i
].numsect
= lel(iparts
[i
].numsect
);
623 #if defined(i386) || defined(__amd64)
624 if (!fdisk_is_dos_extended(iparts
[i
].systid
))
627 len
= strlen(disk
->aliases
->alias
) + 1;
628 if ((device
= malloc(len
)) == NULL
) {
634 (void) snprintf(device
, len
, "%s", disk
->aliases
->alias
);
636 if ((ret
= libfdisk_init(&epp
, device
, &iparts
[i
],
637 FDISK_READ_DISK
)) != FDISK_SUCCESS
) {
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.
650 case FDISK_EBADLOGDRIVE
:
651 case FDISK_ENOLOGDRIVE
:
655 case FDISK_EBADMAGIC
:
667 * Collect logical drive information
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
);
686 /* free the device and the epp memory. */
695 /* return 1 if the partition descriptor is still valid, 0 if not. */
697 desc_ok(descriptor_t
*dp
)
699 /* First verify the media name for removable media */
700 if (dp
->p
.disk
->removable
) {
701 char mname
[MAXPATHLEN
];
703 if (!media_read_name(dp
->p
.disk
, mname
, sizeof (mname
))) {
708 return (libdiskmgt_str_eq(dp
->secondary_name
, NULL
));
710 return (libdiskmgt_str_eq(dp
->secondary_name
, mname
));
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
724 * Return 1 if partition has slices, 0 if not.
727 has_slices(descriptor_t
*desc
, int *errp
)
732 struct ipart iparts
[TOTAL_NUMPART
];
734 if (get_parts(desc
->p
.disk
, iparts
, NULL
, 0) != 0) {
739 p
= strrchr(desc
->name
, 'p');
748 * Slices are associated with the active solaris partition or if there
749 * is no active solaris partition, then the first solaris partition.
753 if (iparts
[pnum
].bootid
== ACTIVE
&&
754 (iparts
[pnum
].systid
== SUNIXOS
||
755 iparts
[pnum
].systid
== SUNIXOS2
)) {
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
)) {
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
) {
779 if (i
< TOTAL_NUMPART
&& i
== pnum
) {
789 open_disk(disk_t
*diskp
, char *opath
, int len
)
792 * Just open the first devpath.
794 if (diskp
->aliases
!= NULL
&& diskp
->aliases
->devpaths
!= NULL
) {
797 (void) strlcpy(opath
, diskp
->aliases
->devpaths
->devpath
, len
);
799 return (open(diskp
->aliases
->devpaths
->devpath
, O_RDONLY
|O_NDELAY
));
801 /* On intel we need to open partition device (e.g. c0d0p1). */
802 char part_dev
[MAXPATHLEN
];
805 (void) strlcpy(part_dev
, diskp
->aliases
->devpaths
->devpath
,
807 p
= strrchr(part_dev
, '/');
809 p
= strrchr(part_dev
, 's');
817 ps
= strrchr((p
+ 1), 's');
825 (void) strlcpy(opath
, part_dev
, len
);
827 return (open(part_dev
, O_RDONLY
|O_NDELAY
));