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