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