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.
34 #include <sys/types.h>
38 #include <sys/modctl.h>
40 #include <sys/openpromio.h>
43 #include <sys/sunddi.h>
46 #include "device_info.h"
52 /* alias node searching return values */
55 #define INEXACT_MATCH 2
57 /* for prom io operations */
59 #define MAXPROPSIZE 256
60 #define MAXVALSIZE (BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
62 /* prom_obp_vers() return values */
63 #define OBP_OF 0x4 /* versions OBP 3.x */
64 #define OBP_NO_ALIAS_NODE 0x8 /* No alias node */
69 /* default logical and physical device name space */
71 #define DEVICES "/devices"
73 /* for boot device identification on x86 */
74 #define CREATE_DISKMAP "/boot/solaris/bin/create_diskmap"
75 #define GRUBDISK_MAP "/var/run/solaris_grubdisk.map"
78 * internal structure declarations
81 /* for prom io functions */
84 struct openpromio opp
;
87 /* used to manage lists of devices and aliases */
90 struct name_list
*next
;
94 * internal global data
97 /* global since nftw does not let you pass args to be updated */
98 static struct name_list
**dev_list
;
100 /* global since nftw does not let you pass args to be updated */
101 static struct boot_dev
**bootdev_list
;
103 /* mutex to protect bootdev_list and dev_list */
104 static mutex_t dev_lists_lk
= DEFAULTMUTEX
;
107 * internal function prototypes
110 static int prom_open(int);
111 static void prom_close(int);
112 static int is_openprom(int);
114 static int prom_dev_to_alias(char *dev
, uint_t options
, char ***ret_buf
);
115 static int alias_to_prom_dev(char *alias
, char *ret_buf
);
116 static int prom_srch_aliases_by_def(char *, struct name_list
**,
117 struct name_list
**, int);
118 static int prom_find_aliases_node(int fd
);
119 static int prom_compare_devs(char *prom_dev1
, char *prom_dev2
);
120 static int _prom_strcmp(char *s1
, char *s2
);
121 static int prom_srch_node(int fd
, char *prop_name
, char *ret_buf
);
122 static uint_t
prom_next_node(int fd
, uint_t node_id
);
123 static uint_t
prom_child_node(int fd
, uint_t node_id
);
125 static int prom_obp_vers(void);
127 static void parse_name(char *, char **, char **, char **);
128 static int process_bootdev(const char *, const char *, struct boot_dev
***);
129 static int process_minor_name(char *dev_path
, const char *default_root
);
130 static void options_override(char *prom_path
, char *alias_name
);
131 static int devfs_phys_to_logical(struct boot_dev
**bootdev_array
,
132 const int array_size
, const char *default_root
);
133 static int check_logical_dev(const char *, const struct stat
*, int,
135 static struct boot_dev
*alloc_bootdev(char *);
136 static void free_name_list(struct name_list
*list
, int free_name
);
137 static int insert_alias_list(struct name_list
**list
,
139 static int get_boot_dev_var(struct openpromio
*opp
);
140 static int set_boot_dev_var(struct openpromio
*opp
, char *bootdev
);
141 static int devfs_prom_to_dev_name(char *prom_path
, char *dev_path
);
142 static int devfs_dev_to_prom_names(char *dev_path
, char *prom_path
, size_t len
);
145 * frees a list of paths from devfs_get_prom_name_list
148 prom_list_free(char **prom_list
)
155 while (prom_list
[i
]) {
163 devfs_get_prom_name_list(const char *dev_name
, char ***prom_list
)
165 char *prom_path
= NULL
;
166 int count
= 0; /* # of slots we will need in prom_list */
171 if (dev_name
== NULL
)
172 return (DEVFS_INVAL
);
173 if (*dev_name
!= '/')
174 return (DEVFS_INVAL
);
175 if (prom_list
== NULL
)
176 return (DEVFS_INVAL
);
179 * make sure we are on a machine which supports a prom
180 * and we have permission to use /dev/openprom
182 if ((ret
= prom_obp_vers()) < 0)
184 if ((prom_path
= (char *)malloc(MAXVALSIZE
)) == NULL
)
185 return (DEVFS_NOMEM
);
187 * get the prom path name
189 ret
= devfs_dev_to_prom_names((char *)dev_name
, prom_path
, MAXVALSIZE
);
194 /* deal with list of names */
195 for (i
= 0; i
< ret
; i
++)
196 if (prom_path
[i
] == '\0')
199 if ((list
= (char **)calloc(count
+ 1, sizeof (char *))) == NULL
) {
201 return (DEVFS_NOMEM
);
205 for (i
= 0; i
< count
; i
++) {
206 len
= strlen(ptr
) + 1;
207 if ((list
[i
] = (char *)malloc(len
)) == NULL
) {
210 return (DEVFS_NOMEM
);
212 (void) snprintf(list
[i
], len
, "%s", ptr
);
223 * retrieve the list of prom representations for a given device name
224 * the list will be sorted in the following order: exact aliases,
225 * inexact aliases, prom device path name. If multiple matches occur
226 * for exact or inexact aliases, then these are sorted in collating
227 * order. The list is returned in prom_list
229 * the list may be restricted by specifying the correct flags in options.
232 devfs_get_prom_names(const char *dev_name
, uint_t options
, char ***prom_list
)
234 char *prom_path
= NULL
;
235 int count
= 0; /* # of slots we will need in prom_list */
236 char **alias_list
= NULL
;
240 if (dev_name
== NULL
) {
241 return (DEVFS_INVAL
);
243 if (*dev_name
!= '/') {
244 return (DEVFS_INVAL
);
246 if (prom_list
== NULL
) {
247 return (DEVFS_INVAL
);
250 * make sure we are on a machine which supports a prom
251 * and we have permission to use /dev/openprom
253 if ((ret
= prom_obp_vers()) < 0) {
256 if ((prom_path
= (char *)malloc(MAXPATHLEN
)) == NULL
) {
257 return (DEVFS_NOMEM
);
260 * get the prom path name
262 ret
= devfs_dev_to_prom_name((char *)dev_name
, prom_path
);
267 /* get the list of aliases (exact and inexact) */
268 if ((ret
= prom_dev_to_alias(prom_path
, options
, &alias_list
)) < 0) {
272 /* now figure out how big the return array must be */
273 if (alias_list
!= NULL
) {
274 while (alias_list
[count
] != NULL
) {
278 if ((options
& BOOTDEV_NO_PROM_PATH
) == 0) {
279 count
++; /* # of slots we will need in prom_list */
281 count
++; /* for the null terminator */
283 /* allocate space for the list */
284 if ((list
= (char **)calloc(count
, sizeof (char *))) == NULL
) {
286 while ((alias_list
) && (alias_list
[count
] != NULL
)) {
287 free(alias_list
[count
]);
292 return (DEVFS_NOMEM
);
294 /* fill in the array and free the name list of aliases. */
296 while ((alias_list
) && (alias_list
[count
] != NULL
)) {
297 list
[count
] = alias_list
[count
];
300 if ((options
& BOOTDEV_NO_PROM_PATH
) == 0) {
301 list
[count
] = prom_path
;
303 if (alias_list
!= NULL
) {
311 * Get a list prom-path translations for a solaris device.
313 * Returns the number of and all OBP paths and alias variants that
314 * reference the Solaris device path passed in.
317 devfs_get_all_prom_names(const char *solaris_path
, uint_t flags
,
318 struct devfs_prom_path
**paths
)
320 int ret
, len
, i
, count
= 0;
321 char *ptr
, *prom_path
;
322 struct devfs_prom_path
*cur
= NULL
, *new;
324 if ((ret
= prom_obp_vers()) < 0)
326 if ((prom_path
= (char *)malloc(MAXVALSIZE
)) == NULL
)
327 return (DEVFS_NOMEM
);
329 if ((ret
= devfs_dev_to_prom_names((char *)solaris_path
,
330 prom_path
, MAXVALSIZE
)) < 0) {
335 for (i
= 0; i
< ret
; i
++)
336 if (prom_path
[i
] == '\0')
341 for (i
= 0; i
< count
; i
++) {
342 if ((new = (struct devfs_prom_path
*)calloc(
343 sizeof (struct devfs_prom_path
), 1)) == NULL
) {
345 devfs_free_all_prom_names(*paths
);
346 return (DEVFS_NOMEM
);
355 len
= strlen(ptr
) + 1;
356 if ((cur
->obp_path
= (char *)calloc(len
, 1)) == NULL
) {
358 devfs_free_all_prom_names(*paths
);
359 return (DEVFS_NOMEM
);
362 (void) snprintf(cur
->obp_path
, len
, "%s", ptr
);
364 if ((ret
= prom_dev_to_alias(cur
->obp_path
, flags
,
365 &(cur
->alias_list
))) < 0) {
367 devfs_free_all_prom_names(*paths
);
377 devfs_free_all_prom_names(struct devfs_prom_path
*paths
)
384 devfs_free_all_prom_names(paths
->next
);
386 if (paths
->obp_path
!= NULL
)
387 free(paths
->obp_path
);
389 if (paths
->alias_list
!= NULL
) {
390 for (i
= 0; paths
->alias_list
[i
] != NULL
; i
++)
391 if (paths
->alias_list
[i
] != NULL
)
392 free(paths
->alias_list
[i
]);
394 free(paths
->alias_list
);
401 * Accepts a device name as an input argument. Uses this to set the
402 * boot-device (or like) variable
404 * By default, this routine prepends to the list and converts the
405 * logical device name to its most compact prom representation.
406 * Available options include: converting the device name to a prom
407 * path name (but not an alias) or performing no conversion at all;
408 * overwriting the existing contents of boot-device rather than
412 devfs_bootdev_set_list(const char *dev_name
, const uint_t options
)
417 char **alias_list
= NULL
;
418 char **prom_list
= NULL
;
420 struct openpromio
*opp
= &(oppbuf
.opp
);
423 if (devfs_bootdev_modifiable() != 0) {
424 return (DEVFS_NOTSUP
);
426 if (dev_name
== NULL
) {
427 return (DEVFS_INVAL
);
429 if (strlen(dev_name
) >= MAXPATHLEN
)
430 return (DEVFS_INVAL
);
432 if ((*dev_name
!= '/') && !(options
& BOOTDEV_LITERAL
)) {
433 return (DEVFS_INVAL
);
435 if ((options
& BOOTDEV_LITERAL
) && (options
& BOOTDEV_PROMDEV
)) {
436 return (DEVFS_INVAL
);
439 * if we are prepending, make sure that this obp rev
440 * supports multiple boot device entries.
442 ret
= prom_obp_vers();
447 if ((prom_path
= (char *)malloc(MAXVALSIZE
)) == NULL
) {
448 return (DEVFS_NOMEM
);
450 if (options
& BOOTDEV_LITERAL
) {
451 (void) strcpy(prom_path
, dev_name
);
453 /* need to convert to prom representation */
454 ret
= devfs_get_prom_name_list(dev_name
, &prom_list
);
463 while (prom_list
&& prom_list
[i
]) {
464 if (!(options
& BOOTDEV_PROMDEV
)) {
465 ret
= prom_dev_to_alias(prom_list
[i
], 0,
469 prom_list_free(prom_list
);
472 if ((alias_list
!= NULL
) &&
473 (alias_list
[0] != NULL
)) {
474 (void) snprintf(ptr
, len
, "%s ",
476 for (ret
= 0; alias_list
[ret
] != NULL
;
478 free(alias_list
[ret
]);
480 (void) snprintf(ptr
, len
, "%s ",
483 if (alias_list
!= NULL
)
486 (void) snprintf(ptr
, len
, "%s ", prom_list
[i
]);
496 prom_list_free(prom_list
);
498 if (options
& BOOTDEV_OVERWRITE
) {
499 new_bootdev
= prom_path
;
501 /* retrieve the current value of boot-device */
502 ret
= get_boot_dev_var(opp
);
507 /* prepend new entry - deal with duplicates */
508 new_bootdev
= (char *)malloc(strlen(opp
->oprom_array
)
509 + strlen(prom_path
) + 2);
510 if (new_bootdev
== NULL
) {
512 return (DEVFS_NOMEM
);
514 (void) strcpy(new_bootdev
, prom_path
);
515 if (opp
->oprom_size
> 0) {
516 for (ptr
= strtok(opp
->oprom_array
, " "); ptr
!= NULL
;
517 ptr
= strtok(NULL
, " ")) {
518 /* we strip out duplicates */
519 if (strcmp(prom_path
, ptr
) == 0) {
522 (void) strcat(new_bootdev
, " ");
523 (void) strcat(new_bootdev
, ptr
);
528 /* now set the new value */
529 ret
= set_boot_dev_var(opp
, new_bootdev
);
531 if (options
& BOOTDEV_OVERWRITE
) {
542 * sets the string bootdev as the new value for boot-device
545 set_boot_dev_var(struct openpromio
*opp
, char *bootdev
)
552 char *bootdev_variables
[] = {
559 int *ip
= (int *)((void *)opp
->oprom_array
);
562 prom_fd
= prom_open(O_RDWR
);
567 /* get the diagnostic-mode? property */
568 (void) strcpy(opp
->oprom_array
, "diagnostic-mode?");
569 opp
->oprom_size
= MAXVALSIZE
;
570 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
571 if ((opp
->oprom_size
> 0) &&
572 (strcmp(opp
->oprom_array
, "true") == 0)) {
577 /* get the diag-switch? property */
578 (void) strcpy(opp
->oprom_array
, "diag-switch?");
579 opp
->oprom_size
= MAXVALSIZE
;
580 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
581 if ((opp
->oprom_size
> 0) &&
582 (strcmp(opp
->oprom_array
, "true") == 0)) {
588 * look for one of the following properties in order:
593 * Use the first one that we find.
596 opp
->oprom_size
= MAXPROPSIZE
;
597 while ((opp
->oprom_size
!= 0) && (!found
)) {
598 opp
->oprom_size
= MAXPROPSIZE
;
599 if (ioctl(prom_fd
, OPROMNXTOPT
, opp
) < 0) {
602 for (i
= 0; bootdev_variables
[i
] != NULL
; i
++) {
603 if (strcmp(opp
->oprom_array
, bootdev_variables
[i
])
611 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
612 opp
->oprom_size
= MAXVALSIZE
;
613 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) < 0) {
615 return (DEVFS_NOTSUP
);
619 return (DEVFS_NOTSUP
);
622 /* save the old copy in case we fail */
623 if ((save_bootdev
= strdup(opp
->oprom_array
)) == NULL
) {
625 return (DEVFS_NOMEM
);
627 /* set up the new value of boot-device */
628 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
629 valbuf
= opp
->oprom_array
+ strlen(opp
->oprom_array
) + 1;
630 (void) strcpy(valbuf
, bootdev
);
632 opp
->oprom_size
= strlen(valbuf
) + strlen(opp
->oprom_array
) + 2;
634 if (ioctl(prom_fd
, OPROMSETOPT
, opp
) < 0) {
641 * now read it back to make sure it took
643 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
644 opp
->oprom_size
= MAXVALSIZE
;
645 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
646 if (_prom_strcmp(opp
->oprom_array
, bootdev
) == 0) {
652 /* deal with setting it to "" */
653 if ((strlen(bootdev
) == 0) && (opp
->oprom_size
== 0)) {
661 * something did not take - write out the old value and
662 * hope that we can restore things...
664 * unfortunately, there is no way for us to differentiate
665 * whether we exceeded the maximum number of characters
666 * allowable. The limit varies from prom rev to prom
667 * rev, and on some proms, when the limit is
668 * exceeded, whatever was in the
669 * boot-device variable becomes unreadable.
671 * so if we fail, we will assume we ran out of room. If we
672 * not able to restore the original setting, then we will
673 * return DEVFS_ERR instead.
676 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
677 valbuf
= opp
->oprom_array
+ strlen(opp
->oprom_array
) + 1;
678 (void) strcpy(valbuf
, save_bootdev
);
680 opp
->oprom_size
= strlen(valbuf
) + strlen(opp
->oprom_array
) + 2;
682 if (ioctl(prom_fd
, OPROMSETOPT
, opp
) < 0) {
690 * retrieve the current value for boot-device
693 get_boot_dev_var(struct openpromio
*opp
)
697 char *bootdev_variables
[] = {
704 int *ip
= (int *)((void *)opp
->oprom_array
);
707 prom_fd
= prom_open(O_RDONLY
);
712 /* get the diagnostic-mode? property */
713 (void) strcpy(opp
->oprom_array
, "diagnostic-mode?");
714 opp
->oprom_size
= MAXVALSIZE
;
715 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
716 if ((opp
->oprom_size
> 0) &&
717 (strcmp(opp
->oprom_array
, "true") == 0)) {
722 /* get the diag-switch? property */
723 (void) strcpy(opp
->oprom_array
, "diag-switch?");
724 opp
->oprom_size
= MAXVALSIZE
;
725 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) >= 0) {
726 if ((opp
->oprom_size
> 0) &&
727 (strcmp(opp
->oprom_array
, "true") == 0)) {
733 * look for one of the following properties in order:
738 * Use the first one that we find.
741 opp
->oprom_size
= MAXPROPSIZE
;
742 while ((opp
->oprom_size
!= 0) && (!found
)) {
743 opp
->oprom_size
= MAXPROPSIZE
;
744 if (ioctl(prom_fd
, OPROMNXTOPT
, opp
) < 0) {
747 for (i
= 0; bootdev_variables
[i
] != NULL
; i
++) {
748 if (strcmp(opp
->oprom_array
, bootdev_variables
[i
])
756 (void) strcpy(opp
->oprom_array
, bootdev_variables
[i
]);
757 opp
->oprom_size
= MAXVALSIZE
;
758 if (ioctl(prom_fd
, OPROMGETOPT
, opp
) < 0) {
762 /* boot-device exists but contains nothing */
763 if (opp
->oprom_size
== 0) {
764 *opp
->oprom_array
= '\0';
768 return (DEVFS_NOTSUP
);
781 /* make sure we have a map file */
782 fp
= fopen(GRUBDISK_MAP
, "r");
784 (void) snprintf(cmd
, sizeof (cmd
),
785 "%s > /dev/null", CREATE_DISKMAP
);
787 fp
= fopen(GRUBDISK_MAP
, "r");
793 find_x86_boot_device(struct openpromio
*opp
)
796 char *cp
, line
[MAXVALSIZE
+ 6];
799 file
= open_diskmap();
803 while (fgets(line
, MAXVALSIZE
+ 6, file
)) {
804 if (strncmp(line
, "0 ", 2) != 0)
807 line
[strlen(line
) - 1] = '\0';
809 * an x86 BIOS only boots a disk, not a partition
810 * or a slice, so hard-code :q (p0)
812 cp
= strchr(line
+ 2, ' ');
815 (void) snprintf(opp
->oprom_array
, MAXVALSIZE
,
817 opp
->oprom_size
= MAXVALSIZE
;
824 #endif /* ndef __sparc */
827 * retrieve the list of entries in the boot-device configuration
828 * variable. An array of boot_dev structs will be created, one entry
829 * for each device name in the boot-device variable. Each entry
830 * in the array will contain the logical device representation of the
831 * boot-device entry, if any.
833 * default_root. if set, is used to locate logical device entries in
834 * directories other than /dev
837 devfs_bootdev_get_list(const char *default_root
,
838 struct boot_dev
***bootdev_list
)
841 struct openpromio
*opp
= &(oppbuf
.opp
);
843 struct boot_dev
**tmp_list
;
845 if (default_root
== NULL
) {
847 } else if (*default_root
!= '/') {
848 return (DEVFS_INVAL
);
851 if (bootdev_list
== NULL
) {
852 return (DEVFS_INVAL
);
855 /* get the boot-device variable */
857 i
= get_boot_dev_var(opp
);
859 i
= find_x86_boot_device(opp
);
864 /* now try to translate each entry to a logical device. */
865 i
= process_bootdev(opp
->oprom_array
, default_root
, &tmp_list
);
867 *bootdev_list
= tmp_list
;
875 * loop thru the list of entries in a boot-device configuration
879 process_bootdev(const char *bootdevice
, const char *default_root
,
880 struct boot_dev
***list
)
884 char prom_path
[MAXPATHLEN
];
885 char ret_buf
[MAXPATHLEN
];
886 struct boot_dev
**bootdev_array
;
891 if ((entry
= (char *)malloc(strlen(bootdevice
) + 1)) == NULL
) {
892 return (DEVFS_NOMEM
);
894 /* count the number of entries */
895 (void) strcpy(entry
, bootdevice
);
896 for (ptr
= strtok(entry
, " "); ptr
!= NULL
;
897 ptr
= strtok(NULL
, " ")) {
900 (void) strcpy(entry
, bootdevice
);
902 bootdev_array
= (struct boot_dev
**)
903 calloc((size_t)num_entries
+ 1, sizeof (struct boot_dev
*));
905 if (bootdev_array
== NULL
) {
907 return (DEVFS_NOMEM
);
910 vers
= prom_obp_vers();
916 /* for each entry in boot-device, do... */
917 for (ptr
= strtok(entry
, " "), i
= 0; ptr
!= NULL
;
918 ptr
= strtok(NULL
, " "), i
++) {
920 if ((bootdev_array
[i
] = alloc_bootdev(ptr
)) == NULL
) {
921 devfs_bootdev_free_list(bootdev_array
);
923 return (DEVFS_NOMEM
);
927 * prom boot-device may be aliased, so we need to do
928 * the necessary prom alias to dev translation.
931 if (alias_to_prom_dev(ptr
, prom_path
) < 0) {
935 (void) strcpy(prom_path
, ptr
);
938 /* now we have a prom device path - convert to a devfs name */
939 if (devfs_prom_to_dev_name(prom_path
, ret_buf
) < 0) {
943 /* append any default minor names necessary */
944 if (process_minor_name(ret_buf
, default_root
) < 0) {
950 * store the physical device path for now - when
951 * we are all done with the entries, we will convert
952 * these to their logical device name equivalents
954 bootdev_array
[i
]->bootdev_trans
[0] = strdup(ret_buf
);
957 * Convert all of the boot-device entries that translated to a
958 * physical device path in /devices to a logical device path
959 * in /dev (note that there may be several logical device paths
960 * associated with a single physical device path - return them all
963 if (devfs_phys_to_logical(bootdev_array
, num_entries
,
965 devfs_bootdev_free_list(bootdev_array
);
966 bootdev_array
= NULL
;
970 *list
= bootdev_array
;
975 * We may get a device path from the prom that has no minor name
976 * information included in it. Since this device name will not
977 * correspond directly to a physical device in /devices, we do our
978 * best to append what the default minor name should be and try this.
980 * For sparc: we append slice 0 (:a).
981 * For x86: we append fdisk partition 0 (:q).
984 process_minor_name(char *dev_path
, const char *root
)
988 const char *default_minor_name
= "a";
990 const char *default_minor_name
= "q";
993 struct stat stat_buf
;
994 char path
[MAXPATHLEN
];
996 (void) snprintf(path
, sizeof (path
), "%s%s%s", root
, DEVICES
, dev_path
);
998 * if the device file already exists as given to us, there
999 * is nothing to do but return.
1001 if (stat(path
, &stat_buf
) == 0) {
1005 * if there is no ':' after the last '/' character, or if there is
1006 * a ':' with no specifier, append the default segment specifier
1007 * ; if there is a ':' followed by a digit, this indicates
1008 * a partition number (which does not map into the /devices name
1009 * space), so strip the number and replace it with the letter
1010 * that represents the partition index
1012 if ((cp
= strrchr(dev_path
, '/')) != NULL
) {
1013 if ((cp
= strchr(cp
, ':')) == NULL
) {
1014 (void) strcat(dev_path
, ":");
1015 (void) strcat(dev_path
, default_minor_name
);
1016 } else if (*++cp
== '\0') {
1017 (void) strcat(dev_path
, default_minor_name
);
1018 } else if (isdigit(*cp
)) {
1020 /* make sure to squash the digit */
1023 case 0: (void) strcat(dev_path
, "q");
1025 case 1: (void) strcat(dev_path
, "r");
1027 case 2: (void) strcat(dev_path
, "s");
1029 case 3: (void) strcat(dev_path
, "t");
1031 case 4: (void) strcat(dev_path
, "u");
1033 default: (void) strcat(dev_path
, "a");
1039 * see if we can find something now.
1041 (void) snprintf(path
, sizeof (path
), "%s%s%s", root
, DEVICES
, dev_path
);
1043 if (stat(path
, &stat_buf
) == 0) {
1051 * for each entry in bootdev_array, convert the physical device
1052 * representation of the boot-device entry to one or more logical device
1053 * entries. We use the hammer method - walk through the logical device
1054 * name space looking for matches (/dev). We use nftw to do this.
1057 devfs_phys_to_logical(struct boot_dev
**bootdev_array
, const int array_size
,
1058 const char *default_root
)
1060 int walk_flags
= FTW_PHYS
| FTW_MOUNT
;
1062 struct name_list
*list
;
1064 char **dev_name_array
;
1065 size_t default_root_len
;
1066 char *dev_dir
= DEV
;
1069 if (array_size
< 0) {
1073 if (bootdev_array
== NULL
) {
1076 if (default_root
== NULL
) {
1079 default_root_len
= strlen(default_root
);
1080 if ((default_root_len
!= 0) && (*default_root
!= '/')) {
1084 /* short cut for an empty array */
1085 if (*bootdev_array
== NULL
) {
1089 /* tell nftw where to start (default: /dev) */
1090 len
= default_root_len
+ strlen(dev_dir
) + 1;
1091 if ((full_path
= (char *)malloc(len
)) == NULL
) {
1096 * if the default root path is terminated with a /, we have to
1097 * make sure we don't end up with one too many slashes in the
1098 * path we are building.
1100 if ((default_root_len
> (size_t)0) &&
1101 (default_root
[default_root_len
- 1] == '/')) {
1102 (void) snprintf(full_path
, len
, "%s%s", default_root
,
1105 (void) snprintf(full_path
, len
, "%s%s", default_root
, dev_dir
);
1109 * we need to muck with global data to make nftw work
1110 * so single thread access
1112 (void) mutex_lock(&dev_lists_lk
);
1115 * set the global vars bootdev_list and dev_list for use by nftw
1116 * dev_list is an array of lists - one for each boot-device
1117 * entry. The nftw function will create a list of logical device
1118 * entries for each boot-device and put all of the lists in
1121 dev_list
= (struct name_list
**)
1122 calloc(array_size
, sizeof (struct name_list
*));
1123 if (dev_list
== NULL
) {
1125 (void) mutex_unlock(&dev_lists_lk
);
1128 bootdev_list
= bootdev_array
;
1130 if (nftw(full_path
, check_logical_dev
, FT_DEPTH
, walk_flags
) == -1) {
1131 bootdev_list
= NULL
;
1133 for (i
= 0; i
< array_size
; i
++) {
1134 free_name_list(dev_list
[i
], 1);
1136 /* don't free dev_list here because it's been handed off */
1138 (void) mutex_unlock(&dev_lists_lk
);
1143 * now we have a filled in dev_list. So for each logical device
1144 * list in dev_list, count the number of entries in the list,
1145 * create an array of strings of logical devices, and save in the
1146 * corresponding boot_dev structure.
1148 for (i
= 0; i
< array_size
; i
++) {
1149 /* get the next list */
1153 /* count the number of entries in the list */
1154 while (list
!= NULL
) {
1158 if ((dev_name_array
=
1159 (char **)malloc((count
+ 1) * sizeof (char *)))
1166 /* fill in the array */
1167 while (list
!= NULL
) {
1168 dev_name_array
[count
] = list
->name
;
1174 * null terminate the array
1176 dev_name_array
[count
] = NULL
;
1177 if ((bootdev_array
[i
] != NULL
) && (bootdev_array
[i
]->
1178 bootdev_trans
[0] != NULL
)) {
1179 free(bootdev_array
[i
]->bootdev_trans
[0]);
1181 if (bootdev_array
[i
] != NULL
) {
1182 free(bootdev_array
[i
]->bootdev_trans
);
1183 bootdev_array
[i
]->bootdev_trans
= dev_name_array
;
1186 bootdev_list
= NULL
;
1188 for (i
= 0; i
< array_size
; i
++) {
1189 free_name_list(dev_list
[i
], 0);
1193 (void) mutex_unlock(&dev_lists_lk
);
1198 * for a logical dev entry, it walks the list of boot-devices and
1199 * sees if there are any matches. If so, it saves the logical device
1200 * name off in the appropriate list in dev_list
1204 check_logical_dev(const char *node
, const struct stat
*node_stat
, int flags
,
1205 struct FTW
*ftw_info
)
1207 char link_buf
[MAXPATHLEN
];
1210 struct name_list
*dev
;
1214 if (flags
!= FTW_SL
) {
1218 if ((link_buf_len
= readlink(node
, (void *)link_buf
, MAXPATHLEN
))
1222 link_buf
[link_buf_len
] = '\0';
1223 if ((name
= strstr(link_buf
, DEVICES
)) == NULL
) {
1226 name
= (char *)(name
+ strlen(DEVICES
));
1228 for (i
= 0; bootdev_list
[i
] != NULL
; i
++) {
1229 if (bootdev_list
[i
]->bootdev_trans
[0] == NULL
) {
1233 * compare the contents of the link with the physical
1234 * device representation of this boot device
1236 physdev
= bootdev_list
[i
]->bootdev_trans
[0];
1237 if ((strcmp(name
, physdev
) == 0) &&
1238 (strlen(name
) == strlen(physdev
))) {
1239 if ((dev
= (struct name_list
*)
1240 malloc(sizeof (struct name_list
))) == NULL
) {
1243 if ((dev
->name
= strdup(node
)) == NULL
) {
1247 if (dev_list
[i
] == NULL
) {
1249 dev_list
[i
]->next
= NULL
;
1251 dev
->next
= dev_list
[i
];
1260 * frees a list of boot_dev struct pointers
1263 devfs_bootdev_free_list(struct boot_dev
**array
)
1268 if (array
== NULL
) {
1272 while (array
[i
] != NULL
) {
1273 free(array
[i
]->bootdev_element
);
1275 while (array
[i
]->bootdev_trans
[j
] != NULL
) {
1276 free(array
[i
]->bootdev_trans
[j
++]);
1278 free(array
[i
]->bootdev_trans
);
1285 * allocates a boot_dev struct and fills in the bootdev_element portion
1287 static struct boot_dev
*
1288 alloc_bootdev(char *entry_name
)
1290 struct boot_dev
*entry
;
1292 entry
= (struct boot_dev
*)calloc(1, sizeof (struct boot_dev
));
1294 if (entry
== NULL
) {
1297 if ((entry
->bootdev_element
= strdup(entry_name
)) == NULL
) {
1302 * Allocate room for 1 name and a null terminator - the caller of
1303 * this function will need the first slot right away.
1305 if ((entry
->bootdev_trans
= (char **)calloc(2, sizeof (char *)))
1307 free(entry
->bootdev_element
);
1315 * will come back with a concatenated list of paths
1318 devfs_dev_to_prom_names(char *dev_path
, char *prom_path
, size_t len
)
1321 struct openpromio
*opp
= &(oppbuf
.opp
);
1323 int ret
= DEVFS_INVAL
;
1326 if (prom_path
== NULL
) {
1327 return (DEVFS_INVAL
);
1329 if (dev_path
== NULL
) {
1330 return (DEVFS_INVAL
);
1332 if (strlen(dev_path
) >= MAXPATHLEN
)
1333 return (DEVFS_INVAL
);
1335 if (*dev_path
!= '/')
1336 return (DEVFS_INVAL
);
1338 prom_fd
= prom_open(O_RDONLY
);
1343 /* query the prom */
1344 (void) snprintf(opp
->oprom_array
, MAXVALSIZE
, "%s", dev_path
);
1345 opp
->oprom_size
= MAXVALSIZE
;
1347 if (ioctl(prom_fd
, OPROMDEV2PROMNAME
, opp
) == 0) {
1348 prom_close(prom_fd
);
1350 /* return the prom path in prom_path */
1352 i
= len
- opp
->oprom_size
;
1354 bcopy(opp
->oprom_array
, prom_path
, len
);
1355 prom_path
[len
- 1] = NULL
;
1358 bcopy(opp
->oprom_array
, prom_path
, len
);
1359 return (opp
->oprom_size
);
1363 * either the prom does not support this ioctl or the argument
1366 if (errno
== ENXIO
) {
1369 prom_close(prom_fd
);
1374 * Convert a physical or logical device name to a name the prom would
1375 * understand. Fail if this platform does not support a prom or if
1376 * the device does not correspond to a valid prom device.
1377 * dev_path should be the name of a device in the logical or
1378 * physical device namespace.
1379 * prom_path is the prom version of the device name
1380 * prom_path must be large enough to contain the result and is
1381 * supplied by the user.
1383 * This routine only supports converting leaf device paths
1386 devfs_dev_to_prom_name(char *dev_path
, char *prom_path
)
1390 rval
= devfs_dev_to_prom_names(dev_path
, prom_path
, MAXPATHLEN
);
1399 * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs
1400 * path to a driver name.
1401 * devfs_path - the pathname of interest. This must be the physcical device
1402 * path with the mount point prefix (ie. /devices) stripped off.
1403 * drv_buf - user supplied buffer - the driver name will be stored here.
1405 * If the prom lookup fails, we return the name of the last component in
1406 * the pathname. This routine is useful for looking up driver names
1407 * associated with generically named devices.
1409 * This routine returns driver names that have aliases resolved.
1412 devfs_path_to_drv(char *devfs_path
, char *drv_buf
)
1415 struct openpromio
*opp
= &(oppbuf
.opp
);
1416 char *slash
, *colon
, *dev_addr
;
1417 char driver_path
[MAXPATHLEN
];
1420 if (drv_buf
== NULL
) {
1423 if (devfs_path
== NULL
) {
1427 if (strlen(devfs_path
) >= MAXPATHLEN
)
1430 if (*devfs_path
!= '/')
1434 /* strip off any minor node info at the end of the path */
1435 (void) strcpy(driver_path
, devfs_path
);
1436 slash
= strrchr(driver_path
, '/');
1439 colon
= strrchr(slash
, ':');
1443 /* query the prom */
1444 if ((prom_fd
= prom_open(O_RDONLY
)) >= 0) {
1445 (void) strcpy(opp
->oprom_array
, driver_path
);
1446 opp
->oprom_size
= MAXVALSIZE
;
1448 if (ioctl(prom_fd
, OPROMPATH2DRV
, opp
) == 0) {
1449 prom_close(prom_fd
);
1450 /* return the driver name in drv_buf */
1451 (void) strcpy(drv_buf
, opp
->oprom_array
);
1454 prom_close(prom_fd
);
1455 } else if (prom_fd
!= DEVFS_NOTSUP
)
1458 * If we get here, then either:
1459 * 1. this platform does not support an openprom driver
1460 * 2. we were asked to look up a device the prom does
1461 * not know about (e.g. a pseudo device)
1462 * In this case, we use the last component of the devfs path
1463 * name and try to derive the driver name
1466 /* use the last component of devfs_path as the driver name */
1467 if ((dev_addr
= strrchr(slash
, '@')) != NULL
)
1471 /* use opp->oprom_array as a buffer */
1472 (void) strcpy(opp
->oprom_array
, slash
);
1473 if (devfs_resolve_aliases(opp
->oprom_array
) == NULL
)
1475 (void) strcpy(drv_buf
, opp
->oprom_array
);
1480 * These modctl calls do the equivalent of:
1481 * ddi_name_to_major()
1482 * ddi_major_to_name()
1483 * This results in two things:
1484 * - the driver name must be a valid one
1485 * - any driver aliases are resolved.
1486 * drv is overwritten with the resulting name.
1489 devfs_resolve_aliases(char *drv
)
1492 char driver_name
[MAXNAMELEN
+ 1];
1498 if (modctl(MODGETMAJBIND
, drv
, strlen(drv
) + 1, &maj
) < 0)
1500 else if (modctl(MODGETNAME
, driver_name
, sizeof (driver_name
), &maj
)
1504 (void) strcpy(drv
, driver_name
);
1510 * open the openprom device. and verify that we are on an
1511 * OBP/1275 OF machine. If the prom does not exist, then we
1515 prom_open(int oflag
)
1518 char *promdev
= "/dev/openprom";
1520 while (prom_fd
< 0) {
1521 if ((prom_fd
= open(promdev
, oflag
)) < 0) {
1522 if (errno
== EAGAIN
) {
1526 if ((errno
== ENXIO
) || (errno
== ENOENT
)) {
1527 return (DEVFS_NOTSUP
);
1529 if ((errno
== EPERM
) || (errno
== EACCES
)) {
1530 return (DEVFS_PERM
);
1536 if (is_openprom(prom_fd
))
1539 prom_close(prom_fd
);
1545 prom_close(int prom_fd
)
1547 (void) close(prom_fd
);
1551 * is this an OBP/1275 OF machine?
1554 is_openprom(int prom_fd
)
1557 struct openpromio
*opp
= &(oppbuf
.opp
);
1560 opp
->oprom_size
= MAXVALSIZE
;
1561 if (ioctl(prom_fd
, OPROMGETCONS
, opp
) < 0)
1564 i
= (unsigned int)((unsigned char)opp
->oprom_array
[0]);
1565 return ((i
& OPROMCONS_OPENPROM
) == OPROMCONS_OPENPROM
);
1569 * convert a prom device path name to an equivalent physical device
1570 * path in the kernel.
1573 devfs_prom_to_dev_name(char *prom_path
, char *dev_path
)
1576 struct openpromio
*opp
= &(oppbuf
.opp
);
1578 int ret
= DEVFS_INVAL
;
1580 if (dev_path
== NULL
) {
1581 return (DEVFS_INVAL
);
1583 if (prom_path
== NULL
) {
1584 return (DEVFS_INVAL
);
1586 if (strlen(prom_path
) >= MAXPATHLEN
)
1587 return (DEVFS_INVAL
);
1589 if (*prom_path
!= '/') {
1590 return (DEVFS_INVAL
);
1593 /* query the prom */
1594 prom_fd
= prom_open(O_RDONLY
);
1598 (void) strcpy(opp
->oprom_array
, prom_path
);
1599 opp
->oprom_size
= MAXVALSIZE
;
1601 if (ioctl(prom_fd
, OPROMPROM2DEVNAME
, opp
) == 0) {
1602 prom_close(prom_fd
);
1605 * return the prom path in prom_path
1607 (void) strcpy(dev_path
, opp
->oprom_array
);
1611 * either the argument was not a valid name or the openprom
1612 * driver does not support this ioctl.
1614 if (errno
== ENXIO
) {
1617 prom_close(prom_fd
);
1621 * convert a prom device path to a list of equivalent alias names
1622 * If there is no alias node, or there are no aliases that correspond
1623 * to dev, we return empty lists.
1626 prom_dev_to_alias(char *dev
, uint_t options
, char ***ret_buf
)
1628 struct name_list
*exact_list
;
1629 struct name_list
*inexact_list
;
1630 struct name_list
*list
;
1637 vers
= prom_obp_vers();
1643 return (DEVFS_INVAL
);
1647 return (DEVFS_INVAL
);
1649 if (strlen(dev
) >= MAXPATHLEN
)
1650 return (DEVFS_INVAL
);
1652 if ((ptr
= strchr(dev
, ':')) != NULL
) {
1653 if (strchr(ptr
, '/') != NULL
)
1654 return (DEVFS_INVAL
);
1656 if (ret_buf
== NULL
) {
1657 return (DEVFS_INVAL
);
1660 prom_fd
= prom_open(O_RDONLY
);
1665 (void) prom_srch_aliases_by_def(dev
, &exact_list
,
1666 &inexact_list
, prom_fd
);
1668 prom_close(prom_fd
);
1670 if ((options
& BOOTDEV_NO_EXACT_ALIAS
) != 0) {
1671 free_name_list(exact_list
, 1);
1675 if ((options
& BOOTDEV_NO_INEXACT_ALIAS
) != 0) {
1676 free_name_list(inexact_list
, 1);
1677 inexact_list
= NULL
;
1682 while (list
!= NULL
) {
1686 list
= inexact_list
;
1687 while (list
!= NULL
) {
1692 if ((*ret_buf
= (char **)malloc((count
+ 1) * sizeof (char *)))
1694 free_name_list(inexact_list
, 1);
1695 free_name_list(exact_list
, 1);
1696 return (DEVFS_NOMEM
);
1702 while (list
!= NULL
) {
1703 array
[count
] = list
->name
;
1707 list
= inexact_list
;
1708 while (list
!= NULL
) {
1709 array
[count
] = list
->name
;
1713 array
[count
] = NULL
;
1714 free_name_list(inexact_list
, 0);
1715 free_name_list(exact_list
, 0);
1721 * determine the version of prom we are running on.
1722 * Also include any prom revision specific information.
1728 struct openpromio
*opp
= &(oppbuf
.opp
);
1730 static int version
= 0;
1737 prom_fd
= prom_open(O_RDONLY
);
1742 opp
->oprom_size
= MAXVALSIZE
;
1744 if ((ioctl(prom_fd
, OPROMGETVERSION
, opp
)) < 0) {
1745 prom_close(prom_fd
);
1748 prom_close(prom_fd
);
1755 * search the aliases node by definition - compile a list of
1756 * alias names that are both exact and inexact matches.
1759 prom_srch_aliases_by_def(char *promdev_def
, struct name_list
**exact_list
,
1760 struct name_list
**inexact_list
, int prom_fd
)
1763 Oppbuf propdef_oppbuf
;
1764 struct openpromio
*opp
= &(oppbuf
.opp
);
1765 struct openpromio
*propdef_opp
= &(propdef_oppbuf
.opp
);
1766 int *ip
= (int *)((void *)opp
->oprom_array
);
1768 struct name_list
*inexact_match
= *inexact_list
= NULL
;
1769 struct name_list
*exact_match
= *exact_list
= NULL
;
1770 char alias_buf
[MAXNAMELEN
];
1773 if ((ret
= prom_find_aliases_node(prom_fd
)) < 0)
1776 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
1777 opp
->oprom_size
= MAXPROPSIZE
;
1780 if ((ret
= ioctl(prom_fd
, OPROMNXTPROP
, opp
)) < 0)
1782 if (opp
->oprom_size
== 0)
1785 while ((ret
>= 0) && (opp
->oprom_size
> 0)) {
1786 (void) strcpy(propdef_opp
->oprom_array
, opp
->oprom_array
);
1787 opp
->oprom_size
= MAXPROPSIZE
;
1788 propdef_opp
->oprom_size
= MAXVALSIZE
;
1789 if ((ioctl(prom_fd
, OPROMGETPROP
, propdef_opp
) < 0) ||
1790 (propdef_opp
->oprom_size
== 0)) {
1791 ret
= ioctl(prom_fd
, OPROMNXTPROP
, opp
);
1794 ret
= prom_compare_devs(promdev_def
, propdef_opp
->oprom_array
);
1795 if (ret
== EXACT_MATCH
) {
1797 if (insert_alias_list(exact_list
, opp
->oprom_array
)
1799 free_name_list(exact_match
, 1);
1800 free_name_list(inexact_match
, 1);
1804 if (ret
== INEXACT_MATCH
) {
1806 (void) strcpy(alias_buf
, opp
->oprom_array
);
1807 options_override(promdev_def
, alias_buf
);
1808 if (insert_alias_list(inexact_list
, alias_buf
)
1810 free_name_list(exact_match
, 1);
1811 free_name_list(inexact_match
, 1);
1815 ret
= ioctl(prom_fd
, OPROMNXTPROP
, opp
);
1825 * free a list of name_list structs and optionally
1826 * free the strings they contain.
1829 free_name_list(struct name_list
*list
, int free_name
)
1831 struct name_list
*next
= list
;
1833 while (next
!= NULL
) {
1843 * insert a new alias in a list of aliases - the list is sorted
1844 * in collating order (ignoring anything that comes after the
1848 insert_alias_list(struct name_list
**list
, char *alias_name
)
1850 struct name_list
*entry
= *list
;
1851 struct name_list
*new_entry
, *prev_entry
;
1853 char *colon1
, *colon2
;
1856 (struct name_list
*)malloc(sizeof (struct name_list
)))
1860 if ((new_entry
->name
= strdup(alias_name
)) == NULL
) {
1864 new_entry
->next
= NULL
;
1866 if (entry
== NULL
) {
1871 if ((colon1
= strchr(alias_name
, ':')) != NULL
) {
1875 while (entry
!= NULL
) {
1876 if ((colon2
= strchr(entry
->name
, ':')) != NULL
) {
1879 ret
= strcmp(alias_name
, entry
->name
);
1880 if (colon2
!= NULL
) {
1885 free(new_entry
->name
);
1887 if (colon1
!= NULL
) {
1893 new_entry
->next
= entry
;
1894 if (prev_entry
== NULL
) {
1895 /* in beginning of list */
1898 /* in middle of list */
1899 prev_entry
->next
= new_entry
;
1901 if (colon1
!= NULL
) {
1907 entry
= entry
->next
;
1909 /* at end of list */
1910 prev_entry
->next
= new_entry
;
1911 new_entry
->next
= NULL
;
1912 if (colon1
!= NULL
) {
1918 * append :x to alias_name to override any default minor name options
1921 options_override(char *prom_path
, char *alias_name
)
1925 if ((colon
= strrchr(alias_name
, ':')) != NULL
) {
1927 * XXX - should alias names in /aliases ever have a
1928 * : embedded in them?
1929 * If so we ignore it.
1934 if ((colon
= strrchr(prom_path
, ':')) != NULL
) {
1935 (void) strcat(alias_name
, colon
);
1940 * compare to prom device names.
1941 * if the device names are not fully qualified. we convert them -
1942 * we only do this as a last resort though since it requires
1943 * jumping into the kernel.
1946 prom_compare_devs(char *prom_dev1
, char *prom_dev2
)
1950 char *drvname1
, *addrname1
, *minorname1
;
1951 char *drvname2
, *addrname2
, *minorname2
;
1952 char component1
[MAXNAMELEN
], component2
[MAXNAMELEN
];
1953 char devname1
[MAXPATHLEN
], devname2
[MAXPATHLEN
];
1954 int unqualified_name
= 0;
1955 int error
= EXACT_MATCH
;
1957 char *wildcard
= ",0";
1962 if ((ptr1
== NULL
) || (*ptr1
!= '/')) {
1965 if ((ptr2
== NULL
) || (*ptr2
!= '/')) {
1970 * compare device names one component at a time.
1972 while ((ptr1
!= NULL
) && (ptr2
!= NULL
)) {
1973 *ptr1
= *ptr2
= '/';
1976 if ((ptr1
= strchr(dev1
, '/')) != NULL
)
1978 if ((ptr2
= strchr(dev2
, '/')) != NULL
)
1981 (void) strcpy(component1
, dev1
);
1982 (void) strcpy(component2
, dev2
);
1984 parse_name(component1
, &drvname1
, &addrname1
, &minorname1
);
1985 parse_name(component2
, &drvname2
, &addrname2
, &minorname2
);
1987 if ((drvname1
== NULL
) && (addrname1
== NULL
)) {
1992 if ((drvname2
== NULL
) && (addrname2
== NULL
)) {
1997 if (_prom_strcmp(drvname1
, drvname2
) != 0) {
2003 * a possible name is driver_name@address. The address
2004 * portion is optional (i.e. the name is not fully
2005 * qualified.). We have to deal with the case where
2006 * the component name is either driver_name or
2007 * driver_name@address
2009 if ((addrname1
== NULL
) ^ (addrname2
== NULL
)) {
2010 unqualified_name
= 1;
2011 } else if (addrname1
&&
2012 (_prom_strcmp(addrname1
, addrname2
) != 0)) {
2014 * check to see if appending a ",0" to the
2015 * shorter address causes a match to occur.
2018 len1
= strlen(addrname1
);
2019 len2
= strlen(addrname2
);
2020 if ((len1
< len2
) &&
2021 (strncmp(addrname1
, addrname2
, len1
) == 0) &&
2022 (strcmp(wildcard
, &addrname2
[len1
]) == 0)) {
2024 } else if ((len2
< len1
) &&
2025 (strncmp(addrname1
, addrname2
, len2
) == 0) &&
2026 (strcmp(wildcard
, &addrname1
[len2
]) == 0)) {
2035 * if either of the two device paths still has more components,
2036 * then we do not have a match.
2046 if (error
== NO_MATCH
) {
2051 * OK - we found a possible match but one or more of the
2052 * path components was not fully qualified (did not have any
2053 * address information. So we need to convert it to a form
2054 * that is fully qualified and then compare the resulting
2057 if (unqualified_name
!= 0) {
2058 if ((devfs_prom_to_dev_name(prom_dev1
, devname1
) < 0) ||
2059 (devfs_prom_to_dev_name(prom_dev2
, devname2
) < 0)) {
2062 if ((dev1
= strrchr(devname1
, ':')) != NULL
) {
2065 if ((dev2
= strrchr(devname2
, ':')) != NULL
) {
2068 if (strcmp(devname1
, devname2
) != 0) {
2073 * the resulting strings matched. If the minorname information
2074 * matches, then we have an exact match, otherwise an inexact match
2076 if (_prom_strcmp(minorname1
, minorname2
) == 0) {
2077 return (EXACT_MATCH
);
2079 return (INEXACT_MATCH
);
2084 * wrapper or strcmp - deals with null strings.
2087 _prom_strcmp(char *s1
, char *s2
)
2089 if ((s1
== NULL
) && (s2
== NULL
))
2091 if ((s1
== NULL
) && (s2
!= NULL
)) {
2094 if ((s1
!= NULL
) && (s2
== NULL
)) {
2097 return (strcmp(s1
, s2
));
2100 * break device@a,b:minor into components
2103 parse_name(char *name
, char **drvname
, char **addrname
, char **minorname
)
2107 cp
= *drvname
= name
;
2108 *addrname
= *minorname
= NULL
;
2112 while ((ch
= *cp
) != '\0') {
2120 *((*addrname
)-1) = '\0';
2123 *((*minorname
)-1) = '\0';
2128 * converts a prom alias to a prom device name.
2129 * if we find no matching device, then we fail since if were
2130 * given a valid alias, then by definition, there must be a
2131 * device pathname associated with it in the /aliases node.
2134 alias_to_prom_dev(char *alias
, char *ret_buf
)
2137 char alias_buf
[MAXNAMELEN
];
2138 char alias_def
[MAXPATHLEN
];
2139 char options
[16] = "";
2144 if (strchr(alias
, '/') != NULL
)
2145 return (DEVFS_INVAL
);
2147 if (strlen(alias
) > (MAXNAMELEN
- 1))
2148 return (DEVFS_INVAL
);
2150 if (ret_buf
== NULL
) {
2151 return (DEVFS_INVAL
);
2154 prom_fd
= prom_open(O_RDONLY
);
2159 (void) strlcpy(alias_buf
, alias
, sizeof (alias_buf
));
2162 * save off any options (minor name info) that is
2163 * explicitly called out in the alias name
2165 if ((options_ptr
= strchr(alias_buf
, ':')) != NULL
) {
2166 *options_ptr
= '\0';
2167 (void) strlcpy(options
, ++options_ptr
, sizeof (options
));
2172 ret
= prom_find_aliases_node(prom_fd
);
2175 * we loop because one alias may define another... we have
2176 * to work our way down to an actual device definition.
2178 for (i
= 0; i
<= 10; i
++) {
2179 ret
= prom_srch_node(prom_fd
, alias_buf
, alias_def
);
2183 (void) strlcpy(alias_buf
, alias_def
,
2184 sizeof (alias_buf
));
2185 if (*alias_def
== '/') {
2190 * save off any explicit options (minor name info)
2191 * if none has been encountered yet
2193 if (options_ptr
== NULL
) {
2194 options_ptr
= strchr(alias_buf
, ':');
2195 if (options_ptr
!= NULL
) {
2196 *options_ptr
= '\0';
2197 (void) strlcpy(options
, ++options_ptr
,
2203 prom_close(prom_fd
);
2210 (void) strlcpy(ret_buf
, alias_def
, MAXPATHLEN
);
2212 /* override minor name information */
2213 if (options_ptr
!= NULL
) {
2214 if ((options_ptr
= strrchr(ret_buf
, ':')) == NULL
) {
2215 (void) strcat(ret_buf
, ":");
2217 *(++options_ptr
) = '\0';
2219 (void) strcat(ret_buf
, options
);
2225 * search a prom node for a property name
2228 prom_srch_node(int fd
, char *prop_name
, char *ret_buf
)
2231 struct openpromio
*opp
= &(oppbuf
.opp
);
2232 int *ip
= (int *)((void *)opp
->oprom_array
);
2234 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
2235 opp
->oprom_size
= MAXPROPSIZE
;
2238 if (ioctl(fd
, OPROMNXTPROP
, opp
) < 0)
2240 if (opp
->oprom_size
== 0)
2243 while (strcmp(prop_name
, opp
->oprom_array
) != 0) {
2244 opp
->oprom_size
= MAXPROPSIZE
;
2245 if (ioctl(fd
, OPROMNXTPROP
, opp
) < 0)
2247 if (opp
->oprom_size
== 0)
2250 opp
->oprom_size
= MAXVALSIZE
;
2251 if (ioctl(fd
, OPROMGETPROP
, opp
) < 0)
2254 if (opp
->oprom_size
== 0)
2256 (void) strlcpy(ret_buf
, opp
->oprom_array
, MAXPATHLEN
);
2261 * return the aliases node.
2264 prom_find_aliases_node(int fd
)
2267 char buf
[MAXPATHLEN
];
2269 if ((child_id
= prom_next_node(fd
, 0)) == 0)
2271 if ((child_id
= prom_child_node(fd
, child_id
)) == 0)
2274 while (child_id
!= 0) {
2275 if (prom_srch_node(fd
, "name", buf
) == 0) {
2276 if (strcmp(buf
, "aliases") == 0) {
2280 child_id
= prom_next_node(fd
, child_id
);
2289 prom_next_node(int fd
, uint_t node_id
)
2292 struct openpromio
*opp
= &(oppbuf
.opp
);
2293 uint_t
*ip
= (uint_t
*)((void *)opp
->oprom_array
);
2295 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
2296 opp
->oprom_size
= MAXVALSIZE
;
2299 if (ioctl(fd
, OPROMNEXT
, opp
) < 0)
2302 return (*(uint_t
*)((void *)opp
->oprom_array
));
2309 prom_child_node(int fd
, uint_t node_id
)
2312 struct openpromio
*opp
= &(oppbuf
.opp
);
2313 uint_t
*ip
= (uint_t
*)((void *)opp
->oprom_array
);
2315 (void) memset(oppbuf
.buf
, 0, BUFSIZE
);
2316 opp
->oprom_size
= MAXVALSIZE
;
2319 if (ioctl(fd
, OPROMCHILD
, opp
) < 0)
2322 return (*(uint_t
*)((void *)opp
->oprom_array
));
2326 * only on sparc for now
2329 devfs_bootdev_modifiable(void)
2334 return (DEVFS_NOTSUP
);