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