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