Home | History | Annotate | Download | only in libdevinfo
      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 
     27 #include <stdio.h>
     28 #include <string.h>
     29 #include <strings.h>
     30 #include <unistd.h>
     31 #include <stdlib.h>
     32 #include <thread.h>
     33 #include <synch.h>
     34 #include <sys/types.h>
     35 #include <ctype.h>
     36 #include <sys/stat.h>
     37 #include <fcntl.h>
     38 #include <sys/modctl.h>
     39 #include <errno.h>
     40 #include <sys/openpromio.h>
     41 #include <ftw.h>
     42 #include <sys/ddi.h>
     43 #include <sys/sunddi.h>
     44 #include <limits.h>
     45 
     46 #include "device_info.h"
     47 
     48 /*
     49  * #define's
     50  */
     51 
     52 /* alias node searching return values */
     53 #define	NO_MATCH	-1
     54 #define	EXACT_MATCH	1
     55 #define	INEXACT_MATCH	2
     56 
     57 /* for prom io operations */
     58 #define	BUFSIZE		4096
     59 #define	MAXPROPSIZE	256
     60 #define	MAXVALSIZE	(BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
     61 
     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 */
     65 
     66 /* for nftw call */
     67 #define	FT_DEPTH	15
     68 
     69 /* default logical and physical device name space */
     70 #define	DEV	"/dev"
     71 #define	DEVICES	"/devices"
     72 
     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"
     76 
     77 /*
     78  * internal structure declarations
     79  */
     80 
     81 /* for prom io functions */
     82 typedef union {
     83 	char buf[BUFSIZE];
     84 	struct openpromio opp;
     85 } Oppbuf;
     86 
     87 /* used to manage lists of devices and aliases */
     88 struct name_list {
     89 	char *name;
     90 	struct name_list *next;
     91 };
     92 
     93 /*
     94  * internal global data
     95  */
     96 
     97 /* global since nftw does not let you pass args to be updated */
     98 static struct name_list **dev_list;
     99 
    100 /* global since nftw does not let you pass args to be updated */
    101 static struct boot_dev **bootdev_list;
    102 
    103 /* mutex to protect bootdev_list and dev_list */
    104 static mutex_t dev_lists_lk = DEFAULTMUTEX;
    105 
    106 /*
    107  * internal function prototypes
    108  */
    109 
    110 static int prom_open(int);
    111 static void prom_close(int);
    112 static int is_openprom(int);
    113 
    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);
    124 
    125 static int prom_obp_vers(void);
    126 
    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,
    134 	struct FTW *);
    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,
    138 	char *alias_name);
    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);
    143 
    144 /*
    145  * frees a list of paths from devfs_get_prom_name_list
    146  */
    147 static void
    148 prom_list_free(char **prom_list)
    149 {
    150 	int i = 0;
    151 
    152 	if (!prom_list)
    153 		return;
    154 
    155 	while (prom_list[i]) {
    156 		free(prom_list[i]);
    157 		i++;
    158 	}
    159 	free(prom_list);
    160 }
    161 
    162 static int
    163 devfs_get_prom_name_list(const char *dev_name, char ***prom_list)
    164 {
    165 	char *prom_path = NULL;
    166 	int count = 0;		/* # of slots we will need in prom_list */
    167 	int ret, i, len;
    168 	char **list;
    169 	char *ptr;
    170 
    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);
    177 
    178 	/*
    179 	 * make sure we are on a machine which supports a prom
    180 	 * and we have permission to use /dev/openprom
    181 	 */
    182 	if ((ret = prom_obp_vers()) < 0)
    183 		return (ret);
    184 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
    185 		return (DEVFS_NOMEM);
    186 	/*
    187 	 * get the prom path name
    188 	 */
    189 	ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE);
    190 	if (ret < 0) {
    191 		free(prom_path);
    192 		return (ret);
    193 	}
    194 	/* deal with list of names */
    195 	for (i = 0; i < ret; i++)
    196 		if (prom_path[i] == '\0')
    197 			count++;
    198 
    199 	if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) {
    200 		free(prom_path);
    201 		return (DEVFS_NOMEM);
    202 	}
    203 
    204 	ptr = prom_path;
    205 	for (i = 0; i < count; i++) {
    206 		len = strlen(ptr) + 1;
    207 		if ((list[i] = (char *)malloc(len)) == NULL) {
    208 			free(prom_path);
    209 			free(list);
    210 			return (DEVFS_NOMEM);
    211 		}
    212 		(void) snprintf(list[i], len, "%s", ptr);
    213 		ptr += len;
    214 	}
    215 
    216 	free(prom_path);
    217 
    218 	*prom_list = list;
    219 	return (0);
    220 }
    221 
    222 /*
    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
    228  *
    229  * the list may be restricted by specifying the correct flags in options.
    230  */
    231 int
    232 devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list)
    233 {
    234 	char *prom_path = NULL;
    235 	int count = 0;		/* # of slots we will need in prom_list */
    236 	char **alias_list = NULL;
    237 	char **list;
    238 	int ret;
    239 
    240 	if (dev_name == NULL) {
    241 		return (DEVFS_INVAL);
    242 	}
    243 	if (*dev_name != '/') {
    244 		return (DEVFS_INVAL);
    245 	}
    246 	if (prom_list == NULL) {
    247 		return (DEVFS_INVAL);
    248 	}
    249 	/*
    250 	 * make sure we are on a machine which supports a prom
    251 	 * and we have permission to use /dev/openprom
    252 	 */
    253 	if ((ret = prom_obp_vers()) < 0) {
    254 		return (ret);
    255 	}
    256 	if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) {
    257 		return (DEVFS_NOMEM);
    258 	}
    259 	/*
    260 	 * get the prom path name
    261 	 */
    262 	ret = devfs_dev_to_prom_name((char *)dev_name, prom_path);
    263 	if (ret < 0) {
    264 		free(prom_path);
    265 		return (ret);
    266 	}
    267 	/* get the list of aliases (exact and inexact) */
    268 	if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) {
    269 		free(prom_path);
    270 		return (ret);
    271 	}
    272 	/* now figure out how big the return array must be */
    273 	if (alias_list != NULL) {
    274 		while (alias_list[count] != NULL) {
    275 			count++;
    276 		}
    277 	}
    278 	if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
    279 		count++;	/* # of slots we will need in prom_list */
    280 	}
    281 	count++;	/* for the null terminator */
    282 
    283 	/* allocate space for the list */
    284 	if ((list = (char **)calloc(count, sizeof (char *))) == NULL) {
    285 		count = 0;
    286 		while ((alias_list) && (alias_list[count] != NULL)) {
    287 			free(alias_list[count]);
    288 			count++;
    289 		}
    290 		free(alias_list);
    291 		free(prom_path);
    292 		return (DEVFS_NOMEM);
    293 	}
    294 	/* fill in the array and free the name list of aliases. */
    295 	count = 0;
    296 	while ((alias_list) && (alias_list[count] != NULL)) {
    297 		list[count] = alias_list[count];
    298 		count++;
    299 	}
    300 	if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
    301 		list[count] = prom_path;
    302 	}
    303 	if (alias_list != NULL) {
    304 		free(alias_list);
    305 	}
    306 	*prom_list = list;
    307 	return (0);
    308 }
    309 
    310 /*
    311  * Get a list prom-path translations for a solaris device.
    312  *
    313  * Returns the number of and all OBP paths and alias variants that
    314  * reference the Solaris device path passed in.
    315  */
    316 int
    317 devfs_get_all_prom_names(const char *solaris_path, uint_t flags,
    318     struct devfs_prom_path **paths)
    319 {
    320 	int ret, len, i, count = 0;
    321 	char *ptr, *prom_path;
    322 	struct devfs_prom_path *cur = NULL, *new;
    323 
    324 	if ((ret = prom_obp_vers()) < 0)
    325 		return (ret);
    326 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
    327 		return (DEVFS_NOMEM);
    328 
    329 	if ((ret = devfs_dev_to_prom_names((char *)solaris_path,
    330 	    prom_path, MAXVALSIZE)) < 0) {
    331 		free(prom_path);
    332 		return (ret);
    333 	}
    334 
    335 	for (i = 0; i < ret; i++)
    336 		if (prom_path[i] == '\0')
    337 			count++;
    338 
    339 	*paths = NULL;
    340 	ptr = prom_path;
    341 	for (i = 0; i < count; i++) {
    342 		if ((new = (struct devfs_prom_path *)calloc(
    343 		    sizeof (struct devfs_prom_path), 1)) == NULL) {
    344 			free(prom_path);
    345 			devfs_free_all_prom_names(*paths);
    346 			return (DEVFS_NOMEM);
    347 		}
    348 
    349 		if (cur == NULL)
    350 			*paths = new;
    351 		else
    352 			cur->next = new;
    353 		cur = new;
    354 
    355 		len = strlen(ptr) + 1;
    356 		if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) {
    357 			free(prom_path);
    358 			devfs_free_all_prom_names(*paths);
    359 			return (DEVFS_NOMEM);
    360 		}
    361 
    362 		(void) snprintf(cur->obp_path, len, "%s", ptr);
    363 		ptr += len;
    364 		if ((ret = prom_dev_to_alias(cur->obp_path, flags,
    365 		    &(cur->alias_list))) < 0) {
    366 			free(prom_path);
    367 			devfs_free_all_prom_names(*paths);
    368 			return (ret);
    369 		}
    370 	}
    371 
    372 	free(prom_path);
    373 	return (count);
    374 }
    375 
    376 void
    377 devfs_free_all_prom_names(struct devfs_prom_path *paths)
    378 {
    379 	int i;
    380 
    381 	if (paths == NULL)
    382 		return;
    383 
    384 	devfs_free_all_prom_names(paths->next);
    385 
    386 	if (paths->obp_path != NULL)
    387 		free(paths->obp_path);
    388 
    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]);
    393 
    394 		free(paths->alias_list);
    395 	}
    396 
    397 	free(paths);
    398 }
    399 
    400 /*
    401  * Accepts a device name as an input argument.  Uses this to set the
    402  * boot-device (or like) variable
    403  *
    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
    409  * prepending.
    410  */
    411 int
    412 devfs_bootdev_set_list(const char *dev_name, const uint_t options)
    413 {
    414 	char *prom_path;
    415 	char *new_bootdev;
    416 	char *ptr;
    417 	char **alias_list = NULL;
    418 	char **prom_list = NULL;
    419 	Oppbuf  oppbuf;
    420 	struct openpromio *opp = &(oppbuf.opp);
    421 	int ret, len, i, j;
    422 
    423 	if (devfs_bootdev_modifiable() != 0) {
    424 		return (DEVFS_NOTSUP);
    425 	}
    426 	if (dev_name == NULL) {
    427 		return (DEVFS_INVAL);
    428 	}
    429 	if (strlen(dev_name) >= MAXPATHLEN)
    430 		return (DEVFS_INVAL);
    431 
    432 	if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) {
    433 		return (DEVFS_INVAL);
    434 	}
    435 	if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) {
    436 		return (DEVFS_INVAL);
    437 	}
    438 	/*
    439 	 * if we are prepending, make sure that this obp rev
    440 	 * supports multiple boot device entries.
    441 	 */
    442 	ret = prom_obp_vers();
    443 	if (ret < 0) {
    444 		return (ret);
    445 	}
    446 
    447 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) {
    448 		return (DEVFS_NOMEM);
    449 	}
    450 	if (options & BOOTDEV_LITERAL) {
    451 		(void) strcpy(prom_path, dev_name);
    452 	} else {
    453 		/* need to convert to prom representation */
    454 		ret = devfs_get_prom_name_list(dev_name, &prom_list);
    455 		if (ret < 0) {
    456 			free(prom_path);
    457 			return (ret);
    458 		}
    459 
    460 		len = MAXVALSIZE;
    461 		i = 0;
    462 		ptr = prom_path;
    463 		while (prom_list && prom_list[i]) {
    464 			if (!(options & BOOTDEV_PROMDEV)) {
    465 				ret = prom_dev_to_alias(prom_list[i], 0,
    466 				    &alias_list);
    467 				if (ret < 0) {
    468 					free(prom_path);
    469 					prom_list_free(prom_list);
    470 					return (ret);
    471 				}
    472 				if ((alias_list != NULL) &&
    473 				    (alias_list[0] != NULL)) {
    474 					(void) snprintf(ptr, len, "%s ",
    475 					    alias_list[0]);
    476 					for (ret = 0; alias_list[ret] != NULL;
    477 					    ret++)
    478 						free(alias_list[ret]);
    479 				} else {
    480 					(void) snprintf(ptr, len, "%s ",
    481 					    prom_list[i]);
    482 				}
    483 				if (alias_list != NULL)
    484 					free(alias_list);
    485 			} else {
    486 				(void) snprintf(ptr, len, "%s ", prom_list[i]);
    487 			}
    488 			j = strlen(ptr);
    489 			len -= j;
    490 			ptr += j;
    491 			i++;
    492 		}
    493 		ptr--;
    494 		*ptr = NULL;
    495 
    496 		prom_list_free(prom_list);
    497 	}
    498 	if (options & BOOTDEV_OVERWRITE) {
    499 		new_bootdev = prom_path;
    500 	} else {
    501 		/* retrieve the current value of boot-device */
    502 		ret = get_boot_dev_var(opp);
    503 		if (ret < 0) {
    504 			free(prom_path);
    505 			return (ret);
    506 		}
    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) {
    511 			free(prom_path);
    512 			return (DEVFS_NOMEM);
    513 		}
    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) {
    520 					continue;
    521 				}
    522 				(void) strcat(new_bootdev, " ");
    523 				(void) strcat(new_bootdev, ptr);
    524 			}
    525 		}
    526 	}
    527 
    528 	/* now set the new value */
    529 	ret = set_boot_dev_var(opp, new_bootdev);
    530 
    531 	if (options & BOOTDEV_OVERWRITE) {
    532 		free(prom_path);
    533 	} else {
    534 		free(new_bootdev);
    535 		free(prom_path);
    536 	}
    537 
    538 	return (ret);
    539 }
    540 
    541 /*
    542  * sets the string bootdev as the new value for boot-device
    543  */
    544 static int
    545 set_boot_dev_var(struct openpromio *opp, char *bootdev)
    546 {
    547 	int prom_fd;
    548 	int i;
    549 	int ret;
    550 	char *valbuf;
    551 	char *save_bootdev;
    552 	char *bootdev_variables[] = {
    553 		"boot-device",
    554 		"bootdev",
    555 		"boot-from",
    556 		NULL
    557 	};
    558 	int found = 0;
    559 	int *ip = (int *)((void *)opp->oprom_array);
    560 
    561 	/* query the prom */
    562 	prom_fd = prom_open(O_RDWR);
    563 	if (prom_fd < 0) {
    564 		return (prom_fd);
    565 	}
    566 
    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)) {
    573 			prom_close(prom_fd);
    574 			return (DEVFS_ERR);
    575 		}
    576 	}
    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)) {
    583 			prom_close(prom_fd);
    584 			return (DEVFS_ERR);
    585 		}
    586 	}
    587 	/*
    588 	 * look for one of the following properties in order:
    589 	 *	boot-device
    590 	 *	bootdev
    591 	 *	boot-from
    592 	 *
    593 	 * Use the first one that we find.
    594 	 */
    595 	*ip = 0;
    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) {
    600 			break;
    601 		}
    602 		for (i = 0; bootdev_variables[i] != NULL; i++) {
    603 			if (strcmp(opp->oprom_array, bootdev_variables[i])
    604 			    == 0) {
    605 				found = 1;
    606 				break;
    607 			}
    608 		}
    609 	}
    610 	if (found) {
    611 		(void) strcpy(opp->oprom_array, bootdev_variables[i]);
    612 		opp->oprom_size = MAXVALSIZE;
    613 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
    614 			prom_close(prom_fd);
    615 			return (DEVFS_NOTSUP);
    616 		}
    617 	} else {
    618 		prom_close(prom_fd);
    619 		return (DEVFS_NOTSUP);
    620 	}
    621 
    622 	/* save the old copy in case we fail */
    623 	if ((save_bootdev = strdup(opp->oprom_array)) == NULL) {
    624 		prom_close(prom_fd);
    625 		return (DEVFS_NOMEM);
    626 	}
    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);
    631 
    632 	opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
    633 
    634 	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
    635 		free(save_bootdev);
    636 		prom_close(prom_fd);
    637 		return (DEVFS_ERR);
    638 	}
    639 
    640 	/*
    641 	 * now read it back to make sure it took
    642 	 */
    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) {
    647 			/* success */
    648 			free(save_bootdev);
    649 			prom_close(prom_fd);
    650 			return (0);
    651 		}
    652 		/* deal with setting it to "" */
    653 		if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) {
    654 			/* success */
    655 			free(save_bootdev);
    656 			prom_close(prom_fd);
    657 			return (0);
    658 		}
    659 	}
    660 	/*
    661 	 * something did not take - write out the old value and
    662 	 * hope that we can restore things...
    663 	 *
    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.
    670 	 *
    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.
    674 	 */
    675 	ret = DEVFS_LIMIT;
    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);
    679 
    680 	opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
    681 
    682 	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
    683 		ret = DEVFS_ERR;
    684 	}
    685 	free(save_bootdev);
    686 	prom_close(prom_fd);
    687 	return (ret);
    688 }
    689 /*
    690  * retrieve the current value for boot-device
    691  */
    692 static int
    693 get_boot_dev_var(struct openpromio *opp)
    694 {
    695 	int prom_fd;
    696 	int i;
    697 	char *bootdev_variables[] = {
    698 		"boot-device",
    699 		"bootdev",
    700 		"boot-from",
    701 		NULL
    702 	};
    703 	int found = 0;
    704 	int *ip = (int *)((void *)opp->oprom_array);
    705 
    706 	/* query the prom */
    707 	prom_fd = prom_open(O_RDONLY);
    708 	if (prom_fd < 0) {
    709 		return (prom_fd);
    710 	}
    711 
    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)) {
    718 			prom_close(prom_fd);
    719 			return (DEVFS_ERR);
    720 		}
    721 	}
    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)) {
    728 			prom_close(prom_fd);
    729 			return (DEVFS_ERR);
    730 		}
    731 	}
    732 	/*
    733 	 * look for one of the following properties in order:
    734 	 *	boot-device
    735 	 *	bootdev
    736 	 *	boot-from
    737 	 *
    738 	 * Use the first one that we find.
    739 	 */
    740 	*ip = 0;
    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) {
    745 			break;
    746 		}
    747 		for (i = 0; bootdev_variables[i] != NULL; i++) {
    748 			if (strcmp(opp->oprom_array, bootdev_variables[i])
    749 			    == 0) {
    750 				found = 1;
    751 				break;
    752 			}
    753 		}
    754 	}
    755 	if (found) {
    756 		(void) strcpy(opp->oprom_array, bootdev_variables[i]);
    757 		opp->oprom_size = MAXVALSIZE;
    758 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
    759 			prom_close(prom_fd);
    760 			return (DEVFS_ERR);
    761 		}
    762 		/* boot-device exists but contains nothing */
    763 		if (opp->oprom_size == 0) {
    764 			*opp->oprom_array = '\0';
    765 		}
    766 	} else {
    767 		prom_close(prom_fd);
    768 		return (DEVFS_NOTSUP);
    769 	}
    770 	prom_close(prom_fd);
    771 	return (0);
    772 }
    773 
    774 #ifndef __sparc
    775 static FILE *
    776 open_diskmap(void)
    777 {
    778 	FILE *fp;
    779 	char cmd[PATH_MAX];
    780 
    781 	/* make sure we have a map file */
    782 	fp = fopen(GRUBDISK_MAP, "r");
    783 	if (fp == NULL) {
    784 		(void) snprintf(cmd, sizeof (cmd),
    785 		    "%s > /dev/null", CREATE_DISKMAP);
    786 		(void) system(cmd);
    787 		fp = fopen(GRUBDISK_MAP, "r");
    788 	}
    789 	return (fp);
    790 }
    791 
    792 static int
    793 find_x86_boot_device(struct openpromio *opp)
    794 {
    795 	int ret = DEVFS_ERR;
    796 	char *cp, line[MAXVALSIZE + 6];
    797 	FILE *file;
    798 
    799 	file = open_diskmap();
    800 	if (file == NULL)
    801 		return (DEVFS_ERR);
    802 
    803 	while (fgets(line, MAXVALSIZE + 6, file)) {
    804 		if (strncmp(line, "0 ", 2) != 0)
    805 			continue;
    806 		/* drop new-line */
    807 		line[strlen(line) - 1] = '\0';
    808 		/*
    809 		 * an x86 BIOS only boots a disk, not a partition
    810 		 * or a slice, so hard-code :q (p0)
    811 		 */
    812 		cp = strchr(line + 2, ' ');
    813 		if (cp == NULL)
    814 			break;
    815 		(void) snprintf(opp->oprom_array, MAXVALSIZE,
    816 		    "%s:q", cp + 1);
    817 		opp->oprom_size = MAXVALSIZE;
    818 		ret = 0;
    819 		break;
    820 	}
    821 	(void) fclose(file);
    822 	return (ret);
    823 }
    824 #endif /* ndef __sparc */
    825 
    826 /*
    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.
    832  *
    833  * default_root. if set, is used to locate logical device entries in
    834  * directories other than /dev
    835  */
    836 int
    837 devfs_bootdev_get_list(const char *default_root,
    838 	struct boot_dev ***bootdev_list)
    839 {
    840 	Oppbuf  oppbuf;
    841 	struct openpromio *opp = &(oppbuf.opp);
    842 	int i;
    843 	struct boot_dev **tmp_list;
    844 
    845 	if (default_root == NULL) {
    846 		default_root = "";
    847 	} else if (*default_root != '/') {
    848 		return (DEVFS_INVAL);
    849 	}
    850 
    851 	if (bootdev_list == NULL) {
    852 		return (DEVFS_INVAL);
    853 	}
    854 
    855 	/* get the boot-device variable */
    856 #if defined(sparc)
    857 	i = get_boot_dev_var(opp);
    858 #else
    859 	i = find_x86_boot_device(opp);
    860 #endif
    861 	if (i < 0) {
    862 		return (i);
    863 	}
    864 	/* now try to translate each entry to a logical device. */
    865 	i = process_bootdev(opp->oprom_array, default_root, &tmp_list);
    866 	if (i == 0) {
    867 		*bootdev_list = tmp_list;
    868 		return (0);
    869 	} else {
    870 		return (i);
    871 	}
    872 }
    873 
    874 /*
    875  * loop thru the list of entries in a boot-device configuration
    876  * variable.
    877  */
    878 static int
    879 process_bootdev(const char *bootdevice, const char *default_root,
    880 	struct boot_dev ***list)
    881 {
    882 	int i;
    883 	char *entry, *ptr;
    884 	char prom_path[MAXPATHLEN];
    885 	char ret_buf[MAXPATHLEN];
    886 	struct boot_dev **bootdev_array;
    887 	int num_entries = 0;
    888 	int found = 0;
    889 	int vers;
    890 
    891 	if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) {
    892 		return (DEVFS_NOMEM);
    893 	}
    894 	/* count the number of entries */
    895 	(void) strcpy(entry, bootdevice);
    896 	for (ptr = strtok(entry, " "); ptr != NULL;
    897 	    ptr = strtok(NULL, " ")) {
    898 		num_entries++;
    899 	}
    900 	(void) strcpy(entry, bootdevice);
    901 
    902 	bootdev_array = (struct boot_dev **)
    903 	    calloc((size_t)num_entries + 1, sizeof (struct boot_dev *));
    904 
    905 	if (bootdev_array == NULL) {
    906 		free(entry);
    907 		return (DEVFS_NOMEM);
    908 	}
    909 
    910 	vers = prom_obp_vers();
    911 	if (vers < 0) {
    912 		free(entry);
    913 		return (vers);
    914 	}
    915 
    916 	/* for each entry in boot-device, do... */
    917 	for (ptr = strtok(entry, " "), i = 0; ptr != NULL;
    918 	    ptr = strtok(NULL, " "), i++) {
    919 
    920 		if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) {
    921 			devfs_bootdev_free_list(bootdev_array);
    922 			free(entry);
    923 			return (DEVFS_NOMEM);
    924 		}
    925 
    926 		/*
    927 		 * prom boot-device may be aliased, so we need to do
    928 		 * the necessary prom alias to dev translation.
    929 		 */
    930 		if (*ptr != '/') {
    931 			if (alias_to_prom_dev(ptr, prom_path) < 0) {
    932 				continue;
    933 			}
    934 		} else {
    935 			(void) strcpy(prom_path, ptr);
    936 		}
    937 
    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) {
    940 			continue;
    941 		}
    942 
    943 		/* append any default minor names necessary */
    944 		if (process_minor_name(ret_buf, default_root) < 0) {
    945 			continue;
    946 		}
    947 		found = 1;
    948 
    949 		/*
    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
    953 		 */
    954 		bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf);
    955 	}
    956 	/*
    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
    961 	 */
    962 	if (found) {
    963 		if (devfs_phys_to_logical(bootdev_array, num_entries,
    964 		    default_root) < 0) {
    965 			devfs_bootdev_free_list(bootdev_array);
    966 			bootdev_array = NULL;
    967 		}
    968 	}
    969 	free(entry);
    970 	*list = bootdev_array;
    971 	return (0);
    972 }
    973 
    974 /*
    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.
    979  *
    980  * For sparc: we append slice 0 (:a).
    981  * For x86: we append fdisk partition 0 (:q).
    982  */
    983 static int
    984 process_minor_name(char *dev_path, const char *root)
    985 {
    986 	char *cp;
    987 #if defined(sparc)
    988 	const char *default_minor_name = "a";
    989 #else
    990 	const char *default_minor_name = "q";
    991 #endif
    992 	int n;
    993 	struct stat stat_buf;
    994 	char path[MAXPATHLEN];
    995 
    996 	(void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
    997 	/*
    998 	 * if the device file already exists as given to us, there
    999 	 * is nothing to do but return.
   1000 	 */
   1001 	if (stat(path, &stat_buf) == 0) {
   1002 		return (0);
   1003 	}
   1004 	/*
   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
   1011 	 */
   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)) {
   1019 			n = atoi(cp);
   1020 			/* make sure to squash the digit */
   1021 			*cp = '\0';
   1022 			switch (n) {
   1023 			case 0:	(void) strcat(dev_path, "q");
   1024 					break;
   1025 			case 1:	(void) strcat(dev_path, "r");
   1026 					break;
   1027 			case 2:	(void) strcat(dev_path, "s");
   1028 					break;
   1029 			case 3:	(void) strcat(dev_path, "t");
   1030 					break;
   1031 			case 4:	(void) strcat(dev_path, "u");
   1032 					break;
   1033 			default: (void) strcat(dev_path, "a");
   1034 					break;
   1035 			}
   1036 		}
   1037 	}
   1038 	/*
   1039 	 * see if we can find something now.
   1040 	 */
   1041 	(void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
   1042 
   1043 	if (stat(path, &stat_buf) == 0) {
   1044 		return (0);
   1045 	} else {
   1046 		return (-1);
   1047 	}
   1048 }
   1049 
   1050 /*
   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.
   1055  */
   1056 static int
   1057 devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size,
   1058     const char *default_root)
   1059 {
   1060 	int walk_flags = FTW_PHYS | FTW_MOUNT;
   1061 	char *full_path;
   1062 	struct name_list *list;
   1063 	int count, i;
   1064 	char **dev_name_array;
   1065 	size_t default_root_len;
   1066 	char *dev_dir = DEV;
   1067 	int len;
   1068 
   1069 	if (array_size < 0) {
   1070 		return (-1);
   1071 	}
   1072 
   1073 	if (bootdev_array == NULL) {
   1074 		return (-1);
   1075 	}
   1076 	if (default_root == NULL) {
   1077 		return (-1);
   1078 	}
   1079 	default_root_len = strlen(default_root);
   1080 	if ((default_root_len != 0) && (*default_root != '/')) {
   1081 		return (-1);
   1082 	}
   1083 
   1084 	/* short cut for an empty array */
   1085 	if (*bootdev_array == NULL) {
   1086 		return (0);
   1087 	}
   1088 
   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) {
   1092 		return (-1);
   1093 	}
   1094 
   1095 	/*
   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.
   1099 	 */
   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,
   1103 		    &dev_dir[1]);
   1104 	} else {
   1105 		(void) snprintf(full_path, len, "%s%s", default_root, dev_dir);
   1106 	}
   1107 
   1108 	/*
   1109 	 * we need to muck with global data to make nftw work
   1110 	 * so single thread access
   1111 	 */
   1112 	(void) mutex_lock(&dev_lists_lk);
   1113 
   1114 	/*
   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
   1119 	 * dev_list.
   1120 	 */
   1121 	dev_list = (struct name_list **)
   1122 	    calloc(array_size, sizeof (struct name_list *));
   1123 	if (dev_list == NULL) {
   1124 		free(full_path);
   1125 		(void) mutex_unlock(&dev_lists_lk);
   1126 		return (-1);
   1127 	}
   1128 	bootdev_list = bootdev_array;
   1129 
   1130 	if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) {
   1131 		bootdev_list = NULL;
   1132 		free(full_path);
   1133 		for (i = 0; i < array_size; i++) {
   1134 			free_name_list(dev_list[i], 1);
   1135 		}
   1136 		/* don't free dev_list here because it's been handed off */
   1137 		dev_list = NULL;
   1138 		(void) mutex_unlock(&dev_lists_lk);
   1139 		return (-1);
   1140 	}
   1141 
   1142 	/*
   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.
   1147 	 */
   1148 	for (i = 0; i < array_size; i++) {
   1149 		/* get the next list */
   1150 		list = dev_list[i];
   1151 		count = 0;
   1152 
   1153 		/* count the number of entries in the list */
   1154 		while (list != NULL) {
   1155 			count++;
   1156 			list = list->next;
   1157 		}
   1158 		if ((dev_name_array =
   1159 		    (char **)malloc((count + 1) * sizeof (char *)))
   1160 		    == NULL) {
   1161 			continue;
   1162 		}
   1163 		list = dev_list[i];
   1164 		count = 0;
   1165 
   1166 		/* fill in the array */
   1167 		while (list != NULL) {
   1168 			dev_name_array[count] = list->name;
   1169 			count++;
   1170 			list = list->next;
   1171 		}
   1172 
   1173 		/*
   1174 		 * null terminate the array
   1175 		 */
   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]);
   1180 		}
   1181 		if (bootdev_array[i] != NULL) {
   1182 			free(bootdev_array[i]->bootdev_trans);
   1183 			bootdev_array[i]->bootdev_trans = dev_name_array;
   1184 		}
   1185 	}
   1186 	bootdev_list = NULL;
   1187 	free(full_path);
   1188 	for (i = 0; i < array_size; i++) {
   1189 		free_name_list(dev_list[i], 0);
   1190 	}
   1191 	free(dev_list);
   1192 	dev_list = NULL;
   1193 	(void) mutex_unlock(&dev_lists_lk);
   1194 	return (0);
   1195 }
   1196 /*
   1197  * nftw function
   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
   1201  */
   1202 /* ARGSUSED */
   1203 static int
   1204 check_logical_dev(const char *node, const struct stat *node_stat, int flags,
   1205 	struct FTW *ftw_info)
   1206 {
   1207 	char link_buf[MAXPATHLEN];
   1208 	int link_buf_len;
   1209 	char *name;
   1210 	struct name_list *dev;
   1211 	char *physdev;
   1212 	int i;
   1213 
   1214 	if (flags != FTW_SL) {
   1215 		return (0);
   1216 	}
   1217 
   1218 	if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN))
   1219 	    == -1) {
   1220 		return (0);
   1221 	}
   1222 	link_buf[link_buf_len] = '\0';
   1223 	if ((name = strstr(link_buf, DEVICES)) == NULL) {
   1224 		return (0);
   1225 	}
   1226 	name = (char *)(name + strlen(DEVICES));
   1227 
   1228 	for (i = 0; bootdev_list[i] != NULL; i++) {
   1229 		if (bootdev_list[i]->bootdev_trans[0] == NULL) {
   1230 			continue;
   1231 		}
   1232 		/*
   1233 		 * compare the contents of the link with the physical
   1234 		 * device representation of this boot device
   1235 		 */
   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) {
   1241 				return (-1);
   1242 			}
   1243 			if ((dev->name = strdup(node)) == NULL) {
   1244 				free(dev);
   1245 				return (-1);
   1246 			}
   1247 			if (dev_list[i] == NULL) {
   1248 				dev_list[i] = dev;
   1249 				dev_list[i]->next = NULL;
   1250 			} else {
   1251 				dev->next = dev_list[i];
   1252 				dev_list[i] = dev;
   1253 			}
   1254 		}
   1255 	}
   1256 	return (0);
   1257 }
   1258 
   1259 /*
   1260  * frees a list of boot_dev struct pointers
   1261  */
   1262 void
   1263 devfs_bootdev_free_list(struct boot_dev **array)
   1264 {
   1265 	int i = 0;
   1266 	int j;
   1267 
   1268 	if (array == NULL) {
   1269 		return;
   1270 	}
   1271 
   1272 	while (array[i] != NULL) {
   1273 		free(array[i]->bootdev_element);
   1274 		j = 0;
   1275 		while (array[i]->bootdev_trans[j] != NULL) {
   1276 			free(array[i]->bootdev_trans[j++]);
   1277 		}
   1278 		free(array[i]->bootdev_trans);
   1279 		free(array[i]);
   1280 		i++;
   1281 	}
   1282 	free(array);
   1283 }
   1284 /*
   1285  * allocates a boot_dev struct and fills in the bootdev_element portion
   1286  */
   1287 static struct boot_dev *
   1288 alloc_bootdev(char *entry_name)
   1289 {
   1290 	struct boot_dev *entry;
   1291 
   1292 	entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev));
   1293 
   1294 	if (entry == NULL) {
   1295 		return (NULL);
   1296 	}
   1297 	if ((entry->bootdev_element = strdup(entry_name)) == NULL) {
   1298 		free(entry);
   1299 		return (NULL);
   1300 	}
   1301 	/*
   1302 	 * Allocate room for 1 name and a null terminator - the caller of
   1303 	 * this function will need the first slot right away.
   1304 	 */
   1305 	if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *)))
   1306 	    == NULL) {
   1307 		free(entry->bootdev_element);
   1308 		free(entry);
   1309 		return (NULL);
   1310 	}
   1311 	return (entry);
   1312 }
   1313 
   1314 /*
   1315  * will come back with a concatenated list of paths
   1316  */
   1317 int
   1318 devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len)
   1319 {
   1320 	Oppbuf oppbuf;
   1321 	struct openpromio *opp = &(oppbuf.opp);
   1322 	int prom_fd;
   1323 	int ret = DEVFS_INVAL;
   1324 	int i;
   1325 
   1326 	if (prom_path == NULL) {
   1327 		return (DEVFS_INVAL);
   1328 	}
   1329 	if (dev_path == NULL) {
   1330 		return (DEVFS_INVAL);
   1331 	}
   1332 	if (strlen(dev_path) >= MAXPATHLEN)
   1333 		return (DEVFS_INVAL);
   1334 
   1335 	if (*dev_path != '/')
   1336 		return (DEVFS_INVAL);
   1337 
   1338 	prom_fd = prom_open(O_RDONLY);
   1339 	if (prom_fd < 0) {
   1340 		return (prom_fd);
   1341 	}
   1342 
   1343 	/* query the prom */
   1344 	(void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path);
   1345 	opp->oprom_size = MAXVALSIZE;
   1346 
   1347 	if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) {
   1348 		prom_close(prom_fd);
   1349 
   1350 		/* return the prom path in prom_path */
   1351 
   1352 		i = len - opp->oprom_size;
   1353 		if (i < 0) {
   1354 			bcopy(opp->oprom_array, prom_path, len);
   1355 			prom_path[len - 1] = NULL;
   1356 			return (len);
   1357 		} else {
   1358 			bcopy(opp->oprom_array, prom_path, len);
   1359 			return (opp->oprom_size);
   1360 		}
   1361 	}
   1362 	/*
   1363 	 * either the prom does not support this ioctl or the argument
   1364 	 * was invalid.
   1365 	 */
   1366 	if (errno == ENXIO) {
   1367 		ret = DEVFS_NOTSUP;
   1368 	}
   1369 	prom_close(prom_fd);
   1370 	return (ret);
   1371 }
   1372 
   1373 /*
   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.
   1382  *
   1383  * This routine only supports converting leaf device paths
   1384  */
   1385 int
   1386 devfs_dev_to_prom_name(char *dev_path, char *prom_path)
   1387 {
   1388 	int rval;
   1389 
   1390 	rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN);
   1391 
   1392 	if (rval < 0)
   1393 		return (rval);
   1394 	else
   1395 		return (0);
   1396 }
   1397 
   1398 /*
   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.
   1404  *
   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.
   1408  *
   1409  * This routine returns driver names that have aliases resolved.
   1410  */
   1411 int
   1412 devfs_path_to_drv(char *devfs_path, char *drv_buf)
   1413 {
   1414 	Oppbuf oppbuf;
   1415 	struct openpromio *opp = &(oppbuf.opp);
   1416 	char *slash, *colon, *dev_addr;
   1417 	char driver_path[MAXPATHLEN];
   1418 	int prom_fd;
   1419 
   1420 	if (drv_buf == NULL) {
   1421 		return (-1);
   1422 	}
   1423 	if (devfs_path == NULL) {
   1424 		return (-1);
   1425 	}
   1426 
   1427 	if (strlen(devfs_path) >= MAXPATHLEN)
   1428 		return (-1);
   1429 
   1430 	if (*devfs_path != '/')
   1431 		return (-1);
   1432 
   1433 
   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, '/');
   1437 	if (slash == NULL)
   1438 		return (-1);
   1439 	colon = strrchr(slash, ':');
   1440 	if (colon != NULL)
   1441 		*colon = '\0';
   1442 
   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;
   1447 
   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);
   1452 			return (0);
   1453 		}
   1454 		prom_close(prom_fd);
   1455 	} else if (prom_fd != DEVFS_NOTSUP)
   1456 		return (-1);
   1457 	/*
   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
   1464 	 */
   1465 
   1466 	/* use the last component of devfs_path as the driver name */
   1467 	if ((dev_addr = strrchr(slash, '@')) != NULL)
   1468 		*dev_addr = '\0';
   1469 	slash++;
   1470 
   1471 	/* use opp->oprom_array as a buffer */
   1472 	(void) strcpy(opp->oprom_array, slash);
   1473 	if (devfs_resolve_aliases(opp->oprom_array) == NULL)
   1474 		return (-1);
   1475 	(void) strcpy(drv_buf, opp->oprom_array);
   1476 	return (0);
   1477 }
   1478 
   1479 /*
   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.
   1487  */
   1488 char *
   1489 devfs_resolve_aliases(char *drv)
   1490 {
   1491 	major_t maj;
   1492 	char driver_name[MAXNAMELEN + 1];
   1493 
   1494 	if (drv == NULL) {
   1495 		return (NULL);
   1496 	}
   1497 
   1498 	if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0)
   1499 		return (NULL);
   1500 	else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj)
   1501 	    < 0) {
   1502 		return (NULL);
   1503 	} else {
   1504 		(void) strcpy(drv, driver_name);
   1505 		return (drv);
   1506 	}
   1507 }
   1508 
   1509 /*
   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
   1512  * return an error
   1513  */
   1514 static int
   1515 prom_open(int oflag)
   1516 {
   1517 	int prom_fd = -1;
   1518 	char *promdev = "/dev/openprom";
   1519 
   1520 	while (prom_fd < 0) {
   1521 		if ((prom_fd = open(promdev, oflag)) < 0)  {
   1522 			if (errno == EAGAIN)   {
   1523 				(void) sleep(5);
   1524 				continue;
   1525 			}
   1526 			if ((errno == ENXIO) || (errno == ENOENT)) {
   1527 				return (DEVFS_NOTSUP);
   1528 			}
   1529 			if ((errno == EPERM) || (errno == EACCES)) {
   1530 				return (DEVFS_PERM);
   1531 			}
   1532 			return (DEVFS_ERR);
   1533 		} else
   1534 			break;
   1535 	}
   1536 	if (is_openprom(prom_fd))
   1537 		return (prom_fd);
   1538 	else {
   1539 		prom_close(prom_fd);
   1540 		return (DEVFS_ERR);
   1541 	}
   1542 }
   1543 
   1544 static void
   1545 prom_close(int prom_fd)
   1546 {
   1547 	(void) close(prom_fd);
   1548 }
   1549 
   1550 /*
   1551  * is this an OBP/1275 OF machine?
   1552  */
   1553 static int
   1554 is_openprom(int prom_fd)
   1555 {
   1556 	Oppbuf  oppbuf;
   1557 	struct openpromio *opp = &(oppbuf.opp);
   1558 	unsigned int i;
   1559 
   1560 	opp->oprom_size = MAXVALSIZE;
   1561 	if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
   1562 		return (0);
   1563 
   1564 	i = (unsigned int)((unsigned char)opp->oprom_array[0]);
   1565 	return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
   1566 }
   1567 
   1568 /*
   1569  * convert a prom device path name to an equivalent physical device
   1570  * path in the kernel.
   1571  */
   1572 static int
   1573 devfs_prom_to_dev_name(char *prom_path, char *dev_path)
   1574 {
   1575 	Oppbuf oppbuf;
   1576 	struct openpromio *opp = &(oppbuf.opp);
   1577 	int prom_fd;
   1578 	int ret = DEVFS_INVAL;
   1579 
   1580 	if (dev_path == NULL) {
   1581 		return (DEVFS_INVAL);
   1582 	}
   1583 	if (prom_path == NULL) {
   1584 		return (DEVFS_INVAL);
   1585 	}
   1586 	if (strlen(prom_path) >= MAXPATHLEN)
   1587 		return (DEVFS_INVAL);
   1588 
   1589 	if (*prom_path != '/') {
   1590 		return (DEVFS_INVAL);
   1591 	}
   1592 
   1593 	/* query the prom */
   1594 	prom_fd = prom_open(O_RDONLY);
   1595 	if (prom_fd < 0) {
   1596 		return (prom_fd);
   1597 	}
   1598 	(void) strcpy(opp->oprom_array, prom_path);
   1599 	opp->oprom_size = MAXVALSIZE;
   1600 
   1601 	if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) {
   1602 		prom_close(prom_fd);
   1603 		/*
   1604 		 * success
   1605 		 * return the prom path in prom_path
   1606 		 */
   1607 		(void) strcpy(dev_path, opp->oprom_array);
   1608 		return (0);
   1609 	}
   1610 	/*
   1611 	 * either the argument was not a valid name or the openprom
   1612 	 * driver does not support this ioctl.
   1613 	 */
   1614 	if (errno == ENXIO) {
   1615 		ret = DEVFS_NOTSUP;
   1616 	}
   1617 	prom_close(prom_fd);
   1618 	return (ret);
   1619 }
   1620 /*
   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.
   1624  */
   1625 static int
   1626 prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf)
   1627 {
   1628 	struct name_list *exact_list;
   1629 	struct name_list *inexact_list;
   1630 	struct name_list *list;
   1631 	char *ptr;
   1632 	char **array;
   1633 	int prom_fd;
   1634 	int count;
   1635 	int vers;
   1636 
   1637 	vers = prom_obp_vers();
   1638 	if (vers < 0) {
   1639 		return (vers);
   1640 	}
   1641 
   1642 	if (dev == NULL) {
   1643 		return (DEVFS_INVAL);
   1644 	}
   1645 
   1646 	if (*dev != '/')
   1647 		return (DEVFS_INVAL);
   1648 
   1649 	if (strlen(dev) >= MAXPATHLEN)
   1650 		return (DEVFS_INVAL);
   1651 
   1652 	if ((ptr = strchr(dev, ':')) != NULL) {
   1653 		if (strchr(ptr, '/') != NULL)
   1654 			return (DEVFS_INVAL);
   1655 	}
   1656 	if (ret_buf == NULL) {
   1657 		return (DEVFS_INVAL);
   1658 	}
   1659 
   1660 	prom_fd = prom_open(O_RDONLY);
   1661 	if (prom_fd < 0) {
   1662 		return (prom_fd);
   1663 	}
   1664 
   1665 	(void) prom_srch_aliases_by_def(dev, &exact_list,
   1666 	    &inexact_list,  prom_fd);
   1667 
   1668 	prom_close(prom_fd);
   1669 
   1670 	if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) {
   1671 		free_name_list(exact_list, 1);
   1672 		exact_list = NULL;
   1673 	}
   1674 
   1675 	if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) {
   1676 		free_name_list(inexact_list, 1);
   1677 		inexact_list = NULL;
   1678 	}
   1679 
   1680 	count = 0;
   1681 	list = exact_list;
   1682 	while (list != NULL) {
   1683 		list = list->next;
   1684 		count++;
   1685 	}
   1686 	list = inexact_list;
   1687 	while (list != NULL) {
   1688 		list = list->next;
   1689 		count++;
   1690 	}
   1691 
   1692 	if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *)))
   1693 	    == NULL) {
   1694 		free_name_list(inexact_list, 1);
   1695 		free_name_list(exact_list, 1);
   1696 		return (DEVFS_NOMEM);
   1697 	}
   1698 
   1699 	array = *ret_buf;
   1700 	count = 0;
   1701 	list = exact_list;
   1702 	while (list != NULL) {
   1703 		array[count] = list->name;
   1704 		list = list->next;
   1705 		count++;
   1706 	}
   1707 	list = inexact_list;
   1708 	while (list != NULL) {
   1709 		array[count] = list->name;
   1710 		list = list->next;
   1711 		count++;
   1712 	}
   1713 	array[count] = NULL;
   1714 	free_name_list(inexact_list, 0);
   1715 	free_name_list(exact_list, 0);
   1716 
   1717 	return (0);
   1718 }
   1719 
   1720 /*
   1721  * determine the version of prom we are running on.
   1722  * Also include any prom revision specific information.
   1723  */
   1724 static int
   1725 prom_obp_vers(void)
   1726 {
   1727 	Oppbuf  oppbuf;
   1728 	struct openpromio *opp = &(oppbuf.opp);
   1729 	int prom_fd;
   1730 	static int version = 0;
   1731 
   1732 	/* cache version */
   1733 	if (version > 0) {
   1734 		return (version);
   1735 	}
   1736 
   1737 	prom_fd = prom_open(O_RDONLY);
   1738 	if (prom_fd < 0) {
   1739 		return (prom_fd);
   1740 	}
   1741 
   1742 	opp->oprom_size = MAXVALSIZE;
   1743 
   1744 	if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) {
   1745 		prom_close(prom_fd);
   1746 		return (DEVFS_ERR);
   1747 	}
   1748 	prom_close(prom_fd);
   1749 
   1750 	version |= OBP_OF;
   1751 
   1752 	return (version);
   1753 }
   1754 /*
   1755  * search the aliases node by definition - compile a list of
   1756  * alias names that are both exact and inexact matches.
   1757  */
   1758 static int
   1759 prom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list,
   1760     struct name_list **inexact_list, int prom_fd)
   1761 {
   1762 	Oppbuf  oppbuf;
   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);
   1767 	int ret;
   1768 	struct name_list *inexact_match = *inexact_list = NULL;
   1769 	struct name_list *exact_match = *exact_list = NULL;
   1770 	char alias_buf[MAXNAMELEN];
   1771 	int found = 0;
   1772 
   1773 	if ((ret = prom_find_aliases_node(prom_fd)) < 0)
   1774 		return (0);
   1775 
   1776 	(void) memset(oppbuf.buf, 0, BUFSIZE);
   1777 	opp->oprom_size = MAXPROPSIZE;
   1778 	*ip = 0;
   1779 
   1780 	if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0)
   1781 		return (0);
   1782 	if (opp->oprom_size == 0)
   1783 		return (0);
   1784 
   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);
   1792 			continue;
   1793 		}
   1794 		ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array);
   1795 		if (ret == EXACT_MATCH) {
   1796 			found++;
   1797 			if (insert_alias_list(exact_list, opp->oprom_array)
   1798 			    != 0) {
   1799 				free_name_list(exact_match, 1);
   1800 				free_name_list(inexact_match, 1);
   1801 				return (-1);
   1802 			}
   1803 		}
   1804 		if (ret == INEXACT_MATCH) {
   1805 			found++;
   1806 			(void) strcpy(alias_buf, opp->oprom_array);
   1807 			options_override(promdev_def, alias_buf);
   1808 			if (insert_alias_list(inexact_list, alias_buf)
   1809 			    != 0) {
   1810 				free_name_list(exact_match, 1);
   1811 				free_name_list(inexact_match, 1);
   1812 				return (-1);
   1813 			}
   1814 		}
   1815 		ret = ioctl(prom_fd, OPROMNXTPROP, opp);
   1816 	}
   1817 	if (found) {
   1818 		return (0);
   1819 	} else {
   1820 		return (-1);
   1821 	}
   1822 }
   1823 
   1824 /*
   1825  * free a list of name_list structs and optionally
   1826  * free the strings they contain.
   1827  */
   1828 static void
   1829 free_name_list(struct name_list *list, int free_name)
   1830 {
   1831 	struct name_list *next = list;
   1832 
   1833 	while (next != NULL) {
   1834 		list = list->next;
   1835 		if (free_name)
   1836 			free(next->name);
   1837 		free(next);
   1838 		next = list;
   1839 	}
   1840 }
   1841 
   1842 /*
   1843  * insert a new alias in a list of aliases - the list is sorted
   1844  * in collating order (ignoring anything that comes after the
   1845  * ':' in the name).
   1846  */
   1847 static int
   1848 insert_alias_list(struct name_list **list, char *alias_name)
   1849 {
   1850 	struct name_list *entry = *list;
   1851 	struct name_list *new_entry, *prev_entry;
   1852 	int ret;
   1853 	char *colon1, *colon2;
   1854 
   1855 	if ((new_entry =
   1856 	    (struct name_list *)malloc(sizeof (struct name_list)))
   1857 	    == NULL) {
   1858 		return (-1);
   1859 	}
   1860 	if ((new_entry->name = strdup(alias_name)) == NULL) {
   1861 		free(new_entry);
   1862 		return (-1);
   1863 	}
   1864 	new_entry->next = NULL;
   1865 
   1866 	if (entry == NULL) {
   1867 		*list = new_entry;
   1868 		return (0);
   1869 	}
   1870 
   1871 	if ((colon1 = strchr(alias_name, ':')) != NULL) {
   1872 		*colon1 = '\0';
   1873 	}
   1874 	prev_entry = NULL;
   1875 	while (entry != NULL) {
   1876 		if ((colon2 = strchr(entry->name, ':')) != NULL) {
   1877 			*colon2 = '\0';
   1878 		}
   1879 		ret = strcmp(alias_name, entry->name);
   1880 		if (colon2 != NULL) {
   1881 			*colon2 = ':';
   1882 		}
   1883 		/* duplicate */
   1884 		if (ret == 0) {
   1885 			free(new_entry->name);
   1886 			free(new_entry);
   1887 			if (colon1 != NULL) {
   1888 				*colon1 = ':';
   1889 			}
   1890 			return (0);
   1891 		}
   1892 		if (ret < 0) {
   1893 			new_entry->next = entry;
   1894 			if (prev_entry == NULL) {
   1895 				/* in beginning of list */
   1896 				*list = new_entry;
   1897 			} else {
   1898 				/* in middle of list */
   1899 				prev_entry->next = new_entry;
   1900 			}
   1901 			if (colon1 != NULL) {
   1902 				*colon1 = ':';
   1903 			}
   1904 			return (0);
   1905 		}
   1906 		prev_entry = entry;
   1907 		entry = entry->next;
   1908 	}
   1909 	/* at end of list */
   1910 	prev_entry->next = new_entry;
   1911 	new_entry->next = NULL;
   1912 	if (colon1 != NULL) {
   1913 		*colon1 = ':';
   1914 	}
   1915 	return (0);
   1916 }
   1917 /*
   1918  * append :x to alias_name to override any default minor name options
   1919  */
   1920 static void
   1921 options_override(char *prom_path, char *alias_name)
   1922 {
   1923 	char *colon;
   1924 
   1925 	if ((colon = strrchr(alias_name, ':')) != NULL) {
   1926 		/*
   1927 		 * XXX - should alias names in /aliases ever have a
   1928 		 * : embedded in them?
   1929 		 * If so we ignore it.
   1930 		 */
   1931 		*colon = '\0';
   1932 	}
   1933 
   1934 	if ((colon = strrchr(prom_path, ':')) != NULL) {
   1935 		(void) strcat(alias_name, colon);
   1936 	}
   1937 }
   1938 
   1939 /*
   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.
   1944  */
   1945 static int
   1946 prom_compare_devs(char *prom_dev1, char *prom_dev2)
   1947 {
   1948 	char *dev1, *dev2;
   1949 	char *ptr1, *ptr2;
   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;
   1956 	int len1, len2;
   1957 	char *wildcard = ",0";
   1958 
   1959 	ptr1 = prom_dev1;
   1960 	ptr2 = prom_dev2;
   1961 
   1962 	if ((ptr1 == NULL) || (*ptr1 != '/')) {
   1963 		return (NO_MATCH);
   1964 	}
   1965 	if ((ptr2 == NULL) || (*ptr2 != '/')) {
   1966 		return (NO_MATCH);
   1967 	}
   1968 
   1969 	/*
   1970 	 * compare device names one component at a time.
   1971 	 */
   1972 	while ((ptr1 != NULL) && (ptr2 != NULL)) {
   1973 		*ptr1 = *ptr2 = '/';
   1974 		dev1 = ptr1 + 1;
   1975 		dev2 = ptr2 + 1;
   1976 		if ((ptr1 = strchr(dev1, '/')) != NULL)
   1977 			*ptr1 = '\0';
   1978 		if ((ptr2 = strchr(dev2, '/')) != NULL)
   1979 			*ptr2 = '\0';
   1980 
   1981 		(void) strcpy(component1, dev1);
   1982 		(void) strcpy(component2, dev2);
   1983 
   1984 		parse_name(component1, &drvname1, &addrname1, &minorname1);
   1985 		parse_name(component2, &drvname2, &addrname2, &minorname2);
   1986 
   1987 		if ((drvname1 == NULL) && (addrname1 == NULL)) {
   1988 			error = NO_MATCH;
   1989 			break;
   1990 		}
   1991 
   1992 		if ((drvname2 == NULL) && (addrname2 == NULL)) {
   1993 			error = NO_MATCH;
   1994 			break;
   1995 		}
   1996 
   1997 		if (_prom_strcmp(drvname1, drvname2) != 0) {
   1998 			error = NO_MATCH;
   1999 			break;
   2000 		}
   2001 
   2002 		/*
   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
   2008 		 */
   2009 		if ((addrname1 == NULL) ^ (addrname2 == NULL)) {
   2010 			unqualified_name = 1;
   2011 		} else if (addrname1 &&
   2012 		    (_prom_strcmp(addrname1, addrname2) != 0)) {
   2013 			/*
   2014 			 * check to see if appending a ",0" to the
   2015 			 * shorter address causes a match to occur.
   2016 			 * If so succeed.
   2017 			 */
   2018 			len1 = strlen(addrname1);
   2019 			len2 = strlen(addrname2);
   2020 			if ((len1 < len2) &&
   2021 			    (strncmp(addrname1, addrname2, len1) == 0) &&
   2022 			    (strcmp(wildcard, &addrname2[len1]) == 0)) {
   2023 				continue;
   2024 			} else if ((len2 < len1) &&
   2025 			    (strncmp(addrname1, addrname2, len2) == 0) &&
   2026 			    (strcmp(wildcard, &addrname1[len2]) == 0)) {
   2027 				continue;
   2028 			}
   2029 			error = NO_MATCH;
   2030 			break;
   2031 		}
   2032 	}
   2033 
   2034 	/*
   2035 	 * if either of the two device paths still has more components,
   2036 	 * then we do not have a match.
   2037 	 */
   2038 	if (ptr1 != NULL) {
   2039 		*ptr1 = '/';
   2040 		error = NO_MATCH;
   2041 	}
   2042 	if (ptr2 != NULL) {
   2043 		*ptr2 = '/';
   2044 		error = NO_MATCH;
   2045 	}
   2046 	if (error == NO_MATCH) {
   2047 		return (error);
   2048 	}
   2049 
   2050 	/*
   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
   2055 	 * strings.
   2056 	 */
   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)) {
   2060 			return (NO_MATCH);
   2061 		}
   2062 		if ((dev1 = strrchr(devname1, ':')) != NULL) {
   2063 			*dev1 = '\0';
   2064 		}
   2065 		if ((dev2 = strrchr(devname2, ':')) != NULL) {
   2066 			*dev2 = '\0';
   2067 		}
   2068 		if (strcmp(devname1, devname2) != 0) {
   2069 			return (NO_MATCH);
   2070 		}
   2071 	}
   2072 	/*
   2073 	 * the resulting strings matched.  If the minorname information
   2074 	 * matches, then we have an exact match, otherwise an inexact match
   2075 	 */
   2076 	if (_prom_strcmp(minorname1, minorname2) == 0) {
   2077 		return (EXACT_MATCH);
   2078 	} else {
   2079 		return (INEXACT_MATCH);
   2080 	}
   2081 }
   2082 
   2083 /*
   2084  * wrapper or strcmp - deals with null strings.
   2085  */
   2086 static int
   2087 _prom_strcmp(char *s1, char *s2)
   2088 {
   2089 	if ((s1 == NULL) && (s2 == NULL))
   2090 		return (0);
   2091 	if ((s1 == NULL) && (s2 != NULL)) {
   2092 		return (-1);
   2093 	}
   2094 	if ((s1 != NULL) && (s2 == NULL)) {
   2095 		return (1);
   2096 	}
   2097 	return (strcmp(s1, s2));
   2098 }
   2099 /*
   2100  * break device@a,b:minor into components
   2101  */
   2102 static void
   2103 parse_name(char *name, char **drvname, char **addrname, char **minorname)
   2104 {
   2105 	char *cp, ch;
   2106 
   2107 	cp = *drvname = name;
   2108 	*addrname = *minorname = NULL;
   2109 	if (*name == '@')
   2110 		*drvname = NULL;
   2111 
   2112 	while ((ch = *cp) != '\0') {
   2113 		if (ch == '@')
   2114 			*addrname = ++cp;
   2115 		else if (ch == ':')
   2116 			*minorname = ++cp;
   2117 		++cp;
   2118 	}
   2119 	if (*addrname) {
   2120 		*((*addrname)-1) = '\0';
   2121 	}
   2122 	if (*minorname) {
   2123 		*((*minorname)-1) = '\0';
   2124 	}
   2125 }
   2126 
   2127 /*
   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.
   2132  */
   2133 static int
   2134 alias_to_prom_dev(char *alias, char *ret_buf)
   2135 {
   2136 	char *options_ptr;
   2137 	char alias_buf[MAXNAMELEN];
   2138 	char alias_def[MAXPATHLEN];
   2139 	char options[16] = "";
   2140 	int prom_fd = -1;
   2141 	int ret;
   2142 	int i;
   2143 
   2144 	if (strchr(alias, '/') != NULL)
   2145 		return (DEVFS_INVAL);
   2146 
   2147 	if (strlen(alias) > (MAXNAMELEN - 1))
   2148 		return (DEVFS_INVAL);
   2149 
   2150 	if (ret_buf == NULL) {
   2151 		return (DEVFS_INVAL);
   2152 	}
   2153 
   2154 	prom_fd = prom_open(O_RDONLY);
   2155 	if (prom_fd < 0) {
   2156 		return (prom_fd);
   2157 	}
   2158 
   2159 	(void) strlcpy(alias_buf, alias, sizeof (alias_buf));
   2160 
   2161 	/*
   2162 	 * save off any options (minor name info) that is
   2163 	 * explicitly called out in the alias name
   2164 	 */
   2165 	if ((options_ptr = strchr(alias_buf, ':')) != NULL) {
   2166 		*options_ptr = '\0';
   2167 		(void) strlcpy(options, ++options_ptr, sizeof (options));
   2168 	}
   2169 
   2170 	*alias_def = '\0';
   2171 
   2172 	ret = prom_find_aliases_node(prom_fd);
   2173 	if (ret == 0) {
   2174 		/*
   2175 		 * we loop because one alias may define another... we have
   2176 		 * to work our way down to an actual device definition.
   2177 		 */
   2178 		for (i = 0; i <= 10; i++) {
   2179 			ret = prom_srch_node(prom_fd, alias_buf, alias_def);
   2180 			if (ret == -1) {
   2181 				break;
   2182 			}
   2183 			(void) strlcpy(alias_buf, alias_def,
   2184 			    sizeof (alias_buf));
   2185 			if (*alias_def == '/') {
   2186 				break;
   2187 			}
   2188 
   2189 			/*
   2190 			 * save off any explicit options (minor name info)
   2191 			 * if none has been encountered yet
   2192 			 */
   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,
   2198 					    sizeof (options));
   2199 				}
   2200 			}
   2201 		}
   2202 	}
   2203 	prom_close(prom_fd);
   2204 
   2205 	/* error */
   2206 	if (ret == -1) {
   2207 		return (ret);
   2208 	}
   2209 
   2210 	(void) strlcpy(ret_buf, alias_def, MAXPATHLEN);
   2211 
   2212 	/* override minor name information */
   2213 	if (options_ptr != NULL) {
   2214 		if ((options_ptr = strrchr(ret_buf, ':')) == NULL) {
   2215 			(void) strcat(ret_buf, ":");
   2216 		} else {
   2217 			*(++options_ptr) = '\0';
   2218 		}
   2219 		(void) strcat(ret_buf, options);
   2220 	}
   2221 	return (0);
   2222 }
   2223 
   2224 /*
   2225  * search a prom node for a property name
   2226  */
   2227 static int
   2228 prom_srch_node(int fd, char *prop_name, char *ret_buf)
   2229 {
   2230 	Oppbuf  oppbuf;
   2231 	struct openpromio *opp = &(oppbuf.opp);
   2232 	int *ip = (int *)((void *)opp->oprom_array);
   2233 
   2234 	(void) memset(oppbuf.buf, 0, BUFSIZE);
   2235 	opp->oprom_size = MAXPROPSIZE;
   2236 	*ip = 0;
   2237 
   2238 	if (ioctl(fd, OPROMNXTPROP, opp) < 0)
   2239 		return (-1);
   2240 	if (opp->oprom_size == 0)
   2241 		return (-1);
   2242 
   2243 	while (strcmp(prop_name, opp->oprom_array) != 0) {
   2244 		opp->oprom_size = MAXPROPSIZE;
   2245 		if (ioctl(fd, OPROMNXTPROP, opp) < 0)
   2246 			return (-1);
   2247 		if (opp->oprom_size == 0)
   2248 			return (-1);
   2249 	}
   2250 	opp->oprom_size = MAXVALSIZE;
   2251 	if (ioctl(fd, OPROMGETPROP, opp) < 0)
   2252 		return (-1);
   2253 
   2254 	if (opp->oprom_size == 0)
   2255 		return (-1);
   2256 	(void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN);
   2257 	return (0);
   2258 }
   2259 
   2260 /*
   2261  * return the aliases node.
   2262  */
   2263 static int
   2264 prom_find_aliases_node(int fd)
   2265 {
   2266 	uint_t child_id;
   2267 	char buf[MAXPATHLEN];
   2268 
   2269 	if ((child_id = prom_next_node(fd, 0)) == 0)
   2270 		return (-1);
   2271 	if ((child_id = prom_child_node(fd, child_id)) == 0)
   2272 		return (-1);
   2273 
   2274 	while (child_id != 0) {
   2275 		if (prom_srch_node(fd, "name", buf) == 0) {
   2276 			if (strcmp(buf, "aliases") == 0) {
   2277 				return (0);
   2278 			}
   2279 		}
   2280 		child_id = prom_next_node(fd, child_id);
   2281 	}
   2282 	return (-1);
   2283 }
   2284 
   2285 /*
   2286  * get sibling
   2287  */
   2288 static uint_t
   2289 prom_next_node(int fd, uint_t node_id)
   2290 {
   2291 	Oppbuf  oppbuf;
   2292 	struct openpromio *opp = &(oppbuf.opp);
   2293 	uint_t *ip = (uint_t *)((void *)opp->oprom_array);
   2294 
   2295 	(void) memset(oppbuf.buf, 0, BUFSIZE);
   2296 	opp->oprom_size = MAXVALSIZE;
   2297 	*ip = node_id;
   2298 
   2299 	if (ioctl(fd, OPROMNEXT, opp) < 0)
   2300 		return (0);
   2301 
   2302 	return (*(uint_t *)((void *)opp->oprom_array));
   2303 }
   2304 
   2305 /*
   2306  * get child
   2307  */
   2308 static uint_t
   2309 prom_child_node(int fd, uint_t node_id)
   2310 {
   2311 	Oppbuf  oppbuf;
   2312 	struct openpromio *opp = &(oppbuf.opp);
   2313 	uint_t *ip = (uint_t *)((void *)opp->oprom_array);
   2314 
   2315 	(void) memset(oppbuf.buf, 0, BUFSIZE);
   2316 	opp->oprom_size = MAXVALSIZE;
   2317 	*ip = node_id;
   2318 
   2319 	if (ioctl(fd, OPROMCHILD, opp) < 0)
   2320 		return (0);
   2321 
   2322 	return (*(uint_t *)((void *)opp->oprom_array));
   2323 }
   2324 
   2325 /*
   2326  * only on sparc for now
   2327  */
   2328 int
   2329 devfs_bootdev_modifiable(void)
   2330 {
   2331 #if defined(sparc)
   2332 	return (0);
   2333 #else
   2334 	return (DEVFS_NOTSUP);
   2335 #endif
   2336 }
   2337