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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 2017 Nexenta Systems, Inc.
32 #include <libdevinfo.h>
39 #include <sys/sunddi.h>
40 #include <sys/types.h>
45 #include <sys/dktp/fdisk.h>
46 #include <sys/efi_partition.h>
48 #include "libdiskmgt.h"
49 #include "disks_private.h"
50 #include "partition.h"
52 #define VT_ENOTSUP (-5)
59 typedef int (*detectorp
)(char *, nvlist_t
*, int *);
61 static detectorp detectors
[] = {
68 inuse_fs
, /* fs should always be last */
72 static int add_inuse(char *name
, nvlist_t
*attrs
);
73 static int desc_ok(descriptor_t
*dp
);
74 static void dsk2rdsk(char *dsk
, char *rdsk
, int size
);
75 static int get_attrs(descriptor_t
*dp
, int fd
, nvlist_t
*attrs
);
76 static descriptor_t
**get_fixed_assocs(descriptor_t
*desc
, int *errp
);
77 static int get_slice_num(slice_t
*devp
);
78 static int match_fixed_name(disk_t
*dp
, char *name
, int *errp
);
79 static int make_fixed_descriptors(disk_t
*dp
);
82 slice_get_assoc_descriptors(descriptor_t
*desc
, dm_desc_type_t type
,
92 return (media_get_assocs(desc
, errp
));
94 return (partition_get_assocs(desc
, errp
));
102 * This is called by media/partition to get the slice descriptors for the given
103 * media/partition descriptor.
104 * For media, just get the slices, but for a partition, it must be a solaris
105 * partition and if there are active partitions, it must be the active one.
108 slice_get_assocs(descriptor_t
*desc
, int *errp
)
110 /* Just check the first drive name. */
111 if (desc
->p
.disk
->aliases
== NULL
) {
113 return (libdiskmgt_empty_desc_array(errp
));
116 return (get_fixed_assocs(desc
, errp
));
120 slice_get_attributes(descriptor_t
*dp
, int *errp
)
122 nvlist_t
*attrs
= NULL
;
124 char devpath
[MAXPATHLEN
];
131 if (nvlist_alloc(&attrs
, NVATTRS
, 0) != 0) {
136 /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */
137 dsk2rdsk(dp
->name
, devpath
, sizeof (devpath
));
138 fd
= open(devpath
, O_RDONLY
|O_NDELAY
);
140 if ((*errp
= get_attrs(dp
, fd
, attrs
)) != 0) {
153 * Look for the slice by the slice devpath.
156 slice_get_descriptor_by_name(char *name
, int *errp
)
161 for (dp
= cache_get_disklist(); dp
!= NULL
; dp
= dp
->next
) {
162 found
= match_fixed_name(dp
, name
, errp
);
165 char mname
[MAXPATHLEN
];
172 (void) media_read_name(dp
, mname
, sizeof (mname
));
174 return (cache_get_desc(DM_SLICE
, dp
, name
, mname
,
185 slice_get_descriptors(int filter
[], int *errp
)
187 return (cache_get_descriptors(DM_SLICE
, errp
));
191 slice_get_name(descriptor_t
*desc
)
197 slice_get_stats(descriptor_t
*dp
, int stat_type
, int *errp
)
201 if (stat_type
!= DM_SLICE_STAT_USE
) {
208 if (nvlist_alloc(&stats
, NVATTRS_STAT
, 0) != 0) {
213 if ((*errp
= add_inuse(dp
->name
, stats
)) != 0) {
222 * A slice descriptor points to a disk, the name is the devpath and the
223 * secondary name is the media name.
226 slice_make_descriptors()
230 dp
= cache_get_disklist();
234 error
= make_fixed_descriptors(dp
);
245 /* convert rdsk paths to dsk paths */
247 slice_rdsk2dsk(char *rdsk
, char *dsk
, int size
)
251 (void) strlcpy(dsk
, rdsk
, size
);
253 if ((strp
= strstr(dsk
, "/rdsk/")) == NULL
) {
254 /* not rdsk, check for floppy */
255 strp
= strstr(dsk
, "/rdiskette");
259 strp
++; /* move ptr to the r in rdsk or rdiskette */
261 /* move the succeeding chars over by one */
270 * Check if/how the slice is used.
273 add_inuse(char *name
, nvlist_t
*attrs
)
278 for (i
= 0; detectors
[i
] != NULL
; i
++) {
279 if (detectors
[i
](name
, attrs
, &error
) || error
!= 0) {
290 /* return 1 if the slice descriptor is still valid, 0 if not. */
292 desc_ok(descriptor_t
*dp
)
294 /* First verify the media name for removable media */
295 if (dp
->p
.disk
->removable
) {
296 char mname
[MAXPATHLEN
];
298 if (!media_read_name(dp
->p
.disk
, mname
, sizeof (mname
))) {
303 return (libdiskmgt_str_eq(dp
->secondary_name
, NULL
));
305 return (libdiskmgt_str_eq(dp
->secondary_name
, mname
));
310 * We could verify the slice is still there, but other code down the
311 * line already does these checks (e.g. see get_attrs).
317 /* convert dsk paths to rdsk paths */
319 dsk2rdsk(char *dsk
, char *rdsk
, int size
)
324 (void) strlcpy(rdsk
, dsk
, size
);
326 /* make sure there is enough room to add the r to dsk */
328 if (len
+ 2 > size
) {
332 if ((slashp
= strstr(rdsk
, "/dsk/")) == NULL
) {
333 /* not dsk, check for floppy */
334 slashp
= strstr(rdsk
, "/diskette");
337 if (slashp
!= NULL
) {
340 endp
= rdsk
+ len
; /* point to terminating 0 */
341 /* move the succeeding chars over by one */
345 } while (endp
!= slashp
);
352 get_attrs(descriptor_t
*dp
, int fd
, nvlist_t
*attrs
)
354 struct dk_minfo minfo
;
356 int data_format
= FMT_UNKNOWN
;
361 struct dk_cinfo dkinfo
;
369 /* First make sure media is inserted and spun up. */
370 if (!media_read_info(fd
, &minfo
)) {
374 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
375 data_format
= FMT_VTOC
;
376 } else if (status
== VT_ENOTSUP
&& efi_alloc_and_read(fd
, &efip
) >= 0) {
377 data_format
= FMT_EFI
;
378 if (nvlist_add_boolean(attrs
, DM_EFI
) != 0) {
384 if (data_format
== FMT_UNKNOWN
) {
388 if (ioctl(fd
, DKIOCINFO
, &dkinfo
) >= 0) {
389 snum
= dkinfo
.dki_partition
;
392 /* check the slice */
393 if (data_format
== FMT_VTOC
) {
394 if (snum
< 0 || snum
>= vtoc
.v_nparts
||
395 vtoc
.v_part
[snum
].p_size
== 0) {
398 } else { /* data_format == FMT_EFI */
399 if (snum
< 0 || snum
>= efip
->efi_nparts
||
400 efip
->efi_parts
[snum
].p_size
== 0) {
406 /* the slice exists */
408 if (nvlist_add_uint32(attrs
, DM_INDEX
, snum
) != 0) {
409 if (data_format
== FMT_EFI
) {
415 if (data_format
== FMT_VTOC
) {
416 if (nvlist_add_uint64(attrs
, DM_START
,
417 vtoc
.v_part
[snum
].p_start
) != 0) {
421 if (nvlist_add_uint64(attrs
, DM_SIZE
,
422 vtoc
.v_part
[snum
].p_size
) != 0) {
426 if (nvlist_add_uint32(attrs
, DM_TAG
,
427 vtoc
.v_part
[snum
].p_tag
) != 0) {
431 if (nvlist_add_uint32(attrs
, DM_FLAG
,
432 vtoc
.v_part
[snum
].p_flag
) != 0) {
435 } else { /* data_format == FMT_EFI */
436 if (nvlist_add_uint64(attrs
, DM_START
,
437 efip
->efi_parts
[snum
].p_start
) != 0) {
442 if (nvlist_add_uint64(attrs
, DM_SIZE
,
443 efip
->efi_parts
[snum
].p_size
) != 0) {
448 if (efip
->efi_parts
[snum
].p_name
[0] != 0) {
449 char label
[EFI_PART_NAME_LEN
+ 1];
451 (void) snprintf(label
, sizeof (label
), "%.*s",
452 EFI_PART_NAME_LEN
, efip
->efi_parts
[snum
].p_name
);
453 if (nvlist_add_string(attrs
, DM_EFI_NAME
, label
) != 0) {
460 if (data_format
== FMT_EFI
) {
464 if (inuse_mnt(dp
->name
, attrs
, &error
)) {
469 if (fstat(fd
, &buf
) != -1) {
470 if (nvlist_add_uint64(attrs
, DM_DEVT
, buf
.st_rdev
) != 0) {
476 * We need to open the cooked slice (not the raw one) to get the
479 cooked_fd
= open(dp
->name
, O_RDONLY
|O_NDELAY
);
481 if (cooked_fd
>= 0) {
485 if (devid_get(cooked_fd
, &devid
) == 0) {
488 if (devid_get_minor_name(cooked_fd
, &minor
) == 0) {
491 devidstr
= devid_str_encode(devid
, minor
);
492 if (devidstr
!= NULL
) {
494 if (nvlist_add_string(attrs
,
495 DM_DEVICEID
, devidstr
) != 0) {
499 devid_str_free(devidstr
);
501 devid_str_free(minor
);
505 (void) close(cooked_fd
);
515 static descriptor_t
**
516 get_fixed_assocs(descriptor_t
*desc
, int *errp
)
520 int data_format
= FMT_UNKNOWN
;
525 char *media_name
= NULL
;
527 descriptor_t
**slices
;
529 if ((fd
= drive_open_disk(desc
->p
.disk
, NULL
, 0)) < 0) {
534 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
535 data_format
= FMT_VTOC
;
536 } else if (status
== VT_ENOTSUP
&& efi_alloc_and_read(fd
, &efip
) >= 0) {
537 data_format
= FMT_EFI
;
541 return (libdiskmgt_empty_desc_array(errp
));
545 /* count the number of slices */
546 devp
= desc
->p
.disk
->aliases
->devpaths
;
547 for (cnt
= 0; devp
!= NULL
; devp
= devp
->next
)
550 /* allocate the array for the descriptors */
551 slices
= (descriptor_t
**)calloc(cnt
+ 1, sizeof (descriptor_t
*));
552 if (slices
== NULL
) {
553 if (data_format
== FMT_EFI
) {
560 /* get the media name from the descriptor */
561 if (desc
->type
== DM_MEDIA
) {
562 media_name
= desc
->name
;
564 /* must be a DM_PARTITION */
565 media_name
= desc
->secondary_name
;
569 for (devp
= desc
->p
.disk
->aliases
->devpaths
; devp
!= NULL
;
573 char devpath
[MAXPATHLEN
];
575 slice_num
= get_slice_num(devp
);
576 /* can't get slicenum, so no need to keep trying the drive */
577 if (slice_num
== -1) {
581 if (data_format
== FMT_VTOC
) {
582 if (slice_num
>= vtoc
.v_nparts
||
583 vtoc
.v_part
[slice_num
].p_size
== 0) {
586 } else { /* data_format == FMT_EFI */
587 if (slice_num
>= efip
->efi_nparts
||
588 efip
->efi_parts
[slice_num
].p_size
== 0) {
593 slice_rdsk2dsk(devp
->devpath
, devpath
, sizeof (devpath
));
594 slices
[pos
] = cache_get_desc(DM_SLICE
, desc
->p
.disk
, devpath
,
597 cache_free_descriptors(slices
);
598 if (data_format
== FMT_EFI
) {
607 if (data_format
== FMT_EFI
) {
616 get_slice_num(slice_t
*devp
)
618 /* check if we already determined the devpath slice number */
619 if (devp
->slice_num
== -1) {
622 if ((fd
= open(devp
->devpath
, O_RDONLY
|O_NDELAY
)) >= 0) {
623 struct dk_cinfo dkinfo
;
624 if (ioctl(fd
, DKIOCINFO
, &dkinfo
) >= 0) {
625 devp
->slice_num
= dkinfo
.dki_partition
;
631 return (devp
->slice_num
);
635 make_fixed_descriptors(disk_t
*dp
)
640 char mname
[MAXPATHLEN
];
641 int data_format
= FMT_UNKNOWN
;
645 /* Just check the first drive name. */
646 if ((ap
= dp
->aliases
) == NULL
) {
651 (void) media_read_name(dp
, mname
, sizeof (mname
));
653 for (devp
= ap
->devpaths
; devp
!= NULL
; devp
= devp
->next
) {
655 char devpath
[MAXPATHLEN
];
657 slice_num
= get_slice_num(devp
);
658 /* can't get slicenum, so no need to keep trying the drive */
659 if (slice_num
== -1) {
663 if (data_format
== FMT_UNKNOWN
) {
667 if ((fd
= drive_open_disk(dp
, NULL
, 0)) >= 0) {
668 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
669 data_format
= FMT_VTOC
;
670 } else if (status
== VT_ENOTSUP
&&
671 efi_alloc_and_read(fd
, &efip
) >= 0) {
672 data_format
= FMT_EFI
;
678 /* can't get slice data, so no need to keep trying the drive */
679 if (data_format
== FMT_UNKNOWN
) {
683 if (data_format
== FMT_VTOC
) {
684 if (slice_num
>= vtoc
.v_nparts
||
685 vtoc
.v_part
[slice_num
].p_size
== 0) {
688 } else { /* data_format == FMT_EFI */
689 if (slice_num
>= efip
->efi_nparts
||
690 efip
->efi_parts
[slice_num
].p_size
== 0) {
695 slice_rdsk2dsk(devp
->devpath
, devpath
, sizeof (devpath
));
696 cache_load_desc(DM_SLICE
, dp
, devpath
, mname
, &error
);
702 if (data_format
== FMT_EFI
) {
710 * Just look for the name on the devpaths we have cached. Return 1 if we
711 * find the name and the size of that slice is non-zero.
714 match_fixed_name(disk_t
*diskp
, char *name
, int *errp
)
721 int data_format
= FMT_UNKNOWN
;
730 while (devp
!= NULL
) {
731 char path
[MAXPATHLEN
];
733 slice_rdsk2dsk(devp
->devpath
, path
, sizeof (path
));
734 if (libdiskmgt_str_eq(path
, name
)) {
756 * If we found a match on the name we now have to check that this
757 * slice really exists (non-0 size).
760 slice_num
= get_slice_num(dp
);
761 /* can't get slicenum, so no slice */
762 if (slice_num
== -1) {
767 if ((fd
= drive_open_disk(diskp
, NULL
, 0)) < 0) {
772 if ((status
= read_extvtoc(fd
, &vtoc
)) >= 0) {
773 data_format
= FMT_VTOC
;
774 } else if (status
== VT_ENOTSUP
) {
775 status
= efi_alloc_and_read(fd
, &efip
);
777 data_format
= FMT_EFI
;
778 } else if (status
== VT_ERROR
&& errno
== ENOTTY
) {
789 if (data_format
== FMT_VTOC
) {
790 if (slice_num
< vtoc
.v_nparts
&&
791 vtoc
.v_part
[slice_num
].p_size
> 0) {
795 } else { /* data_format == FMT_EFI */
796 if (slice_num
< efip
->efi_nparts
&&
797 efip
->efi_parts
[slice_num
].p_size
> 0) {