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