xref: /illumos-gate/usr/src/lib/libdevinfo/devfsinfo.c (revision 95fa951bc5472014864acb687472500ce1f631fa)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5b6f77fefSas  * Common Development and Distribution License (the "License").
6b6f77fefSas  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*95fa951bSas  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <string.h>
307c478bd9Sstevel@tonic-gate #include <strings.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <thread.h>
347c478bd9Sstevel@tonic-gate #include <synch.h>
357c478bd9Sstevel@tonic-gate #include <sys/types.h>
367c478bd9Sstevel@tonic-gate #include <ctype.h>
377c478bd9Sstevel@tonic-gate #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <fcntl.h>
397c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
407c478bd9Sstevel@tonic-gate #include <errno.h>
417c478bd9Sstevel@tonic-gate #include <sys/openpromio.h>
427c478bd9Sstevel@tonic-gate #include <ftw.h>
437c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
457c478bd9Sstevel@tonic-gate #include <limits.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #include "device_info.h"
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate  * #define's
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /* alias node searching return values */
547c478bd9Sstevel@tonic-gate #define	NO_MATCH	-1
557c478bd9Sstevel@tonic-gate #define	EXACT_MATCH	1
567c478bd9Sstevel@tonic-gate #define	INEXACT_MATCH	2
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* for prom io operations */
597c478bd9Sstevel@tonic-gate #define	BUFSIZE		4096
607c478bd9Sstevel@tonic-gate #define	MAXPROPSIZE	256
617c478bd9Sstevel@tonic-gate #define	MAXVALSIZE	(BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
627c478bd9Sstevel@tonic-gate 
63b6f77fefSas /* prom_obp_vers() return values */
647c478bd9Sstevel@tonic-gate #define	OBP_OF			0x4	/* versions OBP 3.x */
65b6f77fefSas #define	OBP_NO_ALIAS_NODE	0x8	/* No alias node */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /* for nftw call */
687c478bd9Sstevel@tonic-gate #define	FT_DEPTH	15
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* default logical and physical device name space */
717c478bd9Sstevel@tonic-gate #define	DEV	"/dev"
727c478bd9Sstevel@tonic-gate #define	DEVICES	"/devices"
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* for boot device identification on x86 */
757c478bd9Sstevel@tonic-gate #define	CREATE_DISKMAP		"/boot/solaris/bin/create_diskmap"
767c478bd9Sstevel@tonic-gate #define	GRUBDISK_MAP		"/var/run/solaris_grubdisk.map"
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * internal structure declarations
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /* for prom io functions */
837c478bd9Sstevel@tonic-gate typedef union {
847c478bd9Sstevel@tonic-gate 	char buf[BUFSIZE];
857c478bd9Sstevel@tonic-gate 	struct openpromio opp;
867c478bd9Sstevel@tonic-gate } Oppbuf;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate /* used to manage lists of devices and aliases */
897c478bd9Sstevel@tonic-gate struct name_list {
907c478bd9Sstevel@tonic-gate 	char *name;
917c478bd9Sstevel@tonic-gate 	struct name_list *next;
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * internal global data
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* global since nftw does not let you pass args to be updated */
997c478bd9Sstevel@tonic-gate static struct name_list **dev_list;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /* global since nftw does not let you pass args to be updated */
1027c478bd9Sstevel@tonic-gate static struct boot_dev **bootdev_list;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* mutex to protect bootdev_list and dev_list */
1057c478bd9Sstevel@tonic-gate static mutex_t dev_lists_lk = DEFAULTMUTEX;
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * internal function prototypes
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static int prom_open(int);
1127c478bd9Sstevel@tonic-gate static void prom_close(int);
1137c478bd9Sstevel@tonic-gate static int is_openprom(int);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf);
116b6f77fefSas static int alias_to_prom_dev(char *alias, char *ret_buf);
1177c478bd9Sstevel@tonic-gate static int prom_srch_aliases_by_def(char *, struct name_list **,
1187c478bd9Sstevel@tonic-gate     struct name_list **, int);
119b6f77fefSas static int prom_find_aliases_node(int fd);
1207c478bd9Sstevel@tonic-gate static int prom_compare_devs(char *prom_dev1, char *prom_dev2);
1217c478bd9Sstevel@tonic-gate static int _prom_strcmp(char *s1, char *s2);
122b6f77fefSas static int prom_srch_node(int fd, char *prop_name, char *ret_buf);
123b6f77fefSas static uint_t prom_next_node(int fd, uint_t node_id);
124b6f77fefSas static uint_t prom_child_node(int fd, uint_t node_id);
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate static int prom_obp_vers(void);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static void parse_name(char *, char **, char **, char **);
1297c478bd9Sstevel@tonic-gate static int process_bootdev(const char *, const char *, struct boot_dev ***);
1307c478bd9Sstevel@tonic-gate static int process_minor_name(char *dev_path, const char *default_root);
1317c478bd9Sstevel@tonic-gate static void options_override(char *prom_path, char *alias_name);
1327c478bd9Sstevel@tonic-gate static int devfs_phys_to_logical(struct boot_dev **bootdev_array,
1337c478bd9Sstevel@tonic-gate 	const int array_size, const char *default_root);
1347c478bd9Sstevel@tonic-gate static int check_logical_dev(const char *, const struct stat *, int,
1357c478bd9Sstevel@tonic-gate 	struct FTW *);
1367c478bd9Sstevel@tonic-gate static struct boot_dev *alloc_bootdev(char *);
1377c478bd9Sstevel@tonic-gate static void free_name_list(struct name_list *list, int free_name);
1387c478bd9Sstevel@tonic-gate static int insert_alias_list(struct name_list **list,
1397c478bd9Sstevel@tonic-gate 	char *alias_name);
1407c478bd9Sstevel@tonic-gate static int get_boot_dev_var(struct openpromio *opp);
1417c478bd9Sstevel@tonic-gate static int set_boot_dev_var(struct openpromio *opp, char *bootdev);
1427c478bd9Sstevel@tonic-gate static int devfs_prom_to_dev_name(char *prom_path, char *dev_path);
1437c478bd9Sstevel@tonic-gate static int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len);
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate /*
1467c478bd9Sstevel@tonic-gate  * frees a list of paths from devfs_get_prom_name_list
1477c478bd9Sstevel@tonic-gate  */
1487c478bd9Sstevel@tonic-gate static void
1497c478bd9Sstevel@tonic-gate prom_list_free(char **prom_list)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	int i = 0;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	if (!prom_list)
1547c478bd9Sstevel@tonic-gate 		return;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 	while (prom_list[i]) {
1577c478bd9Sstevel@tonic-gate 		free(prom_list[i]);
1587c478bd9Sstevel@tonic-gate 		i++;
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 	free(prom_list);
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate static int
1647c478bd9Sstevel@tonic-gate devfs_get_prom_name_list(const char *dev_name, char ***prom_list)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	char *prom_path = NULL;
1677c478bd9Sstevel@tonic-gate 	int count = 0;		/* # of slots we will need in prom_list */
1687c478bd9Sstevel@tonic-gate 	int ret, i, len;
1697c478bd9Sstevel@tonic-gate 	char **list;
1707c478bd9Sstevel@tonic-gate 	char *ptr;
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	if (dev_name == NULL)
1737c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
1747c478bd9Sstevel@tonic-gate 	if (*dev_name != '/')
1757c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
1767c478bd9Sstevel@tonic-gate 	if (prom_list == NULL)
1777c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/*
1807c478bd9Sstevel@tonic-gate 	 * make sure we are on a machine which supports a prom
1817c478bd9Sstevel@tonic-gate 	 * and we have permission to use /dev/openprom
1827c478bd9Sstevel@tonic-gate 	 */
1837c478bd9Sstevel@tonic-gate 	if ((ret = prom_obp_vers()) < 0)
1847c478bd9Sstevel@tonic-gate 		return (ret);
1857c478bd9Sstevel@tonic-gate 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
1867c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
1877c478bd9Sstevel@tonic-gate 	/*
1887c478bd9Sstevel@tonic-gate 	 * get the prom path name
1897c478bd9Sstevel@tonic-gate 	 */
1907c478bd9Sstevel@tonic-gate 	ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE);
1917c478bd9Sstevel@tonic-gate 	if (ret < 0) {
1927c478bd9Sstevel@tonic-gate 		free(prom_path);
1937c478bd9Sstevel@tonic-gate 		return (ret);
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 	/* deal with list of names */
1967c478bd9Sstevel@tonic-gate 	for (i = 0; i < ret; i++)
1977c478bd9Sstevel@tonic-gate 		if (prom_path[i] == '\0')
1987c478bd9Sstevel@tonic-gate 			count++;
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) {
2017c478bd9Sstevel@tonic-gate 		free(prom_path);
2027c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
2037c478bd9Sstevel@tonic-gate 	}
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	ptr = prom_path;
2067c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
2077c478bd9Sstevel@tonic-gate 		len = strlen(ptr) + 1;
2087c478bd9Sstevel@tonic-gate 		if ((list[i] = (char *)malloc(len)) == NULL) {
2097c478bd9Sstevel@tonic-gate 			free(prom_path);
2107c478bd9Sstevel@tonic-gate 			free(list);
2117c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
2127c478bd9Sstevel@tonic-gate 		}
2137c478bd9Sstevel@tonic-gate 		(void) snprintf(list[i], len, "%s", ptr);
2147c478bd9Sstevel@tonic-gate 		ptr += len;
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	free(prom_path);
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	*prom_list = list;
2207c478bd9Sstevel@tonic-gate 	return (0);
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate  * retrieve the list of prom representations for a given device name
2257c478bd9Sstevel@tonic-gate  * the list will be sorted in the following order: exact aliases,
2267c478bd9Sstevel@tonic-gate  * inexact aliases, prom device path name.  If multiple matches occur
2277c478bd9Sstevel@tonic-gate  * for exact or inexact aliases, then these are sorted in collating
2287c478bd9Sstevel@tonic-gate  * order. The list is returned in prom_list
2297c478bd9Sstevel@tonic-gate  *
2307c478bd9Sstevel@tonic-gate  * the list may be restricted by specifying the correct flags in options.
2317c478bd9Sstevel@tonic-gate  */
2327c478bd9Sstevel@tonic-gate int
2337c478bd9Sstevel@tonic-gate devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list)
2347c478bd9Sstevel@tonic-gate {
2357c478bd9Sstevel@tonic-gate 	char *prom_path = NULL;
2367c478bd9Sstevel@tonic-gate 	int count = 0;		/* # of slots we will need in prom_list */
2377c478bd9Sstevel@tonic-gate 	char **alias_list = NULL;
2387c478bd9Sstevel@tonic-gate 	char **list;
2397c478bd9Sstevel@tonic-gate 	int ret;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	if (dev_name == NULL) {
2427c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
2437c478bd9Sstevel@tonic-gate 	}
2447c478bd9Sstevel@tonic-gate 	if (*dev_name != '/') {
2457c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 	if (prom_list == NULL) {
2487c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 	/*
2517c478bd9Sstevel@tonic-gate 	 * make sure we are on a machine which supports a prom
2527c478bd9Sstevel@tonic-gate 	 * and we have permission to use /dev/openprom
2537c478bd9Sstevel@tonic-gate 	 */
2547c478bd9Sstevel@tonic-gate 	if ((ret = prom_obp_vers()) < 0) {
2557c478bd9Sstevel@tonic-gate 		return (ret);
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 	if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) {
2587c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 	/*
2617c478bd9Sstevel@tonic-gate 	 * get the prom path name
2627c478bd9Sstevel@tonic-gate 	 */
2637c478bd9Sstevel@tonic-gate 	ret = devfs_dev_to_prom_name((char *)dev_name, prom_path);
2647c478bd9Sstevel@tonic-gate 	if (ret < 0) {
2657c478bd9Sstevel@tonic-gate 		free(prom_path);
2667c478bd9Sstevel@tonic-gate 		return (ret);
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 	/* get the list of aliases (exact and inexact) */
2697c478bd9Sstevel@tonic-gate 	if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) {
2707c478bd9Sstevel@tonic-gate 		free(prom_path);
2717c478bd9Sstevel@tonic-gate 		return (ret);
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 	/* now figure out how big the return array must be */
2747c478bd9Sstevel@tonic-gate 	if (alias_list != NULL) {
2757c478bd9Sstevel@tonic-gate 		while (alias_list[count] != NULL) {
2767c478bd9Sstevel@tonic-gate 			count++;
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 	}
2797c478bd9Sstevel@tonic-gate 	if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
2807c478bd9Sstevel@tonic-gate 		count++;	/* # of slots we will need in prom_list */
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 	count++;	/* for the null terminator */
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	/* allocate space for the list */
2857c478bd9Sstevel@tonic-gate 	if ((list = (char **)calloc(count, sizeof (char *))) == NULL) {
2867c478bd9Sstevel@tonic-gate 		count = 0;
2877c478bd9Sstevel@tonic-gate 		while ((alias_list) && (alias_list[count] != NULL)) {
2887c478bd9Sstevel@tonic-gate 			free(alias_list[count]);
2897c478bd9Sstevel@tonic-gate 			count++;
2907c478bd9Sstevel@tonic-gate 		}
2917c478bd9Sstevel@tonic-gate 		free(alias_list);
2927c478bd9Sstevel@tonic-gate 		free(prom_path);
2937c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
2947c478bd9Sstevel@tonic-gate 	}
2957c478bd9Sstevel@tonic-gate 	/* fill in the array and free the name list of aliases. */
2967c478bd9Sstevel@tonic-gate 	count = 0;
2977c478bd9Sstevel@tonic-gate 	while ((alias_list) && (alias_list[count] != NULL)) {
2987c478bd9Sstevel@tonic-gate 		list[count] = alias_list[count];
2997c478bd9Sstevel@tonic-gate 		count++;
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 	if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
3027c478bd9Sstevel@tonic-gate 		list[count] = prom_path;
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 	if (alias_list != NULL) {
3057c478bd9Sstevel@tonic-gate 		free(alias_list);
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 	*prom_list = list;
3087c478bd9Sstevel@tonic-gate 	return (0);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate /*
3127c478bd9Sstevel@tonic-gate  * Get a list prom-path translations for a solaris device.
3137c478bd9Sstevel@tonic-gate  *
3147c478bd9Sstevel@tonic-gate  * Returns the number of and all OBP paths and alias variants that
3157c478bd9Sstevel@tonic-gate  * reference the Solaris device path passed in.
3167c478bd9Sstevel@tonic-gate  */
3177c478bd9Sstevel@tonic-gate int
3187c478bd9Sstevel@tonic-gate devfs_get_all_prom_names(const char *solaris_path, uint_t flags,
3197c478bd9Sstevel@tonic-gate     struct devfs_prom_path **paths)
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate 	int ret, len, i, count = 0;
3227c478bd9Sstevel@tonic-gate 	char *ptr, *prom_path;
3237c478bd9Sstevel@tonic-gate 	struct devfs_prom_path *cur = NULL, *new;
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	if ((ret = prom_obp_vers()) < 0)
3267c478bd9Sstevel@tonic-gate 		return (ret);
3277c478bd9Sstevel@tonic-gate 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
3287c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	if ((ret = devfs_dev_to_prom_names((char *)solaris_path,
3317c478bd9Sstevel@tonic-gate 	    prom_path, MAXVALSIZE)) < 0) {
3327c478bd9Sstevel@tonic-gate 		free(prom_path);
3337c478bd9Sstevel@tonic-gate 		return (ret);
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	for (i = 0; i < ret; i++)
3377c478bd9Sstevel@tonic-gate 		if (prom_path[i] == '\0')
3387c478bd9Sstevel@tonic-gate 			count++;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	*paths = NULL;
3417c478bd9Sstevel@tonic-gate 	ptr = prom_path;
3427c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
3437c478bd9Sstevel@tonic-gate 		if ((new = (struct devfs_prom_path *)calloc(
3447c478bd9Sstevel@tonic-gate 		    sizeof (struct devfs_prom_path), 1)) == NULL) {
3457c478bd9Sstevel@tonic-gate 			free(prom_path);
3467c478bd9Sstevel@tonic-gate 			devfs_free_all_prom_names(*paths);
3477c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 		if (cur == NULL)
3517c478bd9Sstevel@tonic-gate 			*paths = new;
3527c478bd9Sstevel@tonic-gate 		else
3537c478bd9Sstevel@tonic-gate 			cur->next = new;
3547c478bd9Sstevel@tonic-gate 		cur = new;
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 		len = strlen(ptr) + 1;
3577c478bd9Sstevel@tonic-gate 		if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) {
3587c478bd9Sstevel@tonic-gate 			free(prom_path);
3597c478bd9Sstevel@tonic-gate 			devfs_free_all_prom_names(*paths);
3607c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
3617c478bd9Sstevel@tonic-gate 		}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 		(void) snprintf(cur->obp_path, len, "%s", ptr);
3647c478bd9Sstevel@tonic-gate 		ptr += len;
3657c478bd9Sstevel@tonic-gate 		if ((ret = prom_dev_to_alias(cur->obp_path, flags,
3667c478bd9Sstevel@tonic-gate 		    &(cur->alias_list))) < 0) {
3677c478bd9Sstevel@tonic-gate 			free(prom_path);
3687c478bd9Sstevel@tonic-gate 			devfs_free_all_prom_names(*paths);
3697c478bd9Sstevel@tonic-gate 			return (ret);
3707c478bd9Sstevel@tonic-gate 		}
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	free(prom_path);
3747c478bd9Sstevel@tonic-gate 	return (count);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate void
3787c478bd9Sstevel@tonic-gate devfs_free_all_prom_names(struct devfs_prom_path *paths)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	int i;
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 	if (paths == NULL)
3837c478bd9Sstevel@tonic-gate 		return;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	devfs_free_all_prom_names(paths->next);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (paths->obp_path != NULL)
3887c478bd9Sstevel@tonic-gate 		free(paths->obp_path);
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if (paths->alias_list != NULL) {
3917c478bd9Sstevel@tonic-gate 		for (i = 0; paths->alias_list[i] != NULL; i++)
3927c478bd9Sstevel@tonic-gate 			if (paths->alias_list[i] != NULL)
3937c478bd9Sstevel@tonic-gate 				free(paths->alias_list[i]);
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 		free(paths->alias_list);
3967c478bd9Sstevel@tonic-gate 	}
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	free(paths);
3997c478bd9Sstevel@tonic-gate }
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate  * Accepts a device name as an input argument.  Uses this to set the
4037c478bd9Sstevel@tonic-gate  * boot-device (or like) variable
4047c478bd9Sstevel@tonic-gate  *
4057c478bd9Sstevel@tonic-gate  * By default, this routine prepends to the list and converts the
4067c478bd9Sstevel@tonic-gate  * logical device name to its most compact prom representation.
4077c478bd9Sstevel@tonic-gate  * Available options include: converting the device name to a prom
4087c478bd9Sstevel@tonic-gate  * path name (but not an alias) or performing no conversion at all;
4097c478bd9Sstevel@tonic-gate  * overwriting the existing contents of boot-device rather than
4107c478bd9Sstevel@tonic-gate  * prepending.
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate int
4137c478bd9Sstevel@tonic-gate devfs_bootdev_set_list(const char *dev_name, const uint_t options)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	char *prom_path;
4167c478bd9Sstevel@tonic-gate 	char *new_bootdev;
4177c478bd9Sstevel@tonic-gate 	char *ptr;
4187c478bd9Sstevel@tonic-gate 	char **alias_list = NULL;
4197c478bd9Sstevel@tonic-gate 	char **prom_list = NULL;
4207c478bd9Sstevel@tonic-gate 	Oppbuf  oppbuf;
4217c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
4227c478bd9Sstevel@tonic-gate 	int ret, len, i, j;
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	if (devfs_bootdev_modifiable() != 0) {
4257c478bd9Sstevel@tonic-gate 		return (DEVFS_NOTSUP);
4267c478bd9Sstevel@tonic-gate 	}
4277c478bd9Sstevel@tonic-gate 	if (dev_name == NULL) {
4287c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
4297c478bd9Sstevel@tonic-gate 	}
4307c478bd9Sstevel@tonic-gate 	if (strlen(dev_name) >= MAXPATHLEN)
4317c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) {
4347c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
4357c478bd9Sstevel@tonic-gate 	}
4367c478bd9Sstevel@tonic-gate 	if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) {
4377c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
4387c478bd9Sstevel@tonic-gate 	}
4397c478bd9Sstevel@tonic-gate 	/*
4407c478bd9Sstevel@tonic-gate 	 * if we are prepending, make sure that this obp rev
4417c478bd9Sstevel@tonic-gate 	 * supports multiple boot device entries.
4427c478bd9Sstevel@tonic-gate 	 */
4437c478bd9Sstevel@tonic-gate 	ret = prom_obp_vers();
4447c478bd9Sstevel@tonic-gate 	if (ret < 0) {
4457c478bd9Sstevel@tonic-gate 		return (ret);
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) {
4497c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 	if (options & BOOTDEV_LITERAL) {
4527c478bd9Sstevel@tonic-gate 		(void) strcpy(prom_path, dev_name);
4537c478bd9Sstevel@tonic-gate 	} else {
4547c478bd9Sstevel@tonic-gate 		/* need to convert to prom representation */
4557c478bd9Sstevel@tonic-gate 		ret = devfs_get_prom_name_list(dev_name, &prom_list);
4567c478bd9Sstevel@tonic-gate 		if (ret < 0) {
4577c478bd9Sstevel@tonic-gate 			free(prom_path);
4587c478bd9Sstevel@tonic-gate 			return (ret);
4597c478bd9Sstevel@tonic-gate 		}
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		len = MAXVALSIZE;
4627c478bd9Sstevel@tonic-gate 		i = 0;
4637c478bd9Sstevel@tonic-gate 		ptr = prom_path;
4647c478bd9Sstevel@tonic-gate 		while (prom_list && prom_list[i]) {
4657c478bd9Sstevel@tonic-gate 			if (!(options & BOOTDEV_PROMDEV)) {
4667c478bd9Sstevel@tonic-gate 				ret = prom_dev_to_alias(prom_list[i], 0,
4677c478bd9Sstevel@tonic-gate 					&alias_list);
4687c478bd9Sstevel@tonic-gate 				if (ret < 0) {
4697c478bd9Sstevel@tonic-gate 					free(prom_path);
4707c478bd9Sstevel@tonic-gate 					prom_list_free(prom_list);
4717c478bd9Sstevel@tonic-gate 					return (ret);
4727c478bd9Sstevel@tonic-gate 				}
4737c478bd9Sstevel@tonic-gate 				if ((alias_list != NULL) &&
4747c478bd9Sstevel@tonic-gate 				    (alias_list[0] != NULL)) {
4757c478bd9Sstevel@tonic-gate 					(void) snprintf(ptr, len, "%s ",
4767c478bd9Sstevel@tonic-gate 					    alias_list[0]);
4777c478bd9Sstevel@tonic-gate 					for (ret = 0; alias_list[ret] != NULL;
4787c478bd9Sstevel@tonic-gate 					    ret++)
4797c478bd9Sstevel@tonic-gate 						free(alias_list[ret]);
4807c478bd9Sstevel@tonic-gate 				} else {
4817c478bd9Sstevel@tonic-gate 					(void) snprintf(ptr, len, "%s ",
4827c478bd9Sstevel@tonic-gate 					    prom_list[i]);
4837c478bd9Sstevel@tonic-gate 				}
4847c478bd9Sstevel@tonic-gate 				if (alias_list != NULL)
4857c478bd9Sstevel@tonic-gate 					free(alias_list);
4867c478bd9Sstevel@tonic-gate 			} else {
4877c478bd9Sstevel@tonic-gate 				(void) snprintf(ptr, len, "%s ", prom_list[i]);
4887c478bd9Sstevel@tonic-gate 			}
4897c478bd9Sstevel@tonic-gate 			j = strlen(ptr);
4907c478bd9Sstevel@tonic-gate 			len -= j;
4917c478bd9Sstevel@tonic-gate 			ptr += j;
4927c478bd9Sstevel@tonic-gate 			i++;
4937c478bd9Sstevel@tonic-gate 		}
4947c478bd9Sstevel@tonic-gate 		ptr--;
4957c478bd9Sstevel@tonic-gate 		*ptr = NULL;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 		prom_list_free(prom_list);
4987c478bd9Sstevel@tonic-gate 	}
4997c478bd9Sstevel@tonic-gate 	if (options & BOOTDEV_OVERWRITE) {
5007c478bd9Sstevel@tonic-gate 		new_bootdev = prom_path;
5017c478bd9Sstevel@tonic-gate 	} else {
5027c478bd9Sstevel@tonic-gate 		/* retrieve the current value of boot-device */
5037c478bd9Sstevel@tonic-gate 		ret = get_boot_dev_var(opp);
5047c478bd9Sstevel@tonic-gate 		if (ret < 0) {
5057c478bd9Sstevel@tonic-gate 			free(prom_path);
5067c478bd9Sstevel@tonic-gate 			return (ret);
5077c478bd9Sstevel@tonic-gate 		}
5087c478bd9Sstevel@tonic-gate 		/* prepend new entry - deal with duplicates */
5097c478bd9Sstevel@tonic-gate 		new_bootdev = (char *)malloc(strlen(opp->oprom_array)
5107c478bd9Sstevel@tonic-gate 		    + strlen(prom_path) + 2);
5117c478bd9Sstevel@tonic-gate 		if (new_bootdev == NULL) {
5127c478bd9Sstevel@tonic-gate 			free(prom_path);
5137c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
5147c478bd9Sstevel@tonic-gate 		}
5157c478bd9Sstevel@tonic-gate 		(void) strcpy(new_bootdev, prom_path);
5167c478bd9Sstevel@tonic-gate 		if (opp->oprom_size > 0) {
5177c478bd9Sstevel@tonic-gate 			for (ptr = strtok(opp->oprom_array, " "); ptr != NULL;
5187c478bd9Sstevel@tonic-gate 			    ptr = strtok(NULL, " ")) {
5197c478bd9Sstevel@tonic-gate 				/* we strip out duplicates */
5207c478bd9Sstevel@tonic-gate 				if (strcmp(prom_path, ptr) == 0) {
5217c478bd9Sstevel@tonic-gate 					continue;
5227c478bd9Sstevel@tonic-gate 				}
5237c478bd9Sstevel@tonic-gate 				(void) strcat(new_bootdev, " ");
5247c478bd9Sstevel@tonic-gate 				(void) strcat(new_bootdev, ptr);
5257c478bd9Sstevel@tonic-gate 			}
5267c478bd9Sstevel@tonic-gate 		}
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	/* now set the new value */
5307c478bd9Sstevel@tonic-gate 	ret = set_boot_dev_var(opp, new_bootdev);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	if (options & BOOTDEV_OVERWRITE) {
5337c478bd9Sstevel@tonic-gate 		free(prom_path);
5347c478bd9Sstevel@tonic-gate 	} else {
5357c478bd9Sstevel@tonic-gate 		free(new_bootdev);
5367c478bd9Sstevel@tonic-gate 		free(prom_path);
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	return (ret);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate  * sets the string bootdev as the new value for boot-device
5447c478bd9Sstevel@tonic-gate  */
5457c478bd9Sstevel@tonic-gate static int
5467c478bd9Sstevel@tonic-gate set_boot_dev_var(struct openpromio *opp, char *bootdev)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	int prom_fd;
5497c478bd9Sstevel@tonic-gate 	int i;
5507c478bd9Sstevel@tonic-gate 	int ret;
5517c478bd9Sstevel@tonic-gate 	char *valbuf;
5527c478bd9Sstevel@tonic-gate 	char *save_bootdev;
5537c478bd9Sstevel@tonic-gate 	char *bootdev_variables[] = {
5547c478bd9Sstevel@tonic-gate 		"boot-device",
5557c478bd9Sstevel@tonic-gate 		"bootdev",
5567c478bd9Sstevel@tonic-gate 		"boot-from",
5577c478bd9Sstevel@tonic-gate 		NULL
5587c478bd9Sstevel@tonic-gate 	};
5597c478bd9Sstevel@tonic-gate 	int found = 0;
5607c478bd9Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	/* query the prom */
5637c478bd9Sstevel@tonic-gate 	prom_fd = prom_open(O_RDWR);
5647c478bd9Sstevel@tonic-gate 	if (prom_fd < 0) {
5657c478bd9Sstevel@tonic-gate 		return (prom_fd);
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	/* get the diagnostic-mode? property */
5697c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, "diagnostic-mode?");
5707c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
5717c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
5727c478bd9Sstevel@tonic-gate 		if ((opp->oprom_size > 0) &&
5737c478bd9Sstevel@tonic-gate 		    (strcmp(opp->oprom_array, "true") == 0)) {
5747c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
5757c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
5767c478bd9Sstevel@tonic-gate 		}
5777c478bd9Sstevel@tonic-gate 	}
5787c478bd9Sstevel@tonic-gate 	/* get the diag-switch? property */
5797c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, "diag-switch?");
5807c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
5817c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
5827c478bd9Sstevel@tonic-gate 		if ((opp->oprom_size > 0) &&
5837c478bd9Sstevel@tonic-gate 		    (strcmp(opp->oprom_array, "true") == 0)) {
5847c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
5857c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
5867c478bd9Sstevel@tonic-gate 		}
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 	/*
5897c478bd9Sstevel@tonic-gate 	 * look for one of the following properties in order:
5907c478bd9Sstevel@tonic-gate 	 *	boot-device
5917c478bd9Sstevel@tonic-gate 	 *	bootdev
5927c478bd9Sstevel@tonic-gate 	 *	boot-from
5937c478bd9Sstevel@tonic-gate 	 *
5947c478bd9Sstevel@tonic-gate 	 * Use the first one that we find.
5957c478bd9Sstevel@tonic-gate 	 */
5967c478bd9Sstevel@tonic-gate 	*ip = 0;
5977c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXPROPSIZE;
5987c478bd9Sstevel@tonic-gate 	while ((opp->oprom_size != 0) && (!found)) {
5997c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXPROPSIZE;
6007c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
6017c478bd9Sstevel@tonic-gate 			break;
6027c478bd9Sstevel@tonic-gate 		}
6037c478bd9Sstevel@tonic-gate 		for (i = 0; bootdev_variables[i] != NULL; i++) {
6047c478bd9Sstevel@tonic-gate 			if (strcmp(opp->oprom_array, bootdev_variables[i])
6057c478bd9Sstevel@tonic-gate 			    == 0) {
6067c478bd9Sstevel@tonic-gate 				found = 1;
6077c478bd9Sstevel@tonic-gate 				break;
6087c478bd9Sstevel@tonic-gate 			}
6097c478bd9Sstevel@tonic-gate 		}
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 	if (found) {
6127c478bd9Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6137c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXVALSIZE;
6147c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
6157c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
6167c478bd9Sstevel@tonic-gate 			return (DEVFS_NOTSUP);
6177c478bd9Sstevel@tonic-gate 		}
6187c478bd9Sstevel@tonic-gate 	} else {
6197c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
6207c478bd9Sstevel@tonic-gate 		return (DEVFS_NOTSUP);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	/* save the old copy in case we fail */
6247c478bd9Sstevel@tonic-gate 	if ((save_bootdev = strdup(opp->oprom_array)) == NULL) {
6257c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
6267c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 	/* set up the new value of boot-device */
6297c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6307c478bd9Sstevel@tonic-gate 	valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
6317c478bd9Sstevel@tonic-gate 	(void) strcpy(valbuf, bootdev);
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
6367c478bd9Sstevel@tonic-gate 		free(save_bootdev);
6377c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
6387c478bd9Sstevel@tonic-gate 		return (DEVFS_ERR);
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	/*
6427c478bd9Sstevel@tonic-gate 	 * now read it back to make sure it took
6437c478bd9Sstevel@tonic-gate 	 */
6447c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6457c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
6467c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
6477c478bd9Sstevel@tonic-gate 		if (_prom_strcmp(opp->oprom_array, bootdev) == 0) {
6487c478bd9Sstevel@tonic-gate 			/* success */
6497c478bd9Sstevel@tonic-gate 			free(save_bootdev);
6507c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
6517c478bd9Sstevel@tonic-gate 			return (0);
6527c478bd9Sstevel@tonic-gate 		}
6537c478bd9Sstevel@tonic-gate 		/* deal with setting it to "" */
6547c478bd9Sstevel@tonic-gate 		if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) {
6557c478bd9Sstevel@tonic-gate 			/* success */
6567c478bd9Sstevel@tonic-gate 			free(save_bootdev);
6577c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
6587c478bd9Sstevel@tonic-gate 			return (0);
6597c478bd9Sstevel@tonic-gate 		}
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 	/*
6627c478bd9Sstevel@tonic-gate 	 * something did not take - write out the old value and
6637c478bd9Sstevel@tonic-gate 	 * hope that we can restore things...
6647c478bd9Sstevel@tonic-gate 	 *
6657c478bd9Sstevel@tonic-gate 	 * unfortunately, there is no way for us to differentiate
6667c478bd9Sstevel@tonic-gate 	 * whether we exceeded the maximum number of characters
6677c478bd9Sstevel@tonic-gate 	 * allowable.  The limit varies from prom rev to prom
6687c478bd9Sstevel@tonic-gate 	 * rev, and on some proms, when the limit is
6697c478bd9Sstevel@tonic-gate 	 * exceeded, whatever was in the
6707c478bd9Sstevel@tonic-gate 	 * boot-device variable becomes unreadable.
6717c478bd9Sstevel@tonic-gate 	 *
6727c478bd9Sstevel@tonic-gate 	 * so if we fail, we will assume we ran out of room.  If we
6737c478bd9Sstevel@tonic-gate 	 * not able to restore the original setting, then we will
6747c478bd9Sstevel@tonic-gate 	 * return DEVFS_ERR instead.
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 	ret = DEVFS_LIMIT;
6777c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6787c478bd9Sstevel@tonic-gate 	valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
6797c478bd9Sstevel@tonic-gate 	(void) strcpy(valbuf, save_bootdev);
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
6847c478bd9Sstevel@tonic-gate 		ret = DEVFS_ERR;
6857c478bd9Sstevel@tonic-gate 	}
6867c478bd9Sstevel@tonic-gate 	free(save_bootdev);
6877c478bd9Sstevel@tonic-gate 	prom_close(prom_fd);
6887c478bd9Sstevel@tonic-gate 	return (ret);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate /*
6917c478bd9Sstevel@tonic-gate  * retrieve the current value for boot-device
6927c478bd9Sstevel@tonic-gate  */
6937c478bd9Sstevel@tonic-gate static int
6947c478bd9Sstevel@tonic-gate get_boot_dev_var(struct openpromio *opp)
6957c478bd9Sstevel@tonic-gate {
6967c478bd9Sstevel@tonic-gate 	int prom_fd;
6977c478bd9Sstevel@tonic-gate 	int i;
6987c478bd9Sstevel@tonic-gate 	char *bootdev_variables[] = {
6997c478bd9Sstevel@tonic-gate 		"boot-device",
7007c478bd9Sstevel@tonic-gate 		"bootdev",
7017c478bd9Sstevel@tonic-gate 		"boot-from",
7027c478bd9Sstevel@tonic-gate 		NULL
7037c478bd9Sstevel@tonic-gate 	};
7047c478bd9Sstevel@tonic-gate 	int found = 0;
7057c478bd9Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	/* query the prom */
7087c478bd9Sstevel@tonic-gate 	prom_fd = prom_open(O_RDONLY);
7097c478bd9Sstevel@tonic-gate 	if (prom_fd < 0) {
7107c478bd9Sstevel@tonic-gate 		return (prom_fd);
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	/* get the diagnostic-mode? property */
7147c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, "diagnostic-mode?");
7157c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
7167c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
7177c478bd9Sstevel@tonic-gate 		if ((opp->oprom_size > 0) &&
7187c478bd9Sstevel@tonic-gate 		    (strcmp(opp->oprom_array, "true") == 0)) {
7197c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
7207c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
7217c478bd9Sstevel@tonic-gate 		}
7227c478bd9Sstevel@tonic-gate 	}
7237c478bd9Sstevel@tonic-gate 	/* get the diag-switch? property */
7247c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, "diag-switch?");
7257c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
7267c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
7277c478bd9Sstevel@tonic-gate 		if ((opp->oprom_size > 0) &&
7287c478bd9Sstevel@tonic-gate 		    (strcmp(opp->oprom_array, "true") == 0)) {
7297c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
7307c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
7317c478bd9Sstevel@tonic-gate 		}
7327c478bd9Sstevel@tonic-gate 	}
7337c478bd9Sstevel@tonic-gate 	/*
7347c478bd9Sstevel@tonic-gate 	 * look for one of the following properties in order:
7357c478bd9Sstevel@tonic-gate 	 *	boot-device
7367c478bd9Sstevel@tonic-gate 	 *	bootdev
7377c478bd9Sstevel@tonic-gate 	 *	boot-from
7387c478bd9Sstevel@tonic-gate 	 *
7397c478bd9Sstevel@tonic-gate 	 * Use the first one that we find.
7407c478bd9Sstevel@tonic-gate 	 */
7417c478bd9Sstevel@tonic-gate 	*ip = 0;
7427c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXPROPSIZE;
7437c478bd9Sstevel@tonic-gate 	while ((opp->oprom_size != 0) && (!found)) {
7447c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXPROPSIZE;
7457c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
7467c478bd9Sstevel@tonic-gate 			break;
7477c478bd9Sstevel@tonic-gate 		}
7487c478bd9Sstevel@tonic-gate 		for (i = 0; bootdev_variables[i] != NULL; i++) {
7497c478bd9Sstevel@tonic-gate 			if (strcmp(opp->oprom_array, bootdev_variables[i])
7507c478bd9Sstevel@tonic-gate 			    == 0) {
7517c478bd9Sstevel@tonic-gate 				found = 1;
7527c478bd9Sstevel@tonic-gate 				break;
7537c478bd9Sstevel@tonic-gate 			}
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 	if (found) {
7577c478bd9Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, bootdev_variables[i]);
7587c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXVALSIZE;
7597c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
7607c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
7617c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
7627c478bd9Sstevel@tonic-gate 		}
7637c478bd9Sstevel@tonic-gate 		/* boot-device exists but contains nothing */
7647c478bd9Sstevel@tonic-gate 		if (opp->oprom_size == 0) {
7657c478bd9Sstevel@tonic-gate 			*opp->oprom_array = '\0';
7667c478bd9Sstevel@tonic-gate 		}
7677c478bd9Sstevel@tonic-gate 	} else {
7687c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
7697c478bd9Sstevel@tonic-gate 		return (DEVFS_NOTSUP);
7707c478bd9Sstevel@tonic-gate 	}
7717c478bd9Sstevel@tonic-gate 	prom_close(prom_fd);
7727c478bd9Sstevel@tonic-gate 	return (0);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate #ifndef __sparc
7767c478bd9Sstevel@tonic-gate static FILE *
7777c478bd9Sstevel@tonic-gate open_diskmap(void)
7787c478bd9Sstevel@tonic-gate {
7797c478bd9Sstevel@tonic-gate 	FILE *fp;
7807c478bd9Sstevel@tonic-gate 	char cmd[PATH_MAX];
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	/* make sure we have a map file */
7837c478bd9Sstevel@tonic-gate 	fp = fopen(GRUBDISK_MAP, "r");
7847c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
7857c478bd9Sstevel@tonic-gate 		(void) snprintf(cmd, sizeof (cmd),
7867c478bd9Sstevel@tonic-gate 		    "%s > /dev/null", CREATE_DISKMAP);
7877c478bd9Sstevel@tonic-gate 		(void) system(cmd);
7887c478bd9Sstevel@tonic-gate 		fp = fopen(GRUBDISK_MAP, "r");
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 	return (fp);
7917c478bd9Sstevel@tonic-gate }
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate static int
7947c478bd9Sstevel@tonic-gate find_x86_boot_device(struct openpromio *opp)
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate 	int ret = DEVFS_ERR;
7977c478bd9Sstevel@tonic-gate 	char *cp, line[MAXVALSIZE + 6];
7987c478bd9Sstevel@tonic-gate 	FILE *file;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	file = open_diskmap();
8017c478bd9Sstevel@tonic-gate 	if (file == NULL)
8027c478bd9Sstevel@tonic-gate 		return (DEVFS_ERR);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	while (fgets(line, MAXVALSIZE + 6, file)) {
8057c478bd9Sstevel@tonic-gate 		if (strncmp(line, "0 ", 2) != 0)
8067c478bd9Sstevel@tonic-gate 			continue;
8077c478bd9Sstevel@tonic-gate 		/* drop new-line */
8087c478bd9Sstevel@tonic-gate 		line[strlen(line) - 1] = '\0';
8097c478bd9Sstevel@tonic-gate 		/*
8107c478bd9Sstevel@tonic-gate 		 * an x86 BIOS only boots a disk, not a partition
8117c478bd9Sstevel@tonic-gate 		 * or a slice, so hard-code :q (p0)
8127c478bd9Sstevel@tonic-gate 		 */
8137c478bd9Sstevel@tonic-gate 		cp = strchr(line + 2, ' ');
8147c478bd9Sstevel@tonic-gate 		if (cp == NULL)
8157c478bd9Sstevel@tonic-gate 			break;
8167c478bd9Sstevel@tonic-gate 		(void) snprintf(opp->oprom_array, MAXVALSIZE,
8177c478bd9Sstevel@tonic-gate 		    "%s:q", cp + 1);
8187c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXVALSIZE;
8197c478bd9Sstevel@tonic-gate 		ret = 0;
8207c478bd9Sstevel@tonic-gate 		break;
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 	(void) fclose(file);
8237c478bd9Sstevel@tonic-gate 	return (ret);
8247c478bd9Sstevel@tonic-gate }
8257c478bd9Sstevel@tonic-gate #endif /* ndef __sparc */
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate /*
8287c478bd9Sstevel@tonic-gate  * retrieve the list of entries in the boot-device configuration
8297c478bd9Sstevel@tonic-gate  * variable.  An array of boot_dev structs will be created, one entry
8307c478bd9Sstevel@tonic-gate  * for each device name in the boot-device variable.  Each entry
8317c478bd9Sstevel@tonic-gate  * in the array will contain the logical device representation of the
8327c478bd9Sstevel@tonic-gate  * boot-device entry, if any.
8337c478bd9Sstevel@tonic-gate  *
8347c478bd9Sstevel@tonic-gate  * default_root. if set, is used to locate logical device entries in
8357c478bd9Sstevel@tonic-gate  * directories other than /dev
8367c478bd9Sstevel@tonic-gate  */
8377c478bd9Sstevel@tonic-gate int
8387c478bd9Sstevel@tonic-gate devfs_bootdev_get_list(const char *default_root,
8397c478bd9Sstevel@tonic-gate 	struct boot_dev ***bootdev_list)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate 	Oppbuf  oppbuf;
8427c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
8437c478bd9Sstevel@tonic-gate 	int i;
8447c478bd9Sstevel@tonic-gate 	struct boot_dev **tmp_list;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	if (default_root == NULL) {
8477c478bd9Sstevel@tonic-gate 		default_root = "";
8487c478bd9Sstevel@tonic-gate 	} else if (*default_root != '/') {
8497c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
8507c478bd9Sstevel@tonic-gate 	}
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	if (bootdev_list == NULL) {
8537c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	/* get the boot-device variable */
8577c478bd9Sstevel@tonic-gate #if defined(sparc)
8587c478bd9Sstevel@tonic-gate 	i = get_boot_dev_var(opp);
8597c478bd9Sstevel@tonic-gate #else
8607c478bd9Sstevel@tonic-gate 	i = find_x86_boot_device(opp);
8617c478bd9Sstevel@tonic-gate #endif
8627c478bd9Sstevel@tonic-gate 	if (i < 0) {
8637c478bd9Sstevel@tonic-gate 		return (i);
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 	/* now try to translate each entry to a logical device. */
8667c478bd9Sstevel@tonic-gate 	i = process_bootdev(opp->oprom_array, default_root, &tmp_list);
8677c478bd9Sstevel@tonic-gate 	if (i == 0) {
8687c478bd9Sstevel@tonic-gate 		*bootdev_list = tmp_list;
8697c478bd9Sstevel@tonic-gate 		return (0);
8707c478bd9Sstevel@tonic-gate 	} else {
8717c478bd9Sstevel@tonic-gate 		return (i);
8727c478bd9Sstevel@tonic-gate 	}
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate /*
8767c478bd9Sstevel@tonic-gate  * loop thru the list of entries in a boot-device configuration
8777c478bd9Sstevel@tonic-gate  * variable.
8787c478bd9Sstevel@tonic-gate  */
8797c478bd9Sstevel@tonic-gate static int
8807c478bd9Sstevel@tonic-gate process_bootdev(const char *bootdevice, const char *default_root,
8817c478bd9Sstevel@tonic-gate 	struct boot_dev ***list)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate 	int i;
8847c478bd9Sstevel@tonic-gate 	char *entry, *ptr;
8857c478bd9Sstevel@tonic-gate 	char prom_path[MAXPATHLEN];
8867c478bd9Sstevel@tonic-gate 	char ret_buf[MAXPATHLEN];
8877c478bd9Sstevel@tonic-gate 	struct boot_dev **bootdev_array;
8887c478bd9Sstevel@tonic-gate 	int num_entries = 0;
8897c478bd9Sstevel@tonic-gate 	int found = 0;
8907c478bd9Sstevel@tonic-gate 	int vers;
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) {
8937c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 	/* count the number of entries */
8967c478bd9Sstevel@tonic-gate 	(void) strcpy(entry, bootdevice);
8977c478bd9Sstevel@tonic-gate 	for (ptr = strtok(entry, " "); ptr != NULL;
8987c478bd9Sstevel@tonic-gate 	    ptr = strtok(NULL, " ")) {
8997c478bd9Sstevel@tonic-gate 		num_entries++;
9007c478bd9Sstevel@tonic-gate 	}
9017c478bd9Sstevel@tonic-gate 	(void) strcpy(entry, bootdevice);
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	bootdev_array = (struct boot_dev **)
9047c478bd9Sstevel@tonic-gate 	    calloc((size_t)num_entries + 1, sizeof (struct boot_dev *));
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	if (bootdev_array == NULL) {
9077c478bd9Sstevel@tonic-gate 		free(entry);
9087c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	vers = prom_obp_vers();
9127c478bd9Sstevel@tonic-gate 	if (vers < 0) {
9137c478bd9Sstevel@tonic-gate 		free(entry);
9147c478bd9Sstevel@tonic-gate 		return (vers);
9157c478bd9Sstevel@tonic-gate 	}
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	/* for each entry in boot-device, do... */
9187c478bd9Sstevel@tonic-gate 	for (ptr = strtok(entry, " "), i = 0; ptr != NULL;
9197c478bd9Sstevel@tonic-gate 	    ptr = strtok(NULL, " "), i++) {
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 		if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) {
9227c478bd9Sstevel@tonic-gate 			devfs_bootdev_free_list(bootdev_array);
9237c478bd9Sstevel@tonic-gate 			free(entry);
9247c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 
927b6f77fefSas 		/*
928b6f77fefSas 		 * prom boot-device may be aliased, so we need to do
929b6f77fefSas 		 * the necessary prom alias to dev translation.
930b6f77fefSas 		 */
931b6f77fefSas 		if (*ptr != '/') {
932b6f77fefSas 			if (alias_to_prom_dev(ptr, prom_path) < 0) {
933b6f77fefSas 				continue;
934b6f77fefSas 			}
935b6f77fefSas 		} else {
936b6f77fefSas 			(void) strcpy(prom_path, ptr);
937b6f77fefSas 		}
938b6f77fefSas 
9397c478bd9Sstevel@tonic-gate 		/* now we have a prom device path - convert to a devfs name */
9407c478bd9Sstevel@tonic-gate 		if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) {
941b6f77fefSas 		    continue;
9427c478bd9Sstevel@tonic-gate 		}
943b6f77fefSas 
9447c478bd9Sstevel@tonic-gate 		/* append any default minor names necessary */
9457c478bd9Sstevel@tonic-gate 		if (process_minor_name(ret_buf, default_root) < 0) {
946b6f77fefSas 		    continue;
9477c478bd9Sstevel@tonic-gate 		}
9487c478bd9Sstevel@tonic-gate 		found = 1;
949b6f77fefSas 
9507c478bd9Sstevel@tonic-gate 		/*
9517c478bd9Sstevel@tonic-gate 		 * store the physical device path for now - when
9527c478bd9Sstevel@tonic-gate 		 * we are all done with the entries, we will convert
9537c478bd9Sstevel@tonic-gate 		 * these to their logical device name equivalents
9547c478bd9Sstevel@tonic-gate 		 */
9557c478bd9Sstevel@tonic-gate 		bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf);
9567c478bd9Sstevel@tonic-gate 	}
9577c478bd9Sstevel@tonic-gate 	/*
9587c478bd9Sstevel@tonic-gate 	 * Convert all of the boot-device entries that translated to a
9597c478bd9Sstevel@tonic-gate 	 * physical device path in /devices to a logical device path
9607c478bd9Sstevel@tonic-gate 	 * in /dev (note that there may be several logical device paths
9617c478bd9Sstevel@tonic-gate 	 * associated with a single physical device path - return them all
9627c478bd9Sstevel@tonic-gate 	 */
9637c478bd9Sstevel@tonic-gate 	if (found) {
9647c478bd9Sstevel@tonic-gate 		if (devfs_phys_to_logical(bootdev_array, num_entries,
9657c478bd9Sstevel@tonic-gate 		    default_root) < 0) {
9667c478bd9Sstevel@tonic-gate 			devfs_bootdev_free_list(bootdev_array);
9677c478bd9Sstevel@tonic-gate 			bootdev_array = NULL;
9687c478bd9Sstevel@tonic-gate 		}
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 	free(entry);
9717c478bd9Sstevel@tonic-gate 	*list = bootdev_array;
9727c478bd9Sstevel@tonic-gate 	return (0);
9737c478bd9Sstevel@tonic-gate }
9747c478bd9Sstevel@tonic-gate 
9757c478bd9Sstevel@tonic-gate /*
9767c478bd9Sstevel@tonic-gate  * We may get a device path from the prom that has no minor name
9777c478bd9Sstevel@tonic-gate  * information included in it.  Since this device name will not
9787c478bd9Sstevel@tonic-gate  * correspond directly to a physical device in /devices, we do our
9797c478bd9Sstevel@tonic-gate  * best to append what the default minor name should be and try this.
9807c478bd9Sstevel@tonic-gate  *
9817c478bd9Sstevel@tonic-gate  * For sparc: we append slice 0 (:a).
9827c478bd9Sstevel@tonic-gate  * For x86: we append fdisk partition 0 (:q).
9837c478bd9Sstevel@tonic-gate  */
9847c478bd9Sstevel@tonic-gate static int
9857c478bd9Sstevel@tonic-gate process_minor_name(char *dev_path, const char *root)
9867c478bd9Sstevel@tonic-gate {
9877c478bd9Sstevel@tonic-gate 	char *cp;
9887c478bd9Sstevel@tonic-gate #if defined(sparc)
9897c478bd9Sstevel@tonic-gate 	const char *default_minor_name = "a";
9907c478bd9Sstevel@tonic-gate #else
9917c478bd9Sstevel@tonic-gate 	const char *default_minor_name = "q";
9927c478bd9Sstevel@tonic-gate #endif
9937c478bd9Sstevel@tonic-gate 	int n;
9947c478bd9Sstevel@tonic-gate 	struct stat stat_buf;
9957c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
9987c478bd9Sstevel@tonic-gate 	/*
9997c478bd9Sstevel@tonic-gate 	 * if the device file already exists as given to us, there
10007c478bd9Sstevel@tonic-gate 	 * is nothing to do but return.
10017c478bd9Sstevel@tonic-gate 	 */
10027c478bd9Sstevel@tonic-gate 	if (stat(path, &stat_buf) == 0) {
10037c478bd9Sstevel@tonic-gate 		return (0);
10047c478bd9Sstevel@tonic-gate 	}
10057c478bd9Sstevel@tonic-gate 	/*
10067c478bd9Sstevel@tonic-gate 	 * if there is no ':' after the last '/' character, or if there is
10077c478bd9Sstevel@tonic-gate 	 * a ':' with no specifier, append the default segment specifier
10087c478bd9Sstevel@tonic-gate 	 * ; if there is a ':' followed by a digit, this indicates
10097c478bd9Sstevel@tonic-gate 	 * a partition number (which does not map into the /devices name
10107c478bd9Sstevel@tonic-gate 	 * space), so strip the number and replace it with the letter
10117c478bd9Sstevel@tonic-gate 	 * that represents the partition index
10127c478bd9Sstevel@tonic-gate 	 */
10137c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(dev_path, '/')) != NULL) {
10147c478bd9Sstevel@tonic-gate 		if ((cp = strchr(cp, ':')) == NULL) {
10157c478bd9Sstevel@tonic-gate 			(void) strcat(dev_path, ":");
10167c478bd9Sstevel@tonic-gate 			(void) strcat(dev_path, default_minor_name);
10177c478bd9Sstevel@tonic-gate 		} else if (*++cp == '\0') {
10187c478bd9Sstevel@tonic-gate 			(void) strcat(dev_path, default_minor_name);
10197c478bd9Sstevel@tonic-gate 		} else if (isdigit(*cp)) {
10207c478bd9Sstevel@tonic-gate 			n = atoi(cp);
10217c478bd9Sstevel@tonic-gate 			/* make sure to squash the digit */
10227c478bd9Sstevel@tonic-gate 			*cp = '\0';
10237c478bd9Sstevel@tonic-gate 			switch (n) {
10247c478bd9Sstevel@tonic-gate 			    case 0:	(void) strcat(dev_path, "q");
10257c478bd9Sstevel@tonic-gate 					break;
10267c478bd9Sstevel@tonic-gate 			    case 1:	(void) strcat(dev_path, "r");
10277c478bd9Sstevel@tonic-gate 					break;
10287c478bd9Sstevel@tonic-gate 			    case 2:	(void) strcat(dev_path, "s");
10297c478bd9Sstevel@tonic-gate 					break;
10307c478bd9Sstevel@tonic-gate 			    case 3:	(void) strcat(dev_path, "t");
10317c478bd9Sstevel@tonic-gate 					break;
10327c478bd9Sstevel@tonic-gate 			    case 4:	(void) strcat(dev_path, "u");
10337c478bd9Sstevel@tonic-gate 					break;
10347c478bd9Sstevel@tonic-gate 			    default:	(void) strcat(dev_path, "a");
10357c478bd9Sstevel@tonic-gate 					break;
10367c478bd9Sstevel@tonic-gate 			}
10377c478bd9Sstevel@tonic-gate 		}
10387c478bd9Sstevel@tonic-gate 	}
10397c478bd9Sstevel@tonic-gate 	/*
10407c478bd9Sstevel@tonic-gate 	 * see if we can find something now.
10417c478bd9Sstevel@tonic-gate 	 */
10427c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	if (stat(path, &stat_buf) == 0) {
10457c478bd9Sstevel@tonic-gate 		return (0);
10467c478bd9Sstevel@tonic-gate 	} else {
10477c478bd9Sstevel@tonic-gate 		return (-1);
10487c478bd9Sstevel@tonic-gate 	}
10497c478bd9Sstevel@tonic-gate }
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate /*
10527c478bd9Sstevel@tonic-gate  * for each entry in bootdev_array, convert the physical device
10537c478bd9Sstevel@tonic-gate  * representation of the boot-device entry to one or more logical device
10547c478bd9Sstevel@tonic-gate  * entries.  We use the hammer method - walk through the logical device
10557c478bd9Sstevel@tonic-gate  * name space looking for matches (/dev).  We use nftw to do this.
10567c478bd9Sstevel@tonic-gate  */
10577c478bd9Sstevel@tonic-gate static int
10587c478bd9Sstevel@tonic-gate devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size,
10597c478bd9Sstevel@tonic-gate     const char *default_root)
10607c478bd9Sstevel@tonic-gate {
10617c478bd9Sstevel@tonic-gate 	int walk_flags = FTW_PHYS | FTW_MOUNT;
10627c478bd9Sstevel@tonic-gate 	char *full_path;
10637c478bd9Sstevel@tonic-gate 	struct name_list *list;
10647c478bd9Sstevel@tonic-gate 	int count, i;
10657c478bd9Sstevel@tonic-gate 	char **dev_name_array;
10667c478bd9Sstevel@tonic-gate 	size_t default_root_len;
10677c478bd9Sstevel@tonic-gate 	char *dev_dir = DEV;
10687c478bd9Sstevel@tonic-gate 	int len;
10697c478bd9Sstevel@tonic-gate 
10707c478bd9Sstevel@tonic-gate 	if (array_size < 0) {
10717c478bd9Sstevel@tonic-gate 		return (-1);
10727c478bd9Sstevel@tonic-gate 	}
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	if (bootdev_array == NULL) {
10757c478bd9Sstevel@tonic-gate 		return (-1);
10767c478bd9Sstevel@tonic-gate 	}
10777c478bd9Sstevel@tonic-gate 	if (default_root == NULL) {
10787c478bd9Sstevel@tonic-gate 		return (-1);
10797c478bd9Sstevel@tonic-gate 	}
10807c478bd9Sstevel@tonic-gate 	default_root_len = strlen(default_root);
10817c478bd9Sstevel@tonic-gate 	if ((default_root_len != 0) && (*default_root != '/')) {
10827c478bd9Sstevel@tonic-gate 		return (-1);
10837c478bd9Sstevel@tonic-gate 	}
1084b6f77fefSas 
10857c478bd9Sstevel@tonic-gate 	/* short cut for an empty array */
10867c478bd9Sstevel@tonic-gate 	if (*bootdev_array == NULL) {
10877c478bd9Sstevel@tonic-gate 		return (0);
10887c478bd9Sstevel@tonic-gate 	}
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	/* tell nftw where to start (default: /dev) */
10917c478bd9Sstevel@tonic-gate 	len = default_root_len + strlen(dev_dir) + 1;
10927c478bd9Sstevel@tonic-gate 	if ((full_path = (char *)malloc(len)) == NULL) {
10937c478bd9Sstevel@tonic-gate 		return (-1);
10947c478bd9Sstevel@tonic-gate 	}
1095b6f77fefSas 
10967c478bd9Sstevel@tonic-gate 	/*
10977c478bd9Sstevel@tonic-gate 	 * if the default root path is terminated with a /, we have to
10987c478bd9Sstevel@tonic-gate 	 * make sure we don't end up with one too many slashes in the
10997c478bd9Sstevel@tonic-gate 	 * path we are building.
11007c478bd9Sstevel@tonic-gate 	 */
11017c478bd9Sstevel@tonic-gate 	if ((default_root_len > (size_t)0) &&
11027c478bd9Sstevel@tonic-gate 	    (default_root[default_root_len - 1] == '/')) {
11037c478bd9Sstevel@tonic-gate 		(void) snprintf(full_path, len, "%s%s", default_root,
11047c478bd9Sstevel@tonic-gate 		    &dev_dir[1]);
11057c478bd9Sstevel@tonic-gate 	} else {
11067c478bd9Sstevel@tonic-gate 		(void) snprintf(full_path, len, "%s%s", default_root, dev_dir);
11077c478bd9Sstevel@tonic-gate 	}
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	/*
11107c478bd9Sstevel@tonic-gate 	 * we need to muck with global data to make nftw work
11117c478bd9Sstevel@tonic-gate 	 * so single thread access
11127c478bd9Sstevel@tonic-gate 	 */
11137c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&dev_lists_lk);
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	/*
11167c478bd9Sstevel@tonic-gate 	 * set the global vars bootdev_list and dev_list for use by nftw
11177c478bd9Sstevel@tonic-gate 	 * dev_list is an array of lists - one for each boot-device
11187c478bd9Sstevel@tonic-gate 	 * entry.  The nftw function will create a list of logical device
11197c478bd9Sstevel@tonic-gate 	 * entries for each boot-device and put all of the lists in
11207c478bd9Sstevel@tonic-gate 	 * dev_list.
11217c478bd9Sstevel@tonic-gate 	 */
11227c478bd9Sstevel@tonic-gate 	dev_list = (struct name_list **)
11237c478bd9Sstevel@tonic-gate 	    calloc(array_size, sizeof (struct name_list *));
11247c478bd9Sstevel@tonic-gate 	if (dev_list == NULL) {
11257c478bd9Sstevel@tonic-gate 		free(full_path);
11267c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&dev_lists_lk);
11277c478bd9Sstevel@tonic-gate 		return (-1);
11287c478bd9Sstevel@tonic-gate 	}
11297c478bd9Sstevel@tonic-gate 	bootdev_list = bootdev_array;
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 	if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) {
11327c478bd9Sstevel@tonic-gate 		bootdev_list = NULL;
11337c478bd9Sstevel@tonic-gate 		free(full_path);
11347c478bd9Sstevel@tonic-gate 		for (i = 0; i < array_size; i++) {
11357c478bd9Sstevel@tonic-gate 			free_name_list(dev_list[i], 1);
11367c478bd9Sstevel@tonic-gate 		}
11377c478bd9Sstevel@tonic-gate 		/* don't free dev_list here because it's been handed off */
11387c478bd9Sstevel@tonic-gate 		dev_list = NULL;
11397c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&dev_lists_lk);
11407c478bd9Sstevel@tonic-gate 		return (-1);
11417c478bd9Sstevel@tonic-gate 	}
1142b6f77fefSas 
11437c478bd9Sstevel@tonic-gate 	/*
11447c478bd9Sstevel@tonic-gate 	 * now we have a filled in dev_list.  So for each logical device
11457c478bd9Sstevel@tonic-gate 	 * list in dev_list, count the number of entries in the list,
11467c478bd9Sstevel@tonic-gate 	 * create an array of strings of logical devices, and save in the
11477c478bd9Sstevel@tonic-gate 	 * corresponding boot_dev structure.
11487c478bd9Sstevel@tonic-gate 	 */
11497c478bd9Sstevel@tonic-gate 	for (i = 0; i < array_size; i++) {
11507c478bd9Sstevel@tonic-gate 		/* get the next list */
11517c478bd9Sstevel@tonic-gate 		list = dev_list[i];
11527c478bd9Sstevel@tonic-gate 		count = 0;
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 		/* count the number of entries in the list */
11557c478bd9Sstevel@tonic-gate 		while (list != NULL) {
11567c478bd9Sstevel@tonic-gate 			count++;
11577c478bd9Sstevel@tonic-gate 			list = list->next;
11587c478bd9Sstevel@tonic-gate 		}
11597c478bd9Sstevel@tonic-gate 		if ((dev_name_array =
11607c478bd9Sstevel@tonic-gate 		    (char **)malloc((count + 1) * sizeof (char *)))
11617c478bd9Sstevel@tonic-gate 		    == NULL) {
11627c478bd9Sstevel@tonic-gate 			continue;
11637c478bd9Sstevel@tonic-gate 		}
11647c478bd9Sstevel@tonic-gate 		list = dev_list[i];
11657c478bd9Sstevel@tonic-gate 		count = 0;
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 		/* fill in the array */
11687c478bd9Sstevel@tonic-gate 		while (list != NULL) {
11697c478bd9Sstevel@tonic-gate 			dev_name_array[count] = list->name;
11707c478bd9Sstevel@tonic-gate 			count++;
11717c478bd9Sstevel@tonic-gate 			list = list->next;
11727c478bd9Sstevel@tonic-gate 		}
1173b6f77fefSas 
11747c478bd9Sstevel@tonic-gate 		/*
11757c478bd9Sstevel@tonic-gate 		 * null terminate the array
11767c478bd9Sstevel@tonic-gate 		 */
11777c478bd9Sstevel@tonic-gate 		dev_name_array[count] = NULL;
1178b6f77fefSas 		if ((bootdev_array[i] != NULL) && (bootdev_array[i]->
1179b6f77fefSas 		    bootdev_trans[0] != NULL)) {
11807c478bd9Sstevel@tonic-gate 			free(bootdev_array[i]->bootdev_trans[0]);
11817c478bd9Sstevel@tonic-gate 		}
1182b6f77fefSas 		if (bootdev_array[i] != NULL) {
1183b6f77fefSas 			free(bootdev_array[i]->bootdev_trans);
1184b6f77fefSas 			bootdev_array[i]->bootdev_trans = dev_name_array;
1185b6f77fefSas 		}
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 	bootdev_list = NULL;
11887c478bd9Sstevel@tonic-gate 	free(full_path);
11897c478bd9Sstevel@tonic-gate 	for (i = 0; i < array_size; i++) {
11907c478bd9Sstevel@tonic-gate 		free_name_list(dev_list[i], 0);
11917c478bd9Sstevel@tonic-gate 	}
11927c478bd9Sstevel@tonic-gate 	free(dev_list);
11937c478bd9Sstevel@tonic-gate 	dev_list = NULL;
11947c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&dev_lists_lk);
11957c478bd9Sstevel@tonic-gate 	return (0);
11967c478bd9Sstevel@tonic-gate }
11977c478bd9Sstevel@tonic-gate /*
11987c478bd9Sstevel@tonic-gate  * nftw function
11997c478bd9Sstevel@tonic-gate  * for a logical dev entry, it walks the list of boot-devices and
12007c478bd9Sstevel@tonic-gate  * sees if there are any matches.  If so, it saves the logical device
12017c478bd9Sstevel@tonic-gate  * name off in the appropriate list in dev_list
12027c478bd9Sstevel@tonic-gate  */
12037c478bd9Sstevel@tonic-gate /* ARGSUSED */
12047c478bd9Sstevel@tonic-gate static int
12057c478bd9Sstevel@tonic-gate check_logical_dev(const char *node, const struct stat *node_stat, int flags,
12067c478bd9Sstevel@tonic-gate 	struct FTW *ftw_info)
12077c478bd9Sstevel@tonic-gate {
12087c478bd9Sstevel@tonic-gate 	char link_buf[MAXPATHLEN];
12097c478bd9Sstevel@tonic-gate 	int link_buf_len;
12107c478bd9Sstevel@tonic-gate 	char *name;
12117c478bd9Sstevel@tonic-gate 	struct name_list *dev;
12127c478bd9Sstevel@tonic-gate 	char *physdev;
12137c478bd9Sstevel@tonic-gate 	int i;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	if (flags != FTW_SL) {
12167c478bd9Sstevel@tonic-gate 		return (0);
12177c478bd9Sstevel@tonic-gate 	}
12187c478bd9Sstevel@tonic-gate 
12197c478bd9Sstevel@tonic-gate 	if ((link_buf_len = readlink(node, (void *)link_buf, MAXPATHLEN))
12207c478bd9Sstevel@tonic-gate 	    == -1) {
12217c478bd9Sstevel@tonic-gate 		return (0);
12227c478bd9Sstevel@tonic-gate 	}
12237c478bd9Sstevel@tonic-gate 	link_buf[link_buf_len] = '\0';
12247c478bd9Sstevel@tonic-gate 	if ((name = strstr(link_buf, DEVICES)) == NULL) {
12257c478bd9Sstevel@tonic-gate 		return (0);
12267c478bd9Sstevel@tonic-gate 	}
12277c478bd9Sstevel@tonic-gate 	name = (char *)(name + strlen(DEVICES));
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	for (i = 0; bootdev_list[i] != NULL; i++) {
12307c478bd9Sstevel@tonic-gate 		if (bootdev_list[i]->bootdev_trans[0] == NULL) {
12317c478bd9Sstevel@tonic-gate 			continue;
12327c478bd9Sstevel@tonic-gate 		}
12337c478bd9Sstevel@tonic-gate 		/*
12347c478bd9Sstevel@tonic-gate 		 * compare the contents of the link with the physical
12357c478bd9Sstevel@tonic-gate 		 * device representation of this boot device
12367c478bd9Sstevel@tonic-gate 		 */
12377c478bd9Sstevel@tonic-gate 		physdev = bootdev_list[i]->bootdev_trans[0];
12387c478bd9Sstevel@tonic-gate 		if ((strcmp(name, physdev) == 0) &&
12397c478bd9Sstevel@tonic-gate 		    (strlen(name) == strlen(physdev))) {
12407c478bd9Sstevel@tonic-gate 			if ((dev = (struct name_list *)
12417c478bd9Sstevel@tonic-gate 			    malloc(sizeof (struct name_list))) == NULL) {
12427c478bd9Sstevel@tonic-gate 				return (-1);
12437c478bd9Sstevel@tonic-gate 			}
12447c478bd9Sstevel@tonic-gate 			if ((dev->name = strdup(node)) == NULL) {
12457c478bd9Sstevel@tonic-gate 				free(dev);
12467c478bd9Sstevel@tonic-gate 				return (-1);
12477c478bd9Sstevel@tonic-gate 			}
12487c478bd9Sstevel@tonic-gate 			if (dev_list[i] == NULL) {
12497c478bd9Sstevel@tonic-gate 				dev_list[i] = dev;
12507c478bd9Sstevel@tonic-gate 				dev_list[i]->next = NULL;
12517c478bd9Sstevel@tonic-gate 			} else {
12527c478bd9Sstevel@tonic-gate 				dev->next = dev_list[i];
12537c478bd9Sstevel@tonic-gate 				dev_list[i] = dev;
12547c478bd9Sstevel@tonic-gate 			}
12557c478bd9Sstevel@tonic-gate 		}
12567c478bd9Sstevel@tonic-gate 	}
12577c478bd9Sstevel@tonic-gate 	return (0);
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate /*
12617c478bd9Sstevel@tonic-gate  * frees a list of boot_dev struct pointers
12627c478bd9Sstevel@tonic-gate  */
12637c478bd9Sstevel@tonic-gate void
12647c478bd9Sstevel@tonic-gate devfs_bootdev_free_list(struct boot_dev **array)
12657c478bd9Sstevel@tonic-gate {
12667c478bd9Sstevel@tonic-gate 	int i = 0;
12677c478bd9Sstevel@tonic-gate 	int j;
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	if (array == NULL) {
12707c478bd9Sstevel@tonic-gate 		return;
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	while (array[i] != NULL) {
12747c478bd9Sstevel@tonic-gate 		free(array[i]->bootdev_element);
12757c478bd9Sstevel@tonic-gate 		j = 0;
12767c478bd9Sstevel@tonic-gate 		while (array[i]->bootdev_trans[j] != NULL) {
12777c478bd9Sstevel@tonic-gate 			free(array[i]->bootdev_trans[j++]);
12787c478bd9Sstevel@tonic-gate 		}
12797c478bd9Sstevel@tonic-gate 		free(array[i]->bootdev_trans);
12807c478bd9Sstevel@tonic-gate 		free(array[i]);
12817c478bd9Sstevel@tonic-gate 		i++;
12827c478bd9Sstevel@tonic-gate 	}
12837c478bd9Sstevel@tonic-gate 	free(array);
12847c478bd9Sstevel@tonic-gate }
12857c478bd9Sstevel@tonic-gate /*
12867c478bd9Sstevel@tonic-gate  * allocates a boot_dev struct and fills in the bootdev_element portion
12877c478bd9Sstevel@tonic-gate  */
12887c478bd9Sstevel@tonic-gate static struct boot_dev *
12897c478bd9Sstevel@tonic-gate alloc_bootdev(char *entry_name)
12907c478bd9Sstevel@tonic-gate {
12917c478bd9Sstevel@tonic-gate 	struct boot_dev *entry;
12927c478bd9Sstevel@tonic-gate 
12937c478bd9Sstevel@tonic-gate 	entry = (struct boot_dev *)calloc(1, sizeof (struct boot_dev));
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	if (entry == NULL) {
12967c478bd9Sstevel@tonic-gate 		return (NULL);
12977c478bd9Sstevel@tonic-gate 	}
12987c478bd9Sstevel@tonic-gate 	if ((entry->bootdev_element = strdup(entry_name)) == NULL) {
12997c478bd9Sstevel@tonic-gate 		free(entry);
13007c478bd9Sstevel@tonic-gate 		return (NULL);
13017c478bd9Sstevel@tonic-gate 	}
13027c478bd9Sstevel@tonic-gate 	/*
13037c478bd9Sstevel@tonic-gate 	 * Allocate room for 1 name and a null terminator - the caller of
13047c478bd9Sstevel@tonic-gate 	 * this function will need the first slot right away.
13057c478bd9Sstevel@tonic-gate 	 */
13067c478bd9Sstevel@tonic-gate 	if ((entry->bootdev_trans = (char **)calloc(2, sizeof (char *)))
13077c478bd9Sstevel@tonic-gate 	    == NULL) {
13087c478bd9Sstevel@tonic-gate 		free(entry->bootdev_element);
13097c478bd9Sstevel@tonic-gate 		free(entry);
13107c478bd9Sstevel@tonic-gate 		return (NULL);
13117c478bd9Sstevel@tonic-gate 	}
13127c478bd9Sstevel@tonic-gate 	return (entry);
13137c478bd9Sstevel@tonic-gate }
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate /*
13167c478bd9Sstevel@tonic-gate  * will come back with a concatenated list of paths
13177c478bd9Sstevel@tonic-gate  */
13187c478bd9Sstevel@tonic-gate int
13197c478bd9Sstevel@tonic-gate devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len)
13207c478bd9Sstevel@tonic-gate {
13217c478bd9Sstevel@tonic-gate 	Oppbuf oppbuf;
13227c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
13237c478bd9Sstevel@tonic-gate 	int prom_fd;
13247c478bd9Sstevel@tonic-gate 	int ret = DEVFS_INVAL;
13257c478bd9Sstevel@tonic-gate 	int i;
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	if (prom_path == NULL) {
13287c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 	if (dev_path == NULL) {
13317c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
13327c478bd9Sstevel@tonic-gate 	}
13337c478bd9Sstevel@tonic-gate 	if (strlen(dev_path) >= MAXPATHLEN)
13347c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	if (*dev_path != '/')
13377c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	prom_fd = prom_open(O_RDONLY);
13407c478bd9Sstevel@tonic-gate 	if (prom_fd < 0) {
13417c478bd9Sstevel@tonic-gate 		return (prom_fd);
13427c478bd9Sstevel@tonic-gate 	}
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	/* query the prom */
13457c478bd9Sstevel@tonic-gate 	(void) snprintf(opp->oprom_array, MAXVALSIZE, "%s", dev_path);
13467c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMDEV2PROMNAME, opp) == 0) {
13497c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 		/* return the prom path in prom_path */
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 		i = len - opp->oprom_size;
13547c478bd9Sstevel@tonic-gate 		if (i < 0) {
13557c478bd9Sstevel@tonic-gate 			bcopy(opp->oprom_array, prom_path, len);
13567c478bd9Sstevel@tonic-gate 			prom_path[len - 1] = NULL;
13577c478bd9Sstevel@tonic-gate 			return (len);
13587c478bd9Sstevel@tonic-gate 		} else {
13597c478bd9Sstevel@tonic-gate 			bcopy(opp->oprom_array, prom_path, len);
13607c478bd9Sstevel@tonic-gate 			return (opp->oprom_size);
13617c478bd9Sstevel@tonic-gate 		}
13627c478bd9Sstevel@tonic-gate 	}
13637c478bd9Sstevel@tonic-gate 	/*
13647c478bd9Sstevel@tonic-gate 	 * either the prom does not support this ioctl or the argument
13657c478bd9Sstevel@tonic-gate 	 * was invalid.
13667c478bd9Sstevel@tonic-gate 	 */
13677c478bd9Sstevel@tonic-gate 	if (errno == ENXIO) {
13687c478bd9Sstevel@tonic-gate 		ret = DEVFS_NOTSUP;
13697c478bd9Sstevel@tonic-gate 	}
13707c478bd9Sstevel@tonic-gate 	prom_close(prom_fd);
13717c478bd9Sstevel@tonic-gate 	return (ret);
13727c478bd9Sstevel@tonic-gate }
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate /*
13757c478bd9Sstevel@tonic-gate  * Convert a physical or logical device name to a name the prom would
13767c478bd9Sstevel@tonic-gate  * understand.  Fail if this platform does not support a prom or if
13777c478bd9Sstevel@tonic-gate  * the device does not correspond to a valid prom device.
13787c478bd9Sstevel@tonic-gate  *      dev_path should be the name of a device in the logical or
13797c478bd9Sstevel@tonic-gate  *              physical device namespace.
13807c478bd9Sstevel@tonic-gate  *      prom_path is the prom version of the device name
13817c478bd9Sstevel@tonic-gate  *      prom_path must be large enough to contain the result and is
13827c478bd9Sstevel@tonic-gate  *      supplied by the user.
13837c478bd9Sstevel@tonic-gate  *
13847c478bd9Sstevel@tonic-gate  * This routine only supports converting leaf device paths
13857c478bd9Sstevel@tonic-gate  */
13867c478bd9Sstevel@tonic-gate int
13877c478bd9Sstevel@tonic-gate devfs_dev_to_prom_name(char *dev_path, char *prom_path)
13887c478bd9Sstevel@tonic-gate {
13897c478bd9Sstevel@tonic-gate 	int rval;
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 	rval = devfs_dev_to_prom_names(dev_path, prom_path, MAXPATHLEN);
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	if (rval < 0)
13947c478bd9Sstevel@tonic-gate 		return (rval);
13957c478bd9Sstevel@tonic-gate 	else
13967c478bd9Sstevel@tonic-gate 		return (0);
13977c478bd9Sstevel@tonic-gate }
13987c478bd9Sstevel@tonic-gate 
13997c478bd9Sstevel@tonic-gate /*
14007c478bd9Sstevel@tonic-gate  * Use the openprom driver's OPROMPATH2DRV ioctl to convert a devfs
14017c478bd9Sstevel@tonic-gate  * path to a driver name.
14027c478bd9Sstevel@tonic-gate  * devfs_path - the pathname of interest.  This must be the physcical device
14037c478bd9Sstevel@tonic-gate  * path with the mount point prefix (ie. /devices) stripped off.
14047c478bd9Sstevel@tonic-gate  * drv_buf - user supplied buffer - the driver name will be stored here.
14057c478bd9Sstevel@tonic-gate  *
14067c478bd9Sstevel@tonic-gate  * If the prom lookup fails, we return the name of the last component in
14077c478bd9Sstevel@tonic-gate  * the pathname.  This routine is useful for looking up driver names
14087c478bd9Sstevel@tonic-gate  * associated with generically named devices.
14097c478bd9Sstevel@tonic-gate  *
14107c478bd9Sstevel@tonic-gate  * This routine returns driver names that have aliases resolved.
14117c478bd9Sstevel@tonic-gate  */
14127c478bd9Sstevel@tonic-gate int
14137c478bd9Sstevel@tonic-gate devfs_path_to_drv(char *devfs_path, char *drv_buf)
14147c478bd9Sstevel@tonic-gate {
14157c478bd9Sstevel@tonic-gate 	Oppbuf oppbuf;
14167c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
14177c478bd9Sstevel@tonic-gate 	char *slash, *colon, *dev_addr;
14187c478bd9Sstevel@tonic-gate 	char driver_path[MAXPATHLEN];
14197c478bd9Sstevel@tonic-gate 	int prom_fd;
14207c478bd9Sstevel@tonic-gate 
14217c478bd9Sstevel@tonic-gate 	if (drv_buf == NULL) {
14227c478bd9Sstevel@tonic-gate 		return (-1);
14237c478bd9Sstevel@tonic-gate 	}
14247c478bd9Sstevel@tonic-gate 	if (devfs_path == NULL) {
14257c478bd9Sstevel@tonic-gate 		return (-1);
14267c478bd9Sstevel@tonic-gate 	}
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	if (strlen(devfs_path) >= MAXPATHLEN)
14297c478bd9Sstevel@tonic-gate 		return (-1);
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	if (*devfs_path != '/')
14327c478bd9Sstevel@tonic-gate 		return (-1);
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	/* strip off any minor node info at the end of the path */
14367c478bd9Sstevel@tonic-gate 	(void) strcpy(driver_path, devfs_path);
14377c478bd9Sstevel@tonic-gate 	slash = strrchr(driver_path, '/');
14387c478bd9Sstevel@tonic-gate 	if (slash == NULL)
14397c478bd9Sstevel@tonic-gate 		return (-1);
14407c478bd9Sstevel@tonic-gate 	colon = strrchr(slash, ':');
14417c478bd9Sstevel@tonic-gate 	if (colon != NULL)
14427c478bd9Sstevel@tonic-gate 		*colon = '\0';
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	/* query the prom */
14457c478bd9Sstevel@tonic-gate 	if ((prom_fd = prom_open(O_RDONLY)) >= 0) {
14467c478bd9Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, driver_path);
14477c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXVALSIZE;
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMPATH2DRV, opp) == 0) {
14507c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
14517c478bd9Sstevel@tonic-gate 			/* return the driver name in drv_buf */
14527c478bd9Sstevel@tonic-gate 			(void) strcpy(drv_buf, opp->oprom_array);
14537c478bd9Sstevel@tonic-gate 			return (0);
14547c478bd9Sstevel@tonic-gate 		}
14557c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
14567c478bd9Sstevel@tonic-gate 	} else if (prom_fd != DEVFS_NOTSUP)
14577c478bd9Sstevel@tonic-gate 		return (-1);
14587c478bd9Sstevel@tonic-gate 	/*
14597c478bd9Sstevel@tonic-gate 	 * If we get here, then either:
14607c478bd9Sstevel@tonic-gate 	 *	1. this platform does not support an openprom driver
14617c478bd9Sstevel@tonic-gate 	 *	2. we were asked to look up a device the prom does
14627c478bd9Sstevel@tonic-gate 	 *	   not know about (e.g. a pseudo device)
14637c478bd9Sstevel@tonic-gate 	 * In this case, we use the last component of the devfs path
14647c478bd9Sstevel@tonic-gate 	 * name and try to derive the driver name
14657c478bd9Sstevel@tonic-gate 	 */
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	/* use the last component of devfs_path as the driver name */
14687c478bd9Sstevel@tonic-gate 	if ((dev_addr = strrchr(slash, '@')) != NULL)
14697c478bd9Sstevel@tonic-gate 		*dev_addr = '\0';
14707c478bd9Sstevel@tonic-gate 	slash++;
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	/* use opp->oprom_array as a buffer */
14737c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, slash);
14747c478bd9Sstevel@tonic-gate 	if (devfs_resolve_aliases(opp->oprom_array) == NULL)
14757c478bd9Sstevel@tonic-gate 		return (-1);
14767c478bd9Sstevel@tonic-gate 	(void) strcpy(drv_buf, opp->oprom_array);
14777c478bd9Sstevel@tonic-gate 	return (0);
14787c478bd9Sstevel@tonic-gate }
14797c478bd9Sstevel@tonic-gate 
14807c478bd9Sstevel@tonic-gate /*
14817c478bd9Sstevel@tonic-gate  * These modctl calls do the equivalent of:
14827c478bd9Sstevel@tonic-gate  *	ddi_name_to_major()
14837c478bd9Sstevel@tonic-gate  *	ddi_major_to_name()
14847c478bd9Sstevel@tonic-gate  * This results in two things:
14857c478bd9Sstevel@tonic-gate  *	- the driver name must be a valid one
14867c478bd9Sstevel@tonic-gate  *	- any driver aliases are resolved.
14877c478bd9Sstevel@tonic-gate  * drv is overwritten with the resulting name.
14887c478bd9Sstevel@tonic-gate  */
14897c478bd9Sstevel@tonic-gate char *
14907c478bd9Sstevel@tonic-gate devfs_resolve_aliases(char *drv)
14917c478bd9Sstevel@tonic-gate {
14927c478bd9Sstevel@tonic-gate 	major_t maj;
14937c478bd9Sstevel@tonic-gate 	char driver_name[MAXNAMELEN + 1];
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	if (drv == NULL) {
14967c478bd9Sstevel@tonic-gate 		return (NULL);
14977c478bd9Sstevel@tonic-gate 	}
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	if (modctl(MODGETMAJBIND, drv, strlen(drv) + 1, &maj) < 0)
15007c478bd9Sstevel@tonic-gate 		return (NULL);
15017c478bd9Sstevel@tonic-gate 	else if (modctl(MODGETNAME, driver_name, sizeof (driver_name), &maj)
15027c478bd9Sstevel@tonic-gate 	    < 0) {
15037c478bd9Sstevel@tonic-gate 		return (NULL);
15047c478bd9Sstevel@tonic-gate 	} else {
15057c478bd9Sstevel@tonic-gate 		(void) strcpy(drv, driver_name);
15067c478bd9Sstevel@tonic-gate 		return (drv);
15077c478bd9Sstevel@tonic-gate 	}
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate /*
15117c478bd9Sstevel@tonic-gate  * open the openprom device.  and verify that we are on an
15127c478bd9Sstevel@tonic-gate  * OBP/1275 OF machine.  If the prom does not exist, then we
15137c478bd9Sstevel@tonic-gate  * return an error
15147c478bd9Sstevel@tonic-gate  */
15157c478bd9Sstevel@tonic-gate static int
15167c478bd9Sstevel@tonic-gate prom_open(int oflag)
15177c478bd9Sstevel@tonic-gate {
15187c478bd9Sstevel@tonic-gate 	int prom_fd = -1;
15197c478bd9Sstevel@tonic-gate 	char *promdev = "/dev/openprom";
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	while (prom_fd < 0) {
15227c478bd9Sstevel@tonic-gate 		if ((prom_fd = open(promdev, oflag)) < 0)  {
15237c478bd9Sstevel@tonic-gate 			if (errno == EAGAIN)   {
15247c478bd9Sstevel@tonic-gate 				(void) sleep(5);
15257c478bd9Sstevel@tonic-gate 				continue;
15267c478bd9Sstevel@tonic-gate 			}
15277c478bd9Sstevel@tonic-gate 			if ((errno == ENXIO) || (errno == ENOENT)) {
15287c478bd9Sstevel@tonic-gate 				return (DEVFS_NOTSUP);
15297c478bd9Sstevel@tonic-gate 			}
15307c478bd9Sstevel@tonic-gate 			if ((errno == EPERM) || (errno == EACCES)) {
15317c478bd9Sstevel@tonic-gate 				return (DEVFS_PERM);
15327c478bd9Sstevel@tonic-gate 			}
15337c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
15347c478bd9Sstevel@tonic-gate 		} else
15357c478bd9Sstevel@tonic-gate 			break;
15367c478bd9Sstevel@tonic-gate 	}
15377c478bd9Sstevel@tonic-gate 	if (is_openprom(prom_fd))
15387c478bd9Sstevel@tonic-gate 		return (prom_fd);
15397c478bd9Sstevel@tonic-gate 	else {
15407c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
15417c478bd9Sstevel@tonic-gate 		return (DEVFS_ERR);
15427c478bd9Sstevel@tonic-gate 	}
15437c478bd9Sstevel@tonic-gate }
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate static void
15467c478bd9Sstevel@tonic-gate prom_close(int prom_fd)
15477c478bd9Sstevel@tonic-gate {
15487c478bd9Sstevel@tonic-gate 	(void) close(prom_fd);
15497c478bd9Sstevel@tonic-gate }
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate /*
15527c478bd9Sstevel@tonic-gate  * is this an OBP/1275 OF machine?
15537c478bd9Sstevel@tonic-gate  */
15547c478bd9Sstevel@tonic-gate static int
15557c478bd9Sstevel@tonic-gate is_openprom(int prom_fd)
15567c478bd9Sstevel@tonic-gate {
15577c478bd9Sstevel@tonic-gate 	Oppbuf  oppbuf;
15587c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
15597c478bd9Sstevel@tonic-gate 	unsigned int i;
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
15627c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETCONS, opp) < 0)
15637c478bd9Sstevel@tonic-gate 		return (0);
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	i = (unsigned int)((unsigned char)opp->oprom_array[0]);
15667c478bd9Sstevel@tonic-gate 	return ((i & OPROMCONS_OPENPROM) == OPROMCONS_OPENPROM);
15677c478bd9Sstevel@tonic-gate }
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate /*
15707c478bd9Sstevel@tonic-gate  * convert a prom device path name to an equivalent physical device
15717c478bd9Sstevel@tonic-gate  * path in the kernel.
15727c478bd9Sstevel@tonic-gate  */
15737c478bd9Sstevel@tonic-gate static int
15747c478bd9Sstevel@tonic-gate devfs_prom_to_dev_name(char *prom_path, char *dev_path)
15757c478bd9Sstevel@tonic-gate {
15767c478bd9Sstevel@tonic-gate 	Oppbuf oppbuf;
15777c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
15787c478bd9Sstevel@tonic-gate 	int prom_fd;
15797c478bd9Sstevel@tonic-gate 	int ret = DEVFS_INVAL;
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	if (dev_path == NULL) {
15827c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
15837c478bd9Sstevel@tonic-gate 	}
15847c478bd9Sstevel@tonic-gate 	if (prom_path == NULL) {
15857c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
15867c478bd9Sstevel@tonic-gate 	}
15877c478bd9Sstevel@tonic-gate 	if (strlen(prom_path) >= MAXPATHLEN)
15887c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	if (*prom_path != '/') {
15917c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	/* query the prom */
15957c478bd9Sstevel@tonic-gate 	prom_fd = prom_open(O_RDONLY);
15967c478bd9Sstevel@tonic-gate 	if (prom_fd < 0) {
15977c478bd9Sstevel@tonic-gate 		return (prom_fd);
15987c478bd9Sstevel@tonic-gate 	}
15997c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, prom_path);
16007c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMPROM2DEVNAME, opp) == 0) {
16037c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
16047c478bd9Sstevel@tonic-gate 		/*
16057c478bd9Sstevel@tonic-gate 		 * success
16067c478bd9Sstevel@tonic-gate 		 * return the prom path in prom_path
16077c478bd9Sstevel@tonic-gate 		 */
16087c478bd9Sstevel@tonic-gate 		(void) strcpy(dev_path, opp->oprom_array);
16097c478bd9Sstevel@tonic-gate 		return (0);
16107c478bd9Sstevel@tonic-gate 	}
16117c478bd9Sstevel@tonic-gate 	/*
16127c478bd9Sstevel@tonic-gate 	 * either the argument was not a valid name or the openprom
16137c478bd9Sstevel@tonic-gate 	 * driver does not support this ioctl.
16147c478bd9Sstevel@tonic-gate 	 */
16157c478bd9Sstevel@tonic-gate 	if (errno == ENXIO) {
16167c478bd9Sstevel@tonic-gate 		ret = DEVFS_NOTSUP;
16177c478bd9Sstevel@tonic-gate 	}
16187c478bd9Sstevel@tonic-gate 	prom_close(prom_fd);
16197c478bd9Sstevel@tonic-gate 	return (ret);
16207c478bd9Sstevel@tonic-gate }
16217c478bd9Sstevel@tonic-gate /*
16227c478bd9Sstevel@tonic-gate  * convert a prom device path to a list of equivalent alias names
16237c478bd9Sstevel@tonic-gate  * If there is no alias node, or there are no aliases that correspond
16247c478bd9Sstevel@tonic-gate  * to dev, we return empty lists.
16257c478bd9Sstevel@tonic-gate  */
16267c478bd9Sstevel@tonic-gate static int
16277c478bd9Sstevel@tonic-gate prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf)
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate 	struct name_list *exact_list;
16307c478bd9Sstevel@tonic-gate 	struct name_list *inexact_list;
16317c478bd9Sstevel@tonic-gate 	struct name_list *list;
16327c478bd9Sstevel@tonic-gate 	char *ptr;
16337c478bd9Sstevel@tonic-gate 	char **array;
16347c478bd9Sstevel@tonic-gate 	int prom_fd;
16357c478bd9Sstevel@tonic-gate 	int count;
16367c478bd9Sstevel@tonic-gate 	int vers;
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	vers = prom_obp_vers();
16397c478bd9Sstevel@tonic-gate 	if (vers < 0) {
16407c478bd9Sstevel@tonic-gate 		return (vers);
16417c478bd9Sstevel@tonic-gate 	}
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	if (dev == NULL) {
16447c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
16457c478bd9Sstevel@tonic-gate 	}
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	if (*dev != '/')
16487c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	if (strlen(dev) >= MAXPATHLEN)
16517c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
16527c478bd9Sstevel@tonic-gate 
16537c478bd9Sstevel@tonic-gate 	if ((ptr = strchr(dev, ':')) != NULL) {
16547c478bd9Sstevel@tonic-gate 		if (strchr(ptr, '/') != NULL)
16557c478bd9Sstevel@tonic-gate 			return (DEVFS_INVAL);
16567c478bd9Sstevel@tonic-gate 	}
16577c478bd9Sstevel@tonic-gate 	if (ret_buf == NULL) {
16587c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
16597c478bd9Sstevel@tonic-gate 	}
16607c478bd9Sstevel@tonic-gate 
16617c478bd9Sstevel@tonic-gate 	prom_fd = prom_open(O_RDONLY);
16627c478bd9Sstevel@tonic-gate 	if (prom_fd < 0) {
16637c478bd9Sstevel@tonic-gate 		return (prom_fd);
16647c478bd9Sstevel@tonic-gate 	}
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 	(void) prom_srch_aliases_by_def(dev, &exact_list,
16677c478bd9Sstevel@tonic-gate 	    &inexact_list,  prom_fd);
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	prom_close(prom_fd);
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 	if ((options & BOOTDEV_NO_EXACT_ALIAS) != 0) {
16727c478bd9Sstevel@tonic-gate 		free_name_list(exact_list, 1);
16737c478bd9Sstevel@tonic-gate 		exact_list = NULL;
16747c478bd9Sstevel@tonic-gate 	}
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 	if ((options & BOOTDEV_NO_INEXACT_ALIAS) != 0) {
16777c478bd9Sstevel@tonic-gate 		free_name_list(inexact_list, 1);
16787c478bd9Sstevel@tonic-gate 		inexact_list = NULL;
16797c478bd9Sstevel@tonic-gate 	}
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate 	count = 0;
16827c478bd9Sstevel@tonic-gate 	list = exact_list;
16837c478bd9Sstevel@tonic-gate 	while (list != NULL) {
16847c478bd9Sstevel@tonic-gate 		list = list->next;
16857c478bd9Sstevel@tonic-gate 		count++;
16867c478bd9Sstevel@tonic-gate 	}
16877c478bd9Sstevel@tonic-gate 	list = inexact_list;
16887c478bd9Sstevel@tonic-gate 	while (list != NULL) {
16897c478bd9Sstevel@tonic-gate 		list = list->next;
16907c478bd9Sstevel@tonic-gate 		count++;
16917c478bd9Sstevel@tonic-gate 	}
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	if ((*ret_buf = (char **)malloc((count + 1) * sizeof (char *)))
16947c478bd9Sstevel@tonic-gate 	    == NULL) {
16957c478bd9Sstevel@tonic-gate 		free_name_list(inexact_list, 1);
16967c478bd9Sstevel@tonic-gate 		free_name_list(exact_list, 1);
16977c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
16987c478bd9Sstevel@tonic-gate 	}
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	array = *ret_buf;
17017c478bd9Sstevel@tonic-gate 	count = 0;
17027c478bd9Sstevel@tonic-gate 	list = exact_list;
17037c478bd9Sstevel@tonic-gate 	while (list != NULL) {
17047c478bd9Sstevel@tonic-gate 		array[count] = list->name;
17057c478bd9Sstevel@tonic-gate 		list = list->next;
17067c478bd9Sstevel@tonic-gate 		count++;
17077c478bd9Sstevel@tonic-gate 	}
17087c478bd9Sstevel@tonic-gate 	list = inexact_list;
17097c478bd9Sstevel@tonic-gate 	while (list != NULL) {
17107c478bd9Sstevel@tonic-gate 		array[count] = list->name;
17117c478bd9Sstevel@tonic-gate 		list = list->next;
17127c478bd9Sstevel@tonic-gate 		count++;
17137c478bd9Sstevel@tonic-gate 	}
17147c478bd9Sstevel@tonic-gate 	array[count] = NULL;
17157c478bd9Sstevel@tonic-gate 	free_name_list(inexact_list, 0);
17167c478bd9Sstevel@tonic-gate 	free_name_list(exact_list, 0);
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 	return (0);
17197c478bd9Sstevel@tonic-gate }
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate /*
17227c478bd9Sstevel@tonic-gate  * determine the version of prom we are running on.
17237c478bd9Sstevel@tonic-gate  * Also include any prom revision specific information.
17247c478bd9Sstevel@tonic-gate  */
17257c478bd9Sstevel@tonic-gate static int
17267c478bd9Sstevel@tonic-gate prom_obp_vers(void)
17277c478bd9Sstevel@tonic-gate {
17287c478bd9Sstevel@tonic-gate 	Oppbuf  oppbuf;
17297c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
17307c478bd9Sstevel@tonic-gate 	int prom_fd;
17317c478bd9Sstevel@tonic-gate 	static int version = 0;
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 	/* cache version */
17347c478bd9Sstevel@tonic-gate 	if (version > 0) {
17357c478bd9Sstevel@tonic-gate 		return (version);
17367c478bd9Sstevel@tonic-gate 	}
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	prom_fd = prom_open(O_RDONLY);
17397c478bd9Sstevel@tonic-gate 	if (prom_fd < 0) {
17407c478bd9Sstevel@tonic-gate 		return (prom_fd);
17417c478bd9Sstevel@tonic-gate 	}
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	if ((ioctl(prom_fd, OPROMGETVERSION, opp)) < 0) {
17467c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
17477c478bd9Sstevel@tonic-gate 		return (DEVFS_ERR);
17487c478bd9Sstevel@tonic-gate 	}
17497c478bd9Sstevel@tonic-gate 	prom_close(prom_fd);
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	version |= OBP_OF;
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	return (version);
17547c478bd9Sstevel@tonic-gate }
17557c478bd9Sstevel@tonic-gate /*
17567c478bd9Sstevel@tonic-gate  * search the aliases node by definition - compile a list of
17577c478bd9Sstevel@tonic-gate  * alias names that are both exact and inexact matches.
17587c478bd9Sstevel@tonic-gate  */
17597c478bd9Sstevel@tonic-gate static int
17607c478bd9Sstevel@tonic-gate prom_srch_aliases_by_def(char *promdev_def, struct name_list **exact_list,
17617c478bd9Sstevel@tonic-gate     struct name_list **inexact_list, int prom_fd)
17627c478bd9Sstevel@tonic-gate {
17637c478bd9Sstevel@tonic-gate 	Oppbuf  oppbuf;
17647c478bd9Sstevel@tonic-gate 	Oppbuf  propdef_oppbuf;
17657c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
17667c478bd9Sstevel@tonic-gate 	struct openpromio *propdef_opp = &(propdef_oppbuf.opp);
17677c478bd9Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
17687c478bd9Sstevel@tonic-gate 	int ret;
17697c478bd9Sstevel@tonic-gate 	struct name_list *inexact_match = *inexact_list = NULL;
17707c478bd9Sstevel@tonic-gate 	struct name_list *exact_match = *exact_list = NULL;
17717c478bd9Sstevel@tonic-gate 	char alias_buf[MAXNAMELEN];
17727c478bd9Sstevel@tonic-gate 	int found = 0;
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 	(void) memset(oppbuf.buf, 0, BUFSIZE);
17757c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXPROPSIZE;
17767c478bd9Sstevel@tonic-gate 	*ip = 0;
17777c478bd9Sstevel@tonic-gate 
17787c478bd9Sstevel@tonic-gate 	if ((ret = ioctl(prom_fd, OPROMNXTPROP, opp)) < 0)
17797c478bd9Sstevel@tonic-gate 		return (0);
17807c478bd9Sstevel@tonic-gate 	if (opp->oprom_size == 0)
17817c478bd9Sstevel@tonic-gate 		return (0);
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 	while ((ret >= 0) && (opp->oprom_size > 0)) {
17847c478bd9Sstevel@tonic-gate 		(void) strcpy(propdef_opp->oprom_array, opp->oprom_array);
17857c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXPROPSIZE;
17867c478bd9Sstevel@tonic-gate 		propdef_opp->oprom_size = MAXVALSIZE;
17877c478bd9Sstevel@tonic-gate 		if ((ioctl(prom_fd, OPROMGETPROP, propdef_opp) < 0) ||
17887c478bd9Sstevel@tonic-gate 		    (propdef_opp->oprom_size == 0)) {
17897c478bd9Sstevel@tonic-gate 			ret = ioctl(prom_fd, OPROMNXTPROP, opp);
17907c478bd9Sstevel@tonic-gate 			continue;
17917c478bd9Sstevel@tonic-gate 		}
17927c478bd9Sstevel@tonic-gate 		ret = prom_compare_devs(promdev_def, propdef_opp->oprom_array);
17937c478bd9Sstevel@tonic-gate 		if (ret == EXACT_MATCH) {
17947c478bd9Sstevel@tonic-gate 			found++;
17957c478bd9Sstevel@tonic-gate 			if (insert_alias_list(exact_list, opp->oprom_array)
17967c478bd9Sstevel@tonic-gate 			    != 0) {
17977c478bd9Sstevel@tonic-gate 				free_name_list(exact_match, 1);
17987c478bd9Sstevel@tonic-gate 				free_name_list(inexact_match, 1);
17997c478bd9Sstevel@tonic-gate 				return (-1);
18007c478bd9Sstevel@tonic-gate 			}
18017c478bd9Sstevel@tonic-gate 		}
18027c478bd9Sstevel@tonic-gate 		if (ret == INEXACT_MATCH) {
18037c478bd9Sstevel@tonic-gate 			found++;
18047c478bd9Sstevel@tonic-gate 			(void) strcpy(alias_buf, opp->oprom_array);
18057c478bd9Sstevel@tonic-gate 			options_override(promdev_def, alias_buf);
18067c478bd9Sstevel@tonic-gate 			if (insert_alias_list(inexact_list, alias_buf)
18077c478bd9Sstevel@tonic-gate 			    != 0) {
18087c478bd9Sstevel@tonic-gate 				free_name_list(exact_match, 1);
18097c478bd9Sstevel@tonic-gate 				free_name_list(inexact_match, 1);
18107c478bd9Sstevel@tonic-gate 				return (-1);
18117c478bd9Sstevel@tonic-gate 			}
18127c478bd9Sstevel@tonic-gate 		}
18137c478bd9Sstevel@tonic-gate 		ret = ioctl(prom_fd, OPROMNXTPROP, opp);
18147c478bd9Sstevel@tonic-gate 	}
18157c478bd9Sstevel@tonic-gate 	if (found) {
18167c478bd9Sstevel@tonic-gate 		return (0);
18177c478bd9Sstevel@tonic-gate 	} else {
18187c478bd9Sstevel@tonic-gate 		return (-1);
18197c478bd9Sstevel@tonic-gate 	}
18207c478bd9Sstevel@tonic-gate }
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate /*
18237c478bd9Sstevel@tonic-gate  * free a list of name_list structs and optionally
18247c478bd9Sstevel@tonic-gate  * free the strings they contain.
18257c478bd9Sstevel@tonic-gate  */
18267c478bd9Sstevel@tonic-gate static void
18277c478bd9Sstevel@tonic-gate free_name_list(struct name_list *list, int free_name)
18287c478bd9Sstevel@tonic-gate {
18297c478bd9Sstevel@tonic-gate 	struct name_list *next = list;
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	while (next != NULL) {
18327c478bd9Sstevel@tonic-gate 		list = list->next;
18337c478bd9Sstevel@tonic-gate 		if (free_name)
18347c478bd9Sstevel@tonic-gate 			free(next->name);
18357c478bd9Sstevel@tonic-gate 		free(next);
18367c478bd9Sstevel@tonic-gate 		next = list;
18377c478bd9Sstevel@tonic-gate 	}
18387c478bd9Sstevel@tonic-gate }
18397c478bd9Sstevel@tonic-gate 
18407c478bd9Sstevel@tonic-gate /*
18417c478bd9Sstevel@tonic-gate  * insert a new alias in a list of aliases - the list is sorted
18427c478bd9Sstevel@tonic-gate  * in collating order (ignoring anything that comes after the
18437c478bd9Sstevel@tonic-gate  * ':' in the name).
18447c478bd9Sstevel@tonic-gate  */
18457c478bd9Sstevel@tonic-gate static int
18467c478bd9Sstevel@tonic-gate insert_alias_list(struct name_list **list, char *alias_name)
18477c478bd9Sstevel@tonic-gate {
18487c478bd9Sstevel@tonic-gate 	struct name_list *entry = *list;
18497c478bd9Sstevel@tonic-gate 	struct name_list *new_entry, *prev_entry;
18507c478bd9Sstevel@tonic-gate 	int ret;
18517c478bd9Sstevel@tonic-gate 	char *colon1, *colon2;
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	if ((new_entry =
18547c478bd9Sstevel@tonic-gate 	    (struct name_list *)malloc(sizeof (struct name_list)))
18557c478bd9Sstevel@tonic-gate 	    == NULL) {
18567c478bd9Sstevel@tonic-gate 		return (-1);
18577c478bd9Sstevel@tonic-gate 	}
18587c478bd9Sstevel@tonic-gate 	if ((new_entry->name = strdup(alias_name)) == NULL) {
18597c478bd9Sstevel@tonic-gate 		free(new_entry);
18607c478bd9Sstevel@tonic-gate 		return (-1);
18617c478bd9Sstevel@tonic-gate 	}
18627c478bd9Sstevel@tonic-gate 	new_entry->next = NULL;
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 	if (entry == NULL) {
18657c478bd9Sstevel@tonic-gate 		*list = new_entry;
18667c478bd9Sstevel@tonic-gate 		return (0);
18677c478bd9Sstevel@tonic-gate 	}
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 	if ((colon1 = strchr(alias_name, ':')) != NULL) {
18707c478bd9Sstevel@tonic-gate 		*colon1 = '\0';
18717c478bd9Sstevel@tonic-gate 	}
18727c478bd9Sstevel@tonic-gate 	prev_entry = NULL;
18737c478bd9Sstevel@tonic-gate 	while (entry != NULL) {
18747c478bd9Sstevel@tonic-gate 		if ((colon2 = strchr(entry->name, ':')) != NULL) {
18757c478bd9Sstevel@tonic-gate 			*colon2 = '\0';
18767c478bd9Sstevel@tonic-gate 		}
18777c478bd9Sstevel@tonic-gate 		ret = strcmp(alias_name, entry->name);
18787c478bd9Sstevel@tonic-gate 		if (colon2 != NULL) {
18797c478bd9Sstevel@tonic-gate 			*colon2 = ':';
18807c478bd9Sstevel@tonic-gate 		}
18817c478bd9Sstevel@tonic-gate 		/* duplicate */
18827c478bd9Sstevel@tonic-gate 		if (ret == 0) {
18837c478bd9Sstevel@tonic-gate 			free(new_entry->name);
18847c478bd9Sstevel@tonic-gate 			free(new_entry);
18857c478bd9Sstevel@tonic-gate 			if (colon1 != NULL) {
18867c478bd9Sstevel@tonic-gate 				*colon1 = ':';
18877c478bd9Sstevel@tonic-gate 			}
18887c478bd9Sstevel@tonic-gate 			return (0);
18897c478bd9Sstevel@tonic-gate 		}
18907c478bd9Sstevel@tonic-gate 		if (ret < 0) {
18917c478bd9Sstevel@tonic-gate 			new_entry->next = entry;
18927c478bd9Sstevel@tonic-gate 			if (prev_entry == NULL) {
18937c478bd9Sstevel@tonic-gate 				/* in beginning of list */
18947c478bd9Sstevel@tonic-gate 				*list = new_entry;
18957c478bd9Sstevel@tonic-gate 			} else {
18967c478bd9Sstevel@tonic-gate 				/* in middle of list */
18977c478bd9Sstevel@tonic-gate 				prev_entry->next = new_entry;
18987c478bd9Sstevel@tonic-gate 			}
18997c478bd9Sstevel@tonic-gate 			if (colon1 != NULL) {
19007c478bd9Sstevel@tonic-gate 				*colon1 = ':';
19017c478bd9Sstevel@tonic-gate 			}
19027c478bd9Sstevel@tonic-gate 			return (0);
19037c478bd9Sstevel@tonic-gate 		}
19047c478bd9Sstevel@tonic-gate 		prev_entry = entry;
19057c478bd9Sstevel@tonic-gate 		entry = entry->next;
19067c478bd9Sstevel@tonic-gate 	}
19077c478bd9Sstevel@tonic-gate 	/* at end of list */
19087c478bd9Sstevel@tonic-gate 	prev_entry->next = new_entry;
19097c478bd9Sstevel@tonic-gate 	new_entry->next = NULL;
19107c478bd9Sstevel@tonic-gate 	if (colon1 != NULL) {
19117c478bd9Sstevel@tonic-gate 		*colon1 = ':';
19127c478bd9Sstevel@tonic-gate 	}
19137c478bd9Sstevel@tonic-gate 	return (0);
19147c478bd9Sstevel@tonic-gate }
19157c478bd9Sstevel@tonic-gate /*
19167c478bd9Sstevel@tonic-gate  * append :x to alias_name to override any default minor name options
19177c478bd9Sstevel@tonic-gate  */
19187c478bd9Sstevel@tonic-gate static void
19197c478bd9Sstevel@tonic-gate options_override(char *prom_path, char *alias_name)
19207c478bd9Sstevel@tonic-gate {
19217c478bd9Sstevel@tonic-gate 	char *colon;
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	if ((colon = strrchr(alias_name, ':')) != NULL) {
19247c478bd9Sstevel@tonic-gate 		/*
19257c478bd9Sstevel@tonic-gate 		 * XXX - should alias names in /aliases ever have a
19267c478bd9Sstevel@tonic-gate 		 * : embedded in them?
19277c478bd9Sstevel@tonic-gate 		 * If so we ignore it.
19287c478bd9Sstevel@tonic-gate 		 */
19297c478bd9Sstevel@tonic-gate 		*colon = '\0';
19307c478bd9Sstevel@tonic-gate 	}
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 	if ((colon = strrchr(prom_path, ':')) != NULL) {
19337c478bd9Sstevel@tonic-gate 		(void) strcat(alias_name, colon);
19347c478bd9Sstevel@tonic-gate 	}
19357c478bd9Sstevel@tonic-gate }
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate /*
19387c478bd9Sstevel@tonic-gate  * compare to prom device names.
19397c478bd9Sstevel@tonic-gate  * if the device names are not fully qualified. we convert them -
19407c478bd9Sstevel@tonic-gate  * we only do this as a last resort though since it requires
19417c478bd9Sstevel@tonic-gate  * jumping into the kernel.
19427c478bd9Sstevel@tonic-gate  */
19437c478bd9Sstevel@tonic-gate static int
19447c478bd9Sstevel@tonic-gate prom_compare_devs(char *prom_dev1, char *prom_dev2)
19457c478bd9Sstevel@tonic-gate {
19467c478bd9Sstevel@tonic-gate 	char *dev1, *dev2;
19477c478bd9Sstevel@tonic-gate 	char *ptr1, *ptr2;
19487c478bd9Sstevel@tonic-gate 	char *drvname1, *addrname1, *minorname1;
19497c478bd9Sstevel@tonic-gate 	char *drvname2, *addrname2, *minorname2;
19507c478bd9Sstevel@tonic-gate 	char component1[MAXNAMELEN], component2[MAXNAMELEN];
19517c478bd9Sstevel@tonic-gate 	char devname1[MAXPATHLEN], devname2[MAXPATHLEN];
19527c478bd9Sstevel@tonic-gate 	int unqualified_name = 0;
19537c478bd9Sstevel@tonic-gate 	int error = EXACT_MATCH;
19547c478bd9Sstevel@tonic-gate 	int len1, len2;
19557c478bd9Sstevel@tonic-gate 	char *wildcard = ",0";
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate 	ptr1 = prom_dev1;
19587c478bd9Sstevel@tonic-gate 	ptr2 = prom_dev2;
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate 	if ((ptr1 == NULL) || (*ptr1 != '/')) {
19617c478bd9Sstevel@tonic-gate 		return (NO_MATCH);
19627c478bd9Sstevel@tonic-gate 	}
19637c478bd9Sstevel@tonic-gate 	if ((ptr2 == NULL) || (*ptr2 != '/')) {
19647c478bd9Sstevel@tonic-gate 		return (NO_MATCH);
19657c478bd9Sstevel@tonic-gate 	}
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	/*
19687c478bd9Sstevel@tonic-gate 	 * compare device names one component at a time.
19697c478bd9Sstevel@tonic-gate 	 */
19707c478bd9Sstevel@tonic-gate 	while ((ptr1 != NULL) && (ptr2 != NULL)) {
19717c478bd9Sstevel@tonic-gate 		*ptr1 = *ptr2 = '/';
19727c478bd9Sstevel@tonic-gate 		dev1 = ptr1 + 1;
19737c478bd9Sstevel@tonic-gate 		dev2 = ptr2 + 1;
19747c478bd9Sstevel@tonic-gate 		if ((ptr1 = strchr(dev1, '/')) != NULL)
19757c478bd9Sstevel@tonic-gate 			*ptr1 = '\0';
19767c478bd9Sstevel@tonic-gate 		if ((ptr2 = strchr(dev2, '/')) != NULL)
19777c478bd9Sstevel@tonic-gate 			*ptr2 = '\0';
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 		(void) strcpy(component1, dev1);
19807c478bd9Sstevel@tonic-gate 		(void) strcpy(component2, dev2);
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate 		parse_name(component1, &drvname1, &addrname1, &minorname1);
19837c478bd9Sstevel@tonic-gate 		parse_name(component2, &drvname2, &addrname2, &minorname2);
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 		if ((drvname1 == NULL) && (addrname1 == NULL)) {
19867c478bd9Sstevel@tonic-gate 			error = NO_MATCH;
19877c478bd9Sstevel@tonic-gate 			break;
19887c478bd9Sstevel@tonic-gate 		}
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 		if ((drvname2 == NULL) && (addrname2 == NULL)) {
19917c478bd9Sstevel@tonic-gate 			error = NO_MATCH;
19927c478bd9Sstevel@tonic-gate 			break;
19937c478bd9Sstevel@tonic-gate 		}
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 		if (_prom_strcmp(drvname1, drvname2) != 0) {
19967c478bd9Sstevel@tonic-gate 			error = NO_MATCH;
19977c478bd9Sstevel@tonic-gate 			break;
19987c478bd9Sstevel@tonic-gate 		}
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 		/*
20017c478bd9Sstevel@tonic-gate 		 * a possible name is driver_name@address.  The address
20027c478bd9Sstevel@tonic-gate 		 * portion is optional (i.e. the name is not fully
20037c478bd9Sstevel@tonic-gate 		 * qualified.).  We have to deal with the case where
20047c478bd9Sstevel@tonic-gate 		 * the component name is either driver_name or
20057c478bd9Sstevel@tonic-gate 		 * driver_name@address
20067c478bd9Sstevel@tonic-gate 		 */
20077c478bd9Sstevel@tonic-gate 		if ((addrname1 == NULL) ^ (addrname2 == NULL)) {
20087c478bd9Sstevel@tonic-gate 			unqualified_name = 1;
20097c478bd9Sstevel@tonic-gate 		} else if (addrname1 &&
20107c478bd9Sstevel@tonic-gate 		    (_prom_strcmp(addrname1, addrname2) != 0)) {
20117c478bd9Sstevel@tonic-gate 			/*
20127c478bd9Sstevel@tonic-gate 			 * check to see if appending a ",0" to the
20137c478bd9Sstevel@tonic-gate 			 * shorter address causes a match to occur.
20147c478bd9Sstevel@tonic-gate 			 * If so succeed.
20157c478bd9Sstevel@tonic-gate 			 */
20167c478bd9Sstevel@tonic-gate 			len1 = strlen(addrname1);
20177c478bd9Sstevel@tonic-gate 			len2 = strlen(addrname2);
20187c478bd9Sstevel@tonic-gate 			if ((len1 < len2) &&
20197c478bd9Sstevel@tonic-gate 			    (strncmp(addrname1, addrname2, len1) == 0) &&
20207c478bd9Sstevel@tonic-gate 			    (strcmp(wildcard, &addrname2[len1]) == 0)) {
20217c478bd9Sstevel@tonic-gate 				continue;
20227c478bd9Sstevel@tonic-gate 			} else if ((len2 < len1) &&
20237c478bd9Sstevel@tonic-gate 			    (strncmp(addrname1, addrname2, len2) == 0) &&
20247c478bd9Sstevel@tonic-gate 			    (strcmp(wildcard, &addrname1[len2]) == 0)) {
20257c478bd9Sstevel@tonic-gate 				continue;
20267c478bd9Sstevel@tonic-gate 			}
20277c478bd9Sstevel@tonic-gate 			error = NO_MATCH;
20287c478bd9Sstevel@tonic-gate 			break;
20297c478bd9Sstevel@tonic-gate 		}
20307c478bd9Sstevel@tonic-gate 	}
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate 	/*
20337c478bd9Sstevel@tonic-gate 	 * if either of the two device paths still has more components,
20347c478bd9Sstevel@tonic-gate 	 * then we do not have a match.
20357c478bd9Sstevel@tonic-gate 	 */
20367c478bd9Sstevel@tonic-gate 	if (ptr1 != NULL) {
20377c478bd9Sstevel@tonic-gate 		*ptr1 = '/';
20387c478bd9Sstevel@tonic-gate 		error = NO_MATCH;
20397c478bd9Sstevel@tonic-gate 	}
20407c478bd9Sstevel@tonic-gate 	if (ptr2 != NULL) {
20417c478bd9Sstevel@tonic-gate 		*ptr2 = '/';
20427c478bd9Sstevel@tonic-gate 		error = NO_MATCH;
20437c478bd9Sstevel@tonic-gate 	}
20447c478bd9Sstevel@tonic-gate 	if (error == NO_MATCH) {
20457c478bd9Sstevel@tonic-gate 		return (error);
20467c478bd9Sstevel@tonic-gate 	}
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 	/*
20497c478bd9Sstevel@tonic-gate 	 * OK - we found a possible match but one or more of the
20507c478bd9Sstevel@tonic-gate 	 * path components was not fully qualified (did not have any
20517c478bd9Sstevel@tonic-gate 	 * address information.  So we need to convert it to a form
20527c478bd9Sstevel@tonic-gate 	 * that is fully qualified and then compare the resulting
20537c478bd9Sstevel@tonic-gate 	 * strings.
20547c478bd9Sstevel@tonic-gate 	 */
20557c478bd9Sstevel@tonic-gate 	if (unqualified_name != 0) {
20567c478bd9Sstevel@tonic-gate 		if ((devfs_prom_to_dev_name(prom_dev1, devname1) < 0) ||
20577c478bd9Sstevel@tonic-gate 		    (devfs_prom_to_dev_name(prom_dev2, devname2) < 0)) {
20587c478bd9Sstevel@tonic-gate 			return (NO_MATCH);
20597c478bd9Sstevel@tonic-gate 		}
20607c478bd9Sstevel@tonic-gate 		if ((dev1 = strrchr(devname1, ':')) != NULL) {
20617c478bd9Sstevel@tonic-gate 			*dev1 = '\0';
20627c478bd9Sstevel@tonic-gate 		}
20637c478bd9Sstevel@tonic-gate 		if ((dev2 = strrchr(devname2, ':')) != NULL) {
20647c478bd9Sstevel@tonic-gate 			*dev2 = '\0';
20657c478bd9Sstevel@tonic-gate 		}
20667c478bd9Sstevel@tonic-gate 		if (strcmp(devname1, devname2) != 0) {
20677c478bd9Sstevel@tonic-gate 			return (NO_MATCH);
20687c478bd9Sstevel@tonic-gate 		}
20697c478bd9Sstevel@tonic-gate 	}
20707c478bd9Sstevel@tonic-gate 	/*
20717c478bd9Sstevel@tonic-gate 	 * the resulting strings matched.  If the minorname information
20727c478bd9Sstevel@tonic-gate 	 * matches, then we have an exact match, otherwise an inexact match
20737c478bd9Sstevel@tonic-gate 	 */
20747c478bd9Sstevel@tonic-gate 	if (_prom_strcmp(minorname1, minorname2) == 0) {
20757c478bd9Sstevel@tonic-gate 		return (EXACT_MATCH);
20767c478bd9Sstevel@tonic-gate 	} else {
20777c478bd9Sstevel@tonic-gate 		return (INEXACT_MATCH);
20787c478bd9Sstevel@tonic-gate 	}
20797c478bd9Sstevel@tonic-gate }
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate /*
20827c478bd9Sstevel@tonic-gate  * wrapper or strcmp - deals with null strings.
20837c478bd9Sstevel@tonic-gate  */
20847c478bd9Sstevel@tonic-gate static int
20857c478bd9Sstevel@tonic-gate _prom_strcmp(char *s1, char *s2)
20867c478bd9Sstevel@tonic-gate {
20877c478bd9Sstevel@tonic-gate 	if ((s1 == NULL) && (s2 == NULL))
20887c478bd9Sstevel@tonic-gate 		return (0);
20897c478bd9Sstevel@tonic-gate 	if ((s1 == NULL) && (s2 != NULL)) {
20907c478bd9Sstevel@tonic-gate 		return (-1);
20917c478bd9Sstevel@tonic-gate 	}
20927c478bd9Sstevel@tonic-gate 	if ((s1 != NULL) && (s2 == NULL)) {
20937c478bd9Sstevel@tonic-gate 		return (1);
20947c478bd9Sstevel@tonic-gate 	}
20957c478bd9Sstevel@tonic-gate 	return (strcmp(s1, s2));
20967c478bd9Sstevel@tonic-gate }
20977c478bd9Sstevel@tonic-gate /*
20987c478bd9Sstevel@tonic-gate  * break device@a,b:minor into components
20997c478bd9Sstevel@tonic-gate  */
21007c478bd9Sstevel@tonic-gate static void
21017c478bd9Sstevel@tonic-gate parse_name(char *name, char **drvname, char **addrname, char **minorname)
21027c478bd9Sstevel@tonic-gate {
21037c478bd9Sstevel@tonic-gate 	char *cp, ch;
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate 	cp = *drvname = name;
21067c478bd9Sstevel@tonic-gate 	*addrname = *minorname = NULL;
21077c478bd9Sstevel@tonic-gate 	if (*name == '@')
21087c478bd9Sstevel@tonic-gate 		*drvname = NULL;
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 	while ((ch = *cp) != '\0') {
21117c478bd9Sstevel@tonic-gate 		if (ch == '@')
21127c478bd9Sstevel@tonic-gate 			*addrname = ++cp;
21137c478bd9Sstevel@tonic-gate 		else if (ch == ':')
21147c478bd9Sstevel@tonic-gate 			*minorname = ++cp;
21157c478bd9Sstevel@tonic-gate 		++cp;
21167c478bd9Sstevel@tonic-gate 	}
21177c478bd9Sstevel@tonic-gate 	if (*addrname) {
21187c478bd9Sstevel@tonic-gate 		*((*addrname)-1) = '\0';
21197c478bd9Sstevel@tonic-gate 	}
21207c478bd9Sstevel@tonic-gate 	if (*minorname) {
21217c478bd9Sstevel@tonic-gate 		*((*minorname)-1) = '\0';
21227c478bd9Sstevel@tonic-gate 	}
21237c478bd9Sstevel@tonic-gate }
21247c478bd9Sstevel@tonic-gate 
2125b6f77fefSas /*
2126b6f77fefSas  * converts a prom alias to a prom device name.
2127b6f77fefSas  * if we find no matching device, then we fail since if were
2128b6f77fefSas  * given a valid alias, then by definition, there must be a
2129b6f77fefSas  * device pathname associated with it in the /aliases node.
2130b6f77fefSas  */
2131b6f77fefSas static int
2132b6f77fefSas alias_to_prom_dev(char *alias, char *ret_buf)
2133b6f77fefSas {
2134b6f77fefSas 	char *options_ptr;
2135b6f77fefSas 	char alias_buf[MAXNAMELEN];
2136b6f77fefSas 	char alias_def[MAXPATHLEN];
2137b6f77fefSas 	char options[16] = "";
2138b6f77fefSas 	int prom_fd = -1;
2139b6f77fefSas 	int ret;
2140b6f77fefSas 	int i;
2141b6f77fefSas 
2142b6f77fefSas 	if (strchr(alias, '/') != NULL)
2143b6f77fefSas 		return (DEVFS_INVAL);
2144b6f77fefSas 
2145b6f77fefSas 	if (strlen(alias) > (MAXNAMELEN - 1))
2146b6f77fefSas 		return (DEVFS_INVAL);
2147b6f77fefSas 
2148b6f77fefSas 	if (ret_buf == NULL) {
2149b6f77fefSas 		return (DEVFS_INVAL);
2150b6f77fefSas 	}
2151b6f77fefSas 
2152b6f77fefSas 	prom_fd = prom_open(O_RDONLY);
2153b6f77fefSas 	if (prom_fd < 0) {
2154b6f77fefSas 		return (prom_fd);
2155b6f77fefSas 	}
2156b6f77fefSas 
2157b6f77fefSas 	(void) strlcpy(alias_buf, alias, sizeof (alias_buf));
2158b6f77fefSas 
2159b6f77fefSas 	/*
2160b6f77fefSas 	 * save off any options (minor name info) that is
2161b6f77fefSas 	 * explicitly called out in the alias name
2162b6f77fefSas 	 */
2163b6f77fefSas 	if ((options_ptr = strchr(alias_buf, ':')) != NULL) {
2164b6f77fefSas 		*options_ptr = '\0';
2165b6f77fefSas 		(void) strlcpy(options, ++options_ptr, sizeof (options));
2166b6f77fefSas 	}
2167b6f77fefSas 
2168b6f77fefSas 	*alias_def = '\0';
2169b6f77fefSas 
2170b6f77fefSas 	ret = prom_find_aliases_node(prom_fd);
2171b6f77fefSas 	if (ret == 0) {
2172b6f77fefSas 		/*
2173b6f77fefSas 		 * we loop because one alias may define another... we have
2174b6f77fefSas 		 * to work our way down to an actual device definition.
2175b6f77fefSas 		 */
2176b6f77fefSas 		for (i = 0; i <= 10; i++) {
2177b6f77fefSas 			ret = prom_srch_node(prom_fd, alias_buf, alias_def);
2178b6f77fefSas 			if (ret == -1) {
2179b6f77fefSas 				break;
2180b6f77fefSas 			}
2181b6f77fefSas 			(void) strlcpy(alias_buf, alias_def,
2182b6f77fefSas 			    sizeof (alias_buf));
2183b6f77fefSas 			if (*alias_def == '/') {
2184b6f77fefSas 				break;
2185b6f77fefSas 			}
2186b6f77fefSas 
2187b6f77fefSas 			/*
2188b6f77fefSas 			 * save off any explicit options (minor name info)
2189b6f77fefSas 			 * if none has been encountered yet
2190b6f77fefSas 			 */
2191b6f77fefSas 			if (options_ptr == NULL) {
2192b6f77fefSas 				options_ptr = strchr(alias_buf, ':');
2193b6f77fefSas 				if (options_ptr != NULL) {
2194b6f77fefSas 				    *options_ptr = '\0';
2195b6f77fefSas 				    (void) strlcpy(options, ++options_ptr,
2196b6f77fefSas 					    sizeof (options));
2197b6f77fefSas 				}
2198b6f77fefSas 			}
2199b6f77fefSas 		}
2200b6f77fefSas 	}
2201b6f77fefSas 	prom_close(prom_fd);
2202b6f77fefSas 
2203b6f77fefSas 	/* error */
2204b6f77fefSas 	if (ret == -1) {
2205b6f77fefSas 		return (ret);
2206b6f77fefSas 	}
2207b6f77fefSas 
2208*95fa951bSas 	(void) strlcpy(ret_buf, alias_def, MAXPATHLEN);
2209b6f77fefSas 
2210b6f77fefSas 	/* override minor name information */
2211b6f77fefSas 	if (options_ptr != NULL) {
2212b6f77fefSas 		if ((options_ptr = strrchr(ret_buf, ':')) == NULL) {
2213b6f77fefSas 			(void) strcat(ret_buf, ":");
2214b6f77fefSas 		} else {
2215b6f77fefSas 			*(++options_ptr) = '\0';
2216b6f77fefSas 		}
2217b6f77fefSas 		(void) strcat(ret_buf, options);
2218b6f77fefSas 	}
2219b6f77fefSas 	return (0);
2220b6f77fefSas }
2221b6f77fefSas 
2222b6f77fefSas /*
2223b6f77fefSas  * search a prom node for a property name
2224b6f77fefSas  */
2225b6f77fefSas static int
2226b6f77fefSas prom_srch_node(int fd, char *prop_name, char *ret_buf)
2227b6f77fefSas {
2228b6f77fefSas 	Oppbuf  oppbuf;
2229b6f77fefSas 	struct openpromio *opp = &(oppbuf.opp);
2230b6f77fefSas 	int *ip = (int *)((void *)opp->oprom_array);
2231b6f77fefSas 
2232b6f77fefSas 	(void) memset(oppbuf.buf, 0, BUFSIZE);
2233b6f77fefSas 	opp->oprom_size = MAXPROPSIZE;
2234b6f77fefSas 	*ip = 0;
2235b6f77fefSas 
2236b6f77fefSas 	if (ioctl(fd, OPROMNXTPROP, opp) < 0)
2237b6f77fefSas 		return (-1);
2238b6f77fefSas 	if (opp->oprom_size == 0)
2239b6f77fefSas 		return (-1);
2240b6f77fefSas 
2241b6f77fefSas 	while (strcmp(prop_name, opp->oprom_array) != 0) {
2242b6f77fefSas 		opp->oprom_size = MAXPROPSIZE;
2243b6f77fefSas 		if (ioctl(fd, OPROMNXTPROP, opp) < 0)
2244b6f77fefSas 			return (-1);
2245b6f77fefSas 		if (opp->oprom_size == 0)
2246b6f77fefSas 			return (-1);
2247b6f77fefSas 	}
2248b6f77fefSas 	opp->oprom_size = MAXVALSIZE;
2249b6f77fefSas 	if (ioctl(fd, OPROMGETPROP, opp) < 0)
2250b6f77fefSas 		return (-1);
2251b6f77fefSas 
2252b6f77fefSas 	if (opp->oprom_size == 0)
2253b6f77fefSas 		return (-1);
2254*95fa951bSas 	(void) strlcpy(ret_buf, opp->oprom_array, MAXPATHLEN);
2255b6f77fefSas 	return (0);
2256b6f77fefSas }
2257b6f77fefSas 
2258b6f77fefSas /*
2259b6f77fefSas  * return the aliases node.
2260b6f77fefSas  */
2261b6f77fefSas static int
2262b6f77fefSas prom_find_aliases_node(int fd)
2263b6f77fefSas {
2264b6f77fefSas 	uint_t child_id;
2265*95fa951bSas 	char buf[MAXPATHLEN];
2266b6f77fefSas 
2267b6f77fefSas 	if ((child_id = prom_next_node(fd, 0)) == 0)
2268b6f77fefSas 		return (-1);
2269b6f77fefSas 	if ((child_id = prom_child_node(fd, child_id)) == 0)
2270b6f77fefSas 		return (-1);
2271b6f77fefSas 
2272b6f77fefSas 	while (child_id != 0) {
2273b6f77fefSas 		if (prom_srch_node(fd, "name", buf) == 0) {
2274b6f77fefSas 			if (strcmp(buf, "aliases") == 0) {
2275b6f77fefSas 				return (0);
2276b6f77fefSas 			}
2277b6f77fefSas 		}
2278b6f77fefSas 		child_id = prom_next_node(fd, child_id);
2279b6f77fefSas 	}
2280b6f77fefSas 	return (-1);
2281b6f77fefSas }
2282b6f77fefSas 
2283b6f77fefSas /*
2284b6f77fefSas  * get sibling
2285b6f77fefSas  */
2286b6f77fefSas static uint_t
2287b6f77fefSas prom_next_node(int fd, uint_t node_id)
2288b6f77fefSas {
2289b6f77fefSas 	Oppbuf  oppbuf;
2290b6f77fefSas 	struct openpromio *opp = &(oppbuf.opp);
2291b6f77fefSas 	uint_t *ip = (uint_t *)((void *)opp->oprom_array);
2292b6f77fefSas 
2293b6f77fefSas 	(void) memset(oppbuf.buf, 0, BUFSIZE);
2294b6f77fefSas 	opp->oprom_size = MAXVALSIZE;
2295b6f77fefSas 	*ip = node_id;
2296b6f77fefSas 
2297b6f77fefSas 	if (ioctl(fd, OPROMNEXT, opp) < 0)
2298b6f77fefSas 		return (0);
2299b6f77fefSas 
2300b6f77fefSas 	return (*(uint_t *)((void *)opp->oprom_array));
2301b6f77fefSas }
2302b6f77fefSas 
2303b6f77fefSas /*
2304b6f77fefSas  * get child
2305b6f77fefSas  */
2306b6f77fefSas static uint_t
2307b6f77fefSas prom_child_node(int fd, uint_t node_id)
2308b6f77fefSas {
2309b6f77fefSas 	Oppbuf  oppbuf;
2310b6f77fefSas 	struct openpromio *opp = &(oppbuf.opp);
2311b6f77fefSas 	uint_t *ip = (uint_t *)((void *)opp->oprom_array);
2312b6f77fefSas 
2313b6f77fefSas 	(void) memset(oppbuf.buf, 0, BUFSIZE);
2314b6f77fefSas 	opp->oprom_size = MAXVALSIZE;
2315b6f77fefSas 	*ip = node_id;
2316b6f77fefSas 
2317b6f77fefSas 	if (ioctl(fd, OPROMCHILD, opp) < 0)
2318b6f77fefSas 		return (0);
2319b6f77fefSas 
2320b6f77fefSas 	return (*(uint_t *)((void *)opp->oprom_array));
2321b6f77fefSas }
2322b6f77fefSas 
23237c478bd9Sstevel@tonic-gate /*
23247c478bd9Sstevel@tonic-gate  * only on sparc for now
23257c478bd9Sstevel@tonic-gate  */
23267c478bd9Sstevel@tonic-gate int
23277c478bd9Sstevel@tonic-gate devfs_bootdev_modifiable(void)
23287c478bd9Sstevel@tonic-gate {
23297c478bd9Sstevel@tonic-gate #if defined(sparc)
23307c478bd9Sstevel@tonic-gate 	return (0);
23317c478bd9Sstevel@tonic-gate #else
23327c478bd9Sstevel@tonic-gate 	return (DEVFS_NOTSUP);
23337c478bd9Sstevel@tonic-gate #endif
23347c478bd9Sstevel@tonic-gate }
2335