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 /*
22c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <string.h>
297c478bd9Sstevel@tonic-gate #include <strings.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <thread.h>
337c478bd9Sstevel@tonic-gate #include <synch.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <ctype.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <fcntl.h>
387c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
397c478bd9Sstevel@tonic-gate #include <errno.h>
407c478bd9Sstevel@tonic-gate #include <sys/openpromio.h>
417c478bd9Sstevel@tonic-gate #include <ftw.h>
427c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
437c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
447c478bd9Sstevel@tonic-gate #include <limits.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include "device_info.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * #define's
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /* alias node searching return values */
537c478bd9Sstevel@tonic-gate #define	NO_MATCH	-1
547c478bd9Sstevel@tonic-gate #define	EXACT_MATCH	1
557c478bd9Sstevel@tonic-gate #define	INEXACT_MATCH	2
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /* for prom io operations */
587c478bd9Sstevel@tonic-gate #define	BUFSIZE		4096
597c478bd9Sstevel@tonic-gate #define	MAXPROPSIZE	256
607c478bd9Sstevel@tonic-gate #define	MAXVALSIZE	(BUFSIZE - MAXPROPSIZE - sizeof (uint_t))
617c478bd9Sstevel@tonic-gate 
62b6f77fefSas /* prom_obp_vers() return values */
637c478bd9Sstevel@tonic-gate #define	OBP_OF			0x4	/* versions OBP 3.x */
64b6f77fefSas #define	OBP_NO_ALIAS_NODE	0x8	/* No alias node */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate /* for nftw call */
677c478bd9Sstevel@tonic-gate #define	FT_DEPTH	15
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /* default logical and physical device name space */
707c478bd9Sstevel@tonic-gate #define	DEV	"/dev"
717c478bd9Sstevel@tonic-gate #define	DEVICES	"/devices"
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /* for boot device identification on x86 */
747c478bd9Sstevel@tonic-gate #define	CREATE_DISKMAP		"/boot/solaris/bin/create_diskmap"
757c478bd9Sstevel@tonic-gate #define	GRUBDISK_MAP		"/var/run/solaris_grubdisk.map"
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * internal structure declarations
797c478bd9Sstevel@tonic-gate  */
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /* for prom io functions */
827c478bd9Sstevel@tonic-gate typedef union {
837c478bd9Sstevel@tonic-gate 	char buf[BUFSIZE];
847c478bd9Sstevel@tonic-gate 	struct openpromio opp;
857c478bd9Sstevel@tonic-gate } Oppbuf;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* used to manage lists of devices and aliases */
887c478bd9Sstevel@tonic-gate struct name_list {
897c478bd9Sstevel@tonic-gate 	char *name;
907c478bd9Sstevel@tonic-gate 	struct name_list *next;
917c478bd9Sstevel@tonic-gate };
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * internal global data
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /* global since nftw does not let you pass args to be updated */
987c478bd9Sstevel@tonic-gate static struct name_list **dev_list;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate /* global since nftw does not let you pass args to be updated */
1017c478bd9Sstevel@tonic-gate static struct boot_dev **bootdev_list;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /* mutex to protect bootdev_list and dev_list */
1047c478bd9Sstevel@tonic-gate static mutex_t dev_lists_lk = DEFAULTMUTEX;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * internal function prototypes
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static int prom_open(int);
1117c478bd9Sstevel@tonic-gate static void prom_close(int);
1127c478bd9Sstevel@tonic-gate static int is_openprom(int);
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate static int prom_dev_to_alias(char *dev, uint_t options, char ***ret_buf);
115b6f77fefSas static int alias_to_prom_dev(char *alias, char *ret_buf);
1167c478bd9Sstevel@tonic-gate static int prom_srch_aliases_by_def(char *, struct name_list **,
1177c478bd9Sstevel@tonic-gate     struct name_list **, int);
118b6f77fefSas static int prom_find_aliases_node(int fd);
1197c478bd9Sstevel@tonic-gate static int prom_compare_devs(char *prom_dev1, char *prom_dev2);
1207c478bd9Sstevel@tonic-gate static int _prom_strcmp(char *s1, char *s2);
121b6f77fefSas static int prom_srch_node(int fd, char *prop_name, char *ret_buf);
122b6f77fefSas static uint_t prom_next_node(int fd, uint_t node_id);
123b6f77fefSas static uint_t prom_child_node(int fd, uint_t node_id);
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate static int prom_obp_vers(void);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate static void parse_name(char *, char **, char **, char **);
1287c478bd9Sstevel@tonic-gate static int process_bootdev(const char *, const char *, struct boot_dev ***);
1297c478bd9Sstevel@tonic-gate static int process_minor_name(char *dev_path, const char *default_root);
1307c478bd9Sstevel@tonic-gate static void options_override(char *prom_path, char *alias_name);
1317c478bd9Sstevel@tonic-gate static int devfs_phys_to_logical(struct boot_dev **bootdev_array,
1327c478bd9Sstevel@tonic-gate 	const int array_size, const char *default_root);
1337c478bd9Sstevel@tonic-gate static int check_logical_dev(const char *, const struct stat *, int,
1347c478bd9Sstevel@tonic-gate 	struct FTW *);
1357c478bd9Sstevel@tonic-gate static struct boot_dev *alloc_bootdev(char *);
1367c478bd9Sstevel@tonic-gate static void free_name_list(struct name_list *list, int free_name);
1377c478bd9Sstevel@tonic-gate static int insert_alias_list(struct name_list **list,
1387c478bd9Sstevel@tonic-gate 	char *alias_name);
1397c478bd9Sstevel@tonic-gate static int get_boot_dev_var(struct openpromio *opp);
1407c478bd9Sstevel@tonic-gate static int set_boot_dev_var(struct openpromio *opp, char *bootdev);
1417c478bd9Sstevel@tonic-gate static int devfs_prom_to_dev_name(char *prom_path, char *dev_path);
1427c478bd9Sstevel@tonic-gate static int devfs_dev_to_prom_names(char *dev_path, char *prom_path, size_t len);
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /*
1457c478bd9Sstevel@tonic-gate  * frees a list of paths from devfs_get_prom_name_list
1467c478bd9Sstevel@tonic-gate  */
1477c478bd9Sstevel@tonic-gate static void
prom_list_free(char ** prom_list)1487c478bd9Sstevel@tonic-gate prom_list_free(char **prom_list)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate 	int i = 0;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	if (!prom_list)
1537c478bd9Sstevel@tonic-gate 		return;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	while (prom_list[i]) {
1567c478bd9Sstevel@tonic-gate 		free(prom_list[i]);
1577c478bd9Sstevel@tonic-gate 		i++;
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate 	free(prom_list);
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate static int
devfs_get_prom_name_list(const char * dev_name,char *** prom_list)1637c478bd9Sstevel@tonic-gate devfs_get_prom_name_list(const char *dev_name, char ***prom_list)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 	char *prom_path = NULL;
1667c478bd9Sstevel@tonic-gate 	int count = 0;		/* # of slots we will need in prom_list */
1677c478bd9Sstevel@tonic-gate 	int ret, i, len;
1687c478bd9Sstevel@tonic-gate 	char **list;
1697c478bd9Sstevel@tonic-gate 	char *ptr;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (dev_name == NULL)
1727c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
1737c478bd9Sstevel@tonic-gate 	if (*dev_name != '/')
1747c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
1757c478bd9Sstevel@tonic-gate 	if (prom_list == NULL)
1767c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/*
1797c478bd9Sstevel@tonic-gate 	 * make sure we are on a machine which supports a prom
1807c478bd9Sstevel@tonic-gate 	 * and we have permission to use /dev/openprom
1817c478bd9Sstevel@tonic-gate 	 */
1827c478bd9Sstevel@tonic-gate 	if ((ret = prom_obp_vers()) < 0)
1837c478bd9Sstevel@tonic-gate 		return (ret);
1847c478bd9Sstevel@tonic-gate 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
1857c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
1867c478bd9Sstevel@tonic-gate 	/*
1877c478bd9Sstevel@tonic-gate 	 * get the prom path name
1887c478bd9Sstevel@tonic-gate 	 */
1897c478bd9Sstevel@tonic-gate 	ret = devfs_dev_to_prom_names((char *)dev_name, prom_path, MAXVALSIZE);
1907c478bd9Sstevel@tonic-gate 	if (ret < 0) {
1917c478bd9Sstevel@tonic-gate 		free(prom_path);
1927c478bd9Sstevel@tonic-gate 		return (ret);
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate 	/* deal with list of names */
1957c478bd9Sstevel@tonic-gate 	for (i = 0; i < ret; i++)
1967c478bd9Sstevel@tonic-gate 		if (prom_path[i] == '\0')
1977c478bd9Sstevel@tonic-gate 			count++;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if ((list = (char **)calloc(count + 1, sizeof (char *))) == NULL) {
2007c478bd9Sstevel@tonic-gate 		free(prom_path);
2017c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	ptr = prom_path;
2057c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
2067c478bd9Sstevel@tonic-gate 		len = strlen(ptr) + 1;
2077c478bd9Sstevel@tonic-gate 		if ((list[i] = (char *)malloc(len)) == NULL) {
2087c478bd9Sstevel@tonic-gate 			free(prom_path);
2097c478bd9Sstevel@tonic-gate 			free(list);
2107c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
2117c478bd9Sstevel@tonic-gate 		}
2127c478bd9Sstevel@tonic-gate 		(void) snprintf(list[i], len, "%s", ptr);
2137c478bd9Sstevel@tonic-gate 		ptr += len;
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	free(prom_path);
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	*prom_list = list;
2197c478bd9Sstevel@tonic-gate 	return (0);
2207c478bd9Sstevel@tonic-gate }
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate /*
2237c478bd9Sstevel@tonic-gate  * retrieve the list of prom representations for a given device name
2247c478bd9Sstevel@tonic-gate  * the list will be sorted in the following order: exact aliases,
2257c478bd9Sstevel@tonic-gate  * inexact aliases, prom device path name.  If multiple matches occur
2267c478bd9Sstevel@tonic-gate  * for exact or inexact aliases, then these are sorted in collating
2277c478bd9Sstevel@tonic-gate  * order. The list is returned in prom_list
2287c478bd9Sstevel@tonic-gate  *
2297c478bd9Sstevel@tonic-gate  * the list may be restricted by specifying the correct flags in options.
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate int
devfs_get_prom_names(const char * dev_name,uint_t options,char *** prom_list)2327c478bd9Sstevel@tonic-gate devfs_get_prom_names(const char *dev_name, uint_t options, char ***prom_list)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	char *prom_path = NULL;
2357c478bd9Sstevel@tonic-gate 	int count = 0;		/* # of slots we will need in prom_list */
2367c478bd9Sstevel@tonic-gate 	char **alias_list = NULL;
2377c478bd9Sstevel@tonic-gate 	char **list;
2387c478bd9Sstevel@tonic-gate 	int ret;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	if (dev_name == NULL) {
2417c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 	if (*dev_name != '/') {
2447c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 	if (prom_list == NULL) {
2477c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	/*
2507c478bd9Sstevel@tonic-gate 	 * make sure we are on a machine which supports a prom
2517c478bd9Sstevel@tonic-gate 	 * and we have permission to use /dev/openprom
2527c478bd9Sstevel@tonic-gate 	 */
2537c478bd9Sstevel@tonic-gate 	if ((ret = prom_obp_vers()) < 0) {
2547c478bd9Sstevel@tonic-gate 		return (ret);
2557c478bd9Sstevel@tonic-gate 	}
2567c478bd9Sstevel@tonic-gate 	if ((prom_path = (char *)malloc(MAXPATHLEN)) == NULL) {
2577c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
2587c478bd9Sstevel@tonic-gate 	}
2597c478bd9Sstevel@tonic-gate 	/*
2607c478bd9Sstevel@tonic-gate 	 * get the prom path name
2617c478bd9Sstevel@tonic-gate 	 */
2627c478bd9Sstevel@tonic-gate 	ret = devfs_dev_to_prom_name((char *)dev_name, prom_path);
2637c478bd9Sstevel@tonic-gate 	if (ret < 0) {
2647c478bd9Sstevel@tonic-gate 		free(prom_path);
2657c478bd9Sstevel@tonic-gate 		return (ret);
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 	/* get the list of aliases (exact and inexact) */
2687c478bd9Sstevel@tonic-gate 	if ((ret = prom_dev_to_alias(prom_path, options, &alias_list)) < 0) {
2697c478bd9Sstevel@tonic-gate 		free(prom_path);
2707c478bd9Sstevel@tonic-gate 		return (ret);
2717c478bd9Sstevel@tonic-gate 	}
2727c478bd9Sstevel@tonic-gate 	/* now figure out how big the return array must be */
2737c478bd9Sstevel@tonic-gate 	if (alias_list != NULL) {
2747c478bd9Sstevel@tonic-gate 		while (alias_list[count] != NULL) {
2757c478bd9Sstevel@tonic-gate 			count++;
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 	if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
2797c478bd9Sstevel@tonic-gate 		count++;	/* # of slots we will need in prom_list */
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 	count++;	/* for the null terminator */
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	/* allocate space for the list */
2847c478bd9Sstevel@tonic-gate 	if ((list = (char **)calloc(count, sizeof (char *))) == NULL) {
2857c478bd9Sstevel@tonic-gate 		count = 0;
2867c478bd9Sstevel@tonic-gate 		while ((alias_list) && (alias_list[count] != NULL)) {
2877c478bd9Sstevel@tonic-gate 			free(alias_list[count]);
2887c478bd9Sstevel@tonic-gate 			count++;
2897c478bd9Sstevel@tonic-gate 		}
2907c478bd9Sstevel@tonic-gate 		free(alias_list);
2917c478bd9Sstevel@tonic-gate 		free(prom_path);
2927c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	/* fill in the array and free the name list of aliases. */
2957c478bd9Sstevel@tonic-gate 	count = 0;
2967c478bd9Sstevel@tonic-gate 	while ((alias_list) && (alias_list[count] != NULL)) {
2977c478bd9Sstevel@tonic-gate 		list[count] = alias_list[count];
2987c478bd9Sstevel@tonic-gate 		count++;
2997c478bd9Sstevel@tonic-gate 	}
3007c478bd9Sstevel@tonic-gate 	if ((options & BOOTDEV_NO_PROM_PATH) == 0) {
3017c478bd9Sstevel@tonic-gate 		list[count] = prom_path;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 	if (alias_list != NULL) {
3047c478bd9Sstevel@tonic-gate 		free(alias_list);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 	*prom_list = list;
3077c478bd9Sstevel@tonic-gate 	return (0);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate /*
3117c478bd9Sstevel@tonic-gate  * Get a list prom-path translations for a solaris device.
3127c478bd9Sstevel@tonic-gate  *
3137c478bd9Sstevel@tonic-gate  * Returns the number of and all OBP paths and alias variants that
3147c478bd9Sstevel@tonic-gate  * reference the Solaris device path passed in.
3157c478bd9Sstevel@tonic-gate  */
3167c478bd9Sstevel@tonic-gate int
devfs_get_all_prom_names(const char * solaris_path,uint_t flags,struct devfs_prom_path ** paths)3177c478bd9Sstevel@tonic-gate devfs_get_all_prom_names(const char *solaris_path, uint_t flags,
3187c478bd9Sstevel@tonic-gate     struct devfs_prom_path **paths)
3197c478bd9Sstevel@tonic-gate {
3207c478bd9Sstevel@tonic-gate 	int ret, len, i, count = 0;
3217c478bd9Sstevel@tonic-gate 	char *ptr, *prom_path;
3227c478bd9Sstevel@tonic-gate 	struct devfs_prom_path *cur = NULL, *new;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if ((ret = prom_obp_vers()) < 0)
3257c478bd9Sstevel@tonic-gate 		return (ret);
3267c478bd9Sstevel@tonic-gate 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL)
3277c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	if ((ret = devfs_dev_to_prom_names((char *)solaris_path,
3307c478bd9Sstevel@tonic-gate 	    prom_path, MAXVALSIZE)) < 0) {
3317c478bd9Sstevel@tonic-gate 		free(prom_path);
3327c478bd9Sstevel@tonic-gate 		return (ret);
3337c478bd9Sstevel@tonic-gate 	}
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	for (i = 0; i < ret; i++)
3367c478bd9Sstevel@tonic-gate 		if (prom_path[i] == '\0')
3377c478bd9Sstevel@tonic-gate 			count++;
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	*paths = NULL;
3407c478bd9Sstevel@tonic-gate 	ptr = prom_path;
3417c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
3427c478bd9Sstevel@tonic-gate 		if ((new = (struct devfs_prom_path *)calloc(
3437c478bd9Sstevel@tonic-gate 		    sizeof (struct devfs_prom_path), 1)) == NULL) {
3447c478bd9Sstevel@tonic-gate 			free(prom_path);
3457c478bd9Sstevel@tonic-gate 			devfs_free_all_prom_names(*paths);
3467c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
3477c478bd9Sstevel@tonic-gate 		}
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 		if (cur == NULL)
3507c478bd9Sstevel@tonic-gate 			*paths = new;
3517c478bd9Sstevel@tonic-gate 		else
3527c478bd9Sstevel@tonic-gate 			cur->next = new;
3537c478bd9Sstevel@tonic-gate 		cur = new;
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 		len = strlen(ptr) + 1;
3567c478bd9Sstevel@tonic-gate 		if ((cur->obp_path = (char *)calloc(len, 1)) == NULL) {
3577c478bd9Sstevel@tonic-gate 			free(prom_path);
3587c478bd9Sstevel@tonic-gate 			devfs_free_all_prom_names(*paths);
3597c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
3607c478bd9Sstevel@tonic-gate 		}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 		(void) snprintf(cur->obp_path, len, "%s", ptr);
3637c478bd9Sstevel@tonic-gate 		ptr += len;
3647c478bd9Sstevel@tonic-gate 		if ((ret = prom_dev_to_alias(cur->obp_path, flags,
3657c478bd9Sstevel@tonic-gate 		    &(cur->alias_list))) < 0) {
3667c478bd9Sstevel@tonic-gate 			free(prom_path);
3677c478bd9Sstevel@tonic-gate 			devfs_free_all_prom_names(*paths);
3687c478bd9Sstevel@tonic-gate 			return (ret);
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	free(prom_path);
3737c478bd9Sstevel@tonic-gate 	return (count);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate void
devfs_free_all_prom_names(struct devfs_prom_path * paths)3777c478bd9Sstevel@tonic-gate devfs_free_all_prom_names(struct devfs_prom_path *paths)
3787c478bd9Sstevel@tonic-gate {
3797c478bd9Sstevel@tonic-gate 	int i;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	if (paths == NULL)
3827c478bd9Sstevel@tonic-gate 		return;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	devfs_free_all_prom_names(paths->next);
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	if (paths->obp_path != NULL)
3877c478bd9Sstevel@tonic-gate 		free(paths->obp_path);
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	if (paths->alias_list != NULL) {
3907c478bd9Sstevel@tonic-gate 		for (i = 0; paths->alias_list[i] != NULL; i++)
3917c478bd9Sstevel@tonic-gate 			if (paths->alias_list[i] != NULL)
3927c478bd9Sstevel@tonic-gate 				free(paths->alias_list[i]);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 		free(paths->alias_list);
3957c478bd9Sstevel@tonic-gate 	}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	free(paths);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * Accepts a device name as an input argument.  Uses this to set the
4027c478bd9Sstevel@tonic-gate  * boot-device (or like) variable
4037c478bd9Sstevel@tonic-gate  *
4047c478bd9Sstevel@tonic-gate  * By default, this routine prepends to the list and converts the
4057c478bd9Sstevel@tonic-gate  * logical device name to its most compact prom representation.
4067c478bd9Sstevel@tonic-gate  * Available options include: converting the device name to a prom
4077c478bd9Sstevel@tonic-gate  * path name (but not an alias) or performing no conversion at all;
4087c478bd9Sstevel@tonic-gate  * overwriting the existing contents of boot-device rather than
4097c478bd9Sstevel@tonic-gate  * prepending.
4107c478bd9Sstevel@tonic-gate  */
4117c478bd9Sstevel@tonic-gate int
devfs_bootdev_set_list(const char * dev_name,const uint_t options)4127c478bd9Sstevel@tonic-gate devfs_bootdev_set_list(const char *dev_name, const uint_t options)
4137c478bd9Sstevel@tonic-gate {
4147c478bd9Sstevel@tonic-gate 	char *prom_path;
4157c478bd9Sstevel@tonic-gate 	char *new_bootdev;
4167c478bd9Sstevel@tonic-gate 	char *ptr;
4177c478bd9Sstevel@tonic-gate 	char **alias_list = NULL;
4187c478bd9Sstevel@tonic-gate 	char **prom_list = NULL;
4197c478bd9Sstevel@tonic-gate 	Oppbuf  oppbuf;
4207c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
4217c478bd9Sstevel@tonic-gate 	int ret, len, i, j;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	if (devfs_bootdev_modifiable() != 0) {
4247c478bd9Sstevel@tonic-gate 		return (DEVFS_NOTSUP);
4257c478bd9Sstevel@tonic-gate 	}
4267c478bd9Sstevel@tonic-gate 	if (dev_name == NULL) {
4277c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 	if (strlen(dev_name) >= MAXPATHLEN)
4307c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if ((*dev_name != '/') && !(options & BOOTDEV_LITERAL)) {
4337c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 	if ((options & BOOTDEV_LITERAL) && (options & BOOTDEV_PROMDEV)) {
4367c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	/*
4397c478bd9Sstevel@tonic-gate 	 * if we are prepending, make sure that this obp rev
4407c478bd9Sstevel@tonic-gate 	 * supports multiple boot device entries.
4417c478bd9Sstevel@tonic-gate 	 */
4427c478bd9Sstevel@tonic-gate 	ret = prom_obp_vers();
4437c478bd9Sstevel@tonic-gate 	if (ret < 0) {
4447c478bd9Sstevel@tonic-gate 		return (ret);
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	if ((prom_path = (char *)malloc(MAXVALSIZE)) == NULL) {
4487c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 	if (options & BOOTDEV_LITERAL) {
4517c478bd9Sstevel@tonic-gate 		(void) strcpy(prom_path, dev_name);
4527c478bd9Sstevel@tonic-gate 	} else {
4537c478bd9Sstevel@tonic-gate 		/* need to convert to prom representation */
4547c478bd9Sstevel@tonic-gate 		ret = devfs_get_prom_name_list(dev_name, &prom_list);
4557c478bd9Sstevel@tonic-gate 		if (ret < 0) {
4567c478bd9Sstevel@tonic-gate 			free(prom_path);
4577c478bd9Sstevel@tonic-gate 			return (ret);
4587c478bd9Sstevel@tonic-gate 		}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 		len = MAXVALSIZE;
4617c478bd9Sstevel@tonic-gate 		i = 0;
4627c478bd9Sstevel@tonic-gate 		ptr = prom_path;
4637c478bd9Sstevel@tonic-gate 		while (prom_list && prom_list[i]) {
4647c478bd9Sstevel@tonic-gate 			if (!(options & BOOTDEV_PROMDEV)) {
4657c478bd9Sstevel@tonic-gate 				ret = prom_dev_to_alias(prom_list[i], 0,
466c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 				    &alias_list);
4677c478bd9Sstevel@tonic-gate 				if (ret < 0) {
4687c478bd9Sstevel@tonic-gate 					free(prom_path);
4697c478bd9Sstevel@tonic-gate 					prom_list_free(prom_list);
4707c478bd9Sstevel@tonic-gate 					return (ret);
4717c478bd9Sstevel@tonic-gate 				}
4727c478bd9Sstevel@tonic-gate 				if ((alias_list != NULL) &&
4737c478bd9Sstevel@tonic-gate 				    (alias_list[0] != NULL)) {
4747c478bd9Sstevel@tonic-gate 					(void) snprintf(ptr, len, "%s ",
4757c478bd9Sstevel@tonic-gate 					    alias_list[0]);
4767c478bd9Sstevel@tonic-gate 					for (ret = 0; alias_list[ret] != NULL;
4777c478bd9Sstevel@tonic-gate 					    ret++)
4787c478bd9Sstevel@tonic-gate 						free(alias_list[ret]);
4797c478bd9Sstevel@tonic-gate 				} else {
4807c478bd9Sstevel@tonic-gate 					(void) snprintf(ptr, len, "%s ",
4817c478bd9Sstevel@tonic-gate 					    prom_list[i]);
4827c478bd9Sstevel@tonic-gate 				}
4837c478bd9Sstevel@tonic-gate 				if (alias_list != NULL)
4847c478bd9Sstevel@tonic-gate 					free(alias_list);
4857c478bd9Sstevel@tonic-gate 			} else {
4867c478bd9Sstevel@tonic-gate 				(void) snprintf(ptr, len, "%s ", prom_list[i]);
4877c478bd9Sstevel@tonic-gate 			}
4887c478bd9Sstevel@tonic-gate 			j = strlen(ptr);
4897c478bd9Sstevel@tonic-gate 			len -= j;
4907c478bd9Sstevel@tonic-gate 			ptr += j;
4917c478bd9Sstevel@tonic-gate 			i++;
4927c478bd9Sstevel@tonic-gate 		}
4937c478bd9Sstevel@tonic-gate 		ptr--;
494*f00128d8SToomas Soome 		*ptr = 0;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 		prom_list_free(prom_list);
4977c478bd9Sstevel@tonic-gate 	}
4987c478bd9Sstevel@tonic-gate 	if (options & BOOTDEV_OVERWRITE) {
4997c478bd9Sstevel@tonic-gate 		new_bootdev = prom_path;
5007c478bd9Sstevel@tonic-gate 	} else {
5017c478bd9Sstevel@tonic-gate 		/* retrieve the current value of boot-device */
5027c478bd9Sstevel@tonic-gate 		ret = get_boot_dev_var(opp);
5037c478bd9Sstevel@tonic-gate 		if (ret < 0) {
5047c478bd9Sstevel@tonic-gate 			free(prom_path);
5057c478bd9Sstevel@tonic-gate 			return (ret);
5067c478bd9Sstevel@tonic-gate 		}
5077c478bd9Sstevel@tonic-gate 		/* prepend new entry - deal with duplicates */
5087c478bd9Sstevel@tonic-gate 		new_bootdev = (char *)malloc(strlen(opp->oprom_array)
5097c478bd9Sstevel@tonic-gate 		    + strlen(prom_path) + 2);
5107c478bd9Sstevel@tonic-gate 		if (new_bootdev == NULL) {
5117c478bd9Sstevel@tonic-gate 			free(prom_path);
5127c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
5137c478bd9Sstevel@tonic-gate 		}
5147c478bd9Sstevel@tonic-gate 		(void) strcpy(new_bootdev, prom_path);
5157c478bd9Sstevel@tonic-gate 		if (opp->oprom_size > 0) {
5167c478bd9Sstevel@tonic-gate 			for (ptr = strtok(opp->oprom_array, " "); ptr != NULL;
5177c478bd9Sstevel@tonic-gate 			    ptr = strtok(NULL, " ")) {
5187c478bd9Sstevel@tonic-gate 				/* we strip out duplicates */
5197c478bd9Sstevel@tonic-gate 				if (strcmp(prom_path, ptr) == 0) {
5207c478bd9Sstevel@tonic-gate 					continue;
5217c478bd9Sstevel@tonic-gate 				}
5227c478bd9Sstevel@tonic-gate 				(void) strcat(new_bootdev, " ");
5237c478bd9Sstevel@tonic-gate 				(void) strcat(new_bootdev, ptr);
5247c478bd9Sstevel@tonic-gate 			}
5257c478bd9Sstevel@tonic-gate 		}
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	/* now set the new value */
5297c478bd9Sstevel@tonic-gate 	ret = set_boot_dev_var(opp, new_bootdev);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	if (options & BOOTDEV_OVERWRITE) {
5327c478bd9Sstevel@tonic-gate 		free(prom_path);
5337c478bd9Sstevel@tonic-gate 	} else {
5347c478bd9Sstevel@tonic-gate 		free(new_bootdev);
5357c478bd9Sstevel@tonic-gate 		free(prom_path);
5367c478bd9Sstevel@tonic-gate 	}
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	return (ret);
5397c478bd9Sstevel@tonic-gate }
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate /*
5427c478bd9Sstevel@tonic-gate  * sets the string bootdev as the new value for boot-device
5437c478bd9Sstevel@tonic-gate  */
5447c478bd9Sstevel@tonic-gate static int
set_boot_dev_var(struct openpromio * opp,char * bootdev)5457c478bd9Sstevel@tonic-gate set_boot_dev_var(struct openpromio *opp, char *bootdev)
5467c478bd9Sstevel@tonic-gate {
5477c478bd9Sstevel@tonic-gate 	int prom_fd;
5487c478bd9Sstevel@tonic-gate 	int i;
5497c478bd9Sstevel@tonic-gate 	int ret;
5507c478bd9Sstevel@tonic-gate 	char *valbuf;
5517c478bd9Sstevel@tonic-gate 	char *save_bootdev;
5527c478bd9Sstevel@tonic-gate 	char *bootdev_variables[] = {
5537c478bd9Sstevel@tonic-gate 		"boot-device",
5547c478bd9Sstevel@tonic-gate 		"bootdev",
5557c478bd9Sstevel@tonic-gate 		"boot-from",
5567c478bd9Sstevel@tonic-gate 		NULL
5577c478bd9Sstevel@tonic-gate 	};
5587c478bd9Sstevel@tonic-gate 	int found = 0;
5597c478bd9Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	/* query the prom */
5627c478bd9Sstevel@tonic-gate 	prom_fd = prom_open(O_RDWR);
5637c478bd9Sstevel@tonic-gate 	if (prom_fd < 0) {
5647c478bd9Sstevel@tonic-gate 		return (prom_fd);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	/* get the diagnostic-mode? property */
5687c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, "diagnostic-mode?");
5697c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
5707c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
5717c478bd9Sstevel@tonic-gate 		if ((opp->oprom_size > 0) &&
5727c478bd9Sstevel@tonic-gate 		    (strcmp(opp->oprom_array, "true") == 0)) {
5737c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
5747c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
5757c478bd9Sstevel@tonic-gate 		}
5767c478bd9Sstevel@tonic-gate 	}
5777c478bd9Sstevel@tonic-gate 	/* get the diag-switch? property */
5787c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, "diag-switch?");
5797c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
5807c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
5817c478bd9Sstevel@tonic-gate 		if ((opp->oprom_size > 0) &&
5827c478bd9Sstevel@tonic-gate 		    (strcmp(opp->oprom_array, "true") == 0)) {
5837c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
5847c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
5857c478bd9Sstevel@tonic-gate 		}
5867c478bd9Sstevel@tonic-gate 	}
5877c478bd9Sstevel@tonic-gate 	/*
5887c478bd9Sstevel@tonic-gate 	 * look for one of the following properties in order:
5897c478bd9Sstevel@tonic-gate 	 *	boot-device
5907c478bd9Sstevel@tonic-gate 	 *	bootdev
5917c478bd9Sstevel@tonic-gate 	 *	boot-from
5927c478bd9Sstevel@tonic-gate 	 *
5937c478bd9Sstevel@tonic-gate 	 * Use the first one that we find.
5947c478bd9Sstevel@tonic-gate 	 */
5957c478bd9Sstevel@tonic-gate 	*ip = 0;
5967c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXPROPSIZE;
5977c478bd9Sstevel@tonic-gate 	while ((opp->oprom_size != 0) && (!found)) {
5987c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXPROPSIZE;
5997c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
6007c478bd9Sstevel@tonic-gate 			break;
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 		for (i = 0; bootdev_variables[i] != NULL; i++) {
6037c478bd9Sstevel@tonic-gate 			if (strcmp(opp->oprom_array, bootdev_variables[i])
6047c478bd9Sstevel@tonic-gate 			    == 0) {
6057c478bd9Sstevel@tonic-gate 				found = 1;
6067c478bd9Sstevel@tonic-gate 				break;
6077c478bd9Sstevel@tonic-gate 			}
6087c478bd9Sstevel@tonic-gate 		}
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 	if (found) {
6117c478bd9Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6127c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXVALSIZE;
6137c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
6147c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
6157c478bd9Sstevel@tonic-gate 			return (DEVFS_NOTSUP);
6167c478bd9Sstevel@tonic-gate 		}
6177c478bd9Sstevel@tonic-gate 	} else {
6187c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
6197c478bd9Sstevel@tonic-gate 		return (DEVFS_NOTSUP);
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	/* save the old copy in case we fail */
6237c478bd9Sstevel@tonic-gate 	if ((save_bootdev = strdup(opp->oprom_array)) == NULL) {
6247c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
6257c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 	/* set up the new value of boot-device */
6287c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6297c478bd9Sstevel@tonic-gate 	valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
6307c478bd9Sstevel@tonic-gate 	(void) strcpy(valbuf, bootdev);
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
6357c478bd9Sstevel@tonic-gate 		free(save_bootdev);
6367c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
6377c478bd9Sstevel@tonic-gate 		return (DEVFS_ERR);
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	/*
6417c478bd9Sstevel@tonic-gate 	 * now read it back to make sure it took
6427c478bd9Sstevel@tonic-gate 	 */
6437c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6447c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
6457c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
6467c478bd9Sstevel@tonic-gate 		if (_prom_strcmp(opp->oprom_array, bootdev) == 0) {
6477c478bd9Sstevel@tonic-gate 			/* success */
6487c478bd9Sstevel@tonic-gate 			free(save_bootdev);
6497c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
6507c478bd9Sstevel@tonic-gate 			return (0);
6517c478bd9Sstevel@tonic-gate 		}
6527c478bd9Sstevel@tonic-gate 		/* deal with setting it to "" */
6537c478bd9Sstevel@tonic-gate 		if ((strlen(bootdev) == 0) && (opp->oprom_size == 0)) {
6547c478bd9Sstevel@tonic-gate 			/* success */
6557c478bd9Sstevel@tonic-gate 			free(save_bootdev);
6567c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
6577c478bd9Sstevel@tonic-gate 			return (0);
6587c478bd9Sstevel@tonic-gate 		}
6597c478bd9Sstevel@tonic-gate 	}
6607c478bd9Sstevel@tonic-gate 	/*
6617c478bd9Sstevel@tonic-gate 	 * something did not take - write out the old value and
6627c478bd9Sstevel@tonic-gate 	 * hope that we can restore things...
6637c478bd9Sstevel@tonic-gate 	 *
6647c478bd9Sstevel@tonic-gate 	 * unfortunately, there is no way for us to differentiate
6657c478bd9Sstevel@tonic-gate 	 * whether we exceeded the maximum number of characters
6667c478bd9Sstevel@tonic-gate 	 * allowable.  The limit varies from prom rev to prom
6677c478bd9Sstevel@tonic-gate 	 * rev, and on some proms, when the limit is
6687c478bd9Sstevel@tonic-gate 	 * exceeded, whatever was in the
6697c478bd9Sstevel@tonic-gate 	 * boot-device variable becomes unreadable.
6707c478bd9Sstevel@tonic-gate 	 *
6717c478bd9Sstevel@tonic-gate 	 * so if we fail, we will assume we ran out of room.  If we
6727c478bd9Sstevel@tonic-gate 	 * not able to restore the original setting, then we will
6737c478bd9Sstevel@tonic-gate 	 * return DEVFS_ERR instead.
6747c478bd9Sstevel@tonic-gate 	 */
6757c478bd9Sstevel@tonic-gate 	ret = DEVFS_LIMIT;
6767c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, bootdev_variables[i]);
6777c478bd9Sstevel@tonic-gate 	valbuf = opp->oprom_array + strlen(opp->oprom_array) + 1;
6787c478bd9Sstevel@tonic-gate 	(void) strcpy(valbuf, save_bootdev);
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	opp->oprom_size = strlen(valbuf) + strlen(opp->oprom_array) + 2;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMSETOPT, opp) < 0) {
6837c478bd9Sstevel@tonic-gate 		ret = DEVFS_ERR;
6847c478bd9Sstevel@tonic-gate 	}
6857c478bd9Sstevel@tonic-gate 	free(save_bootdev);
6867c478bd9Sstevel@tonic-gate 	prom_close(prom_fd);
6877c478bd9Sstevel@tonic-gate 	return (ret);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate /*
6907c478bd9Sstevel@tonic-gate  * retrieve the current value for boot-device
6917c478bd9Sstevel@tonic-gate  */
6927c478bd9Sstevel@tonic-gate static int
get_boot_dev_var(struct openpromio * opp)6937c478bd9Sstevel@tonic-gate get_boot_dev_var(struct openpromio *opp)
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate 	int prom_fd;
6967c478bd9Sstevel@tonic-gate 	int i;
6977c478bd9Sstevel@tonic-gate 	char *bootdev_variables[] = {
6987c478bd9Sstevel@tonic-gate 		"boot-device",
6997c478bd9Sstevel@tonic-gate 		"bootdev",
7007c478bd9Sstevel@tonic-gate 		"boot-from",
7017c478bd9Sstevel@tonic-gate 		NULL
7027c478bd9Sstevel@tonic-gate 	};
7037c478bd9Sstevel@tonic-gate 	int found = 0;
7047c478bd9Sstevel@tonic-gate 	int *ip = (int *)((void *)opp->oprom_array);
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	/* query the prom */
7077c478bd9Sstevel@tonic-gate 	prom_fd = prom_open(O_RDONLY);
7087c478bd9Sstevel@tonic-gate 	if (prom_fd < 0) {
7097c478bd9Sstevel@tonic-gate 		return (prom_fd);
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	/* get the diagnostic-mode? property */
7137c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, "diagnostic-mode?");
7147c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
7157c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
7167c478bd9Sstevel@tonic-gate 		if ((opp->oprom_size > 0) &&
7177c478bd9Sstevel@tonic-gate 		    (strcmp(opp->oprom_array, "true") == 0)) {
7187c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
7197c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
7207c478bd9Sstevel@tonic-gate 		}
7217c478bd9Sstevel@tonic-gate 	}
7227c478bd9Sstevel@tonic-gate 	/* get the diag-switch? property */
7237c478bd9Sstevel@tonic-gate 	(void) strcpy(opp->oprom_array, "diag-switch?");
7247c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXVALSIZE;
7257c478bd9Sstevel@tonic-gate 	if (ioctl(prom_fd, OPROMGETOPT, opp) >= 0) {
7267c478bd9Sstevel@tonic-gate 		if ((opp->oprom_size > 0) &&
7277c478bd9Sstevel@tonic-gate 		    (strcmp(opp->oprom_array, "true") == 0)) {
7287c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
7297c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
7307c478bd9Sstevel@tonic-gate 		}
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 	/*
7337c478bd9Sstevel@tonic-gate 	 * look for one of the following properties in order:
7347c478bd9Sstevel@tonic-gate 	 *	boot-device
7357c478bd9Sstevel@tonic-gate 	 *	bootdev
7367c478bd9Sstevel@tonic-gate 	 *	boot-from
7377c478bd9Sstevel@tonic-gate 	 *
7387c478bd9Sstevel@tonic-gate 	 * Use the first one that we find.
7397c478bd9Sstevel@tonic-gate 	 */
7407c478bd9Sstevel@tonic-gate 	*ip = 0;
7417c478bd9Sstevel@tonic-gate 	opp->oprom_size = MAXPROPSIZE;
7427c478bd9Sstevel@tonic-gate 	while ((opp->oprom_size != 0) && (!found)) {
7437c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXPROPSIZE;
7447c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0) {
7457c478bd9Sstevel@tonic-gate 			break;
7467c478bd9Sstevel@tonic-gate 		}
7477c478bd9Sstevel@tonic-gate 		for (i = 0; bootdev_variables[i] != NULL; i++) {
7487c478bd9Sstevel@tonic-gate 			if (strcmp(opp->oprom_array, bootdev_variables[i])
7497c478bd9Sstevel@tonic-gate 			    == 0) {
7507c478bd9Sstevel@tonic-gate 				found = 1;
7517c478bd9Sstevel@tonic-gate 				break;
7527c478bd9Sstevel@tonic-gate 			}
7537c478bd9Sstevel@tonic-gate 		}
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 	if (found) {
7567c478bd9Sstevel@tonic-gate 		(void) strcpy(opp->oprom_array, bootdev_variables[i]);
7577c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXVALSIZE;
7587c478bd9Sstevel@tonic-gate 		if (ioctl(prom_fd, OPROMGETOPT, opp) < 0) {
7597c478bd9Sstevel@tonic-gate 			prom_close(prom_fd);
7607c478bd9Sstevel@tonic-gate 			return (DEVFS_ERR);
7617c478bd9Sstevel@tonic-gate 		}
7627c478bd9Sstevel@tonic-gate 		/* boot-device exists but contains nothing */
7637c478bd9Sstevel@tonic-gate 		if (opp->oprom_size == 0) {
7647c478bd9Sstevel@tonic-gate 			*opp->oprom_array = '\0';
7657c478bd9Sstevel@tonic-gate 		}
7667c478bd9Sstevel@tonic-gate 	} else {
7677c478bd9Sstevel@tonic-gate 		prom_close(prom_fd);
7687c478bd9Sstevel@tonic-gate 		return (DEVFS_NOTSUP);
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 	prom_close(prom_fd);
7717c478bd9Sstevel@tonic-gate 	return (0);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate #ifndef __sparc
7757c478bd9Sstevel@tonic-gate static FILE *
open_diskmap(void)7767c478bd9Sstevel@tonic-gate open_diskmap(void)
7777c478bd9Sstevel@tonic-gate {
7787c478bd9Sstevel@tonic-gate 	FILE *fp;
7797c478bd9Sstevel@tonic-gate 	char cmd[PATH_MAX];
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	/* make sure we have a map file */
7827c478bd9Sstevel@tonic-gate 	fp = fopen(GRUBDISK_MAP, "r");
7837c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
7847c478bd9Sstevel@tonic-gate 		(void) snprintf(cmd, sizeof (cmd),
7857c478bd9Sstevel@tonic-gate 		    "%s > /dev/null", CREATE_DISKMAP);
7867c478bd9Sstevel@tonic-gate 		(void) system(cmd);
7877c478bd9Sstevel@tonic-gate 		fp = fopen(GRUBDISK_MAP, "r");
7887c478bd9Sstevel@tonic-gate 	}
7897c478bd9Sstevel@tonic-gate 	return (fp);
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate static int
find_x86_boot_device(struct openpromio * opp)7937c478bd9Sstevel@tonic-gate find_x86_boot_device(struct openpromio *opp)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	int ret = DEVFS_ERR;
7967c478bd9Sstevel@tonic-gate 	char *cp, line[MAXVALSIZE + 6];
7977c478bd9Sstevel@tonic-gate 	FILE *file;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	file = open_diskmap();
8007c478bd9Sstevel@tonic-gate 	if (file == NULL)
8017c478bd9Sstevel@tonic-gate 		return (DEVFS_ERR);
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	while (fgets(line, MAXVALSIZE + 6, file)) {
8047c478bd9Sstevel@tonic-gate 		if (strncmp(line, "0 ", 2) != 0)
8057c478bd9Sstevel@tonic-gate 			continue;
8067c478bd9Sstevel@tonic-gate 		/* drop new-line */
8077c478bd9Sstevel@tonic-gate 		line[strlen(line) - 1] = '\0';
8087c478bd9Sstevel@tonic-gate 		/*
8097c478bd9Sstevel@tonic-gate 		 * an x86 BIOS only boots a disk, not a partition
8107c478bd9Sstevel@tonic-gate 		 * or a slice, so hard-code :q (p0)
8117c478bd9Sstevel@tonic-gate 		 */
8127c478bd9Sstevel@tonic-gate 		cp = strchr(line + 2, ' ');
8137c478bd9Sstevel@tonic-gate 		if (cp == NULL)
8147c478bd9Sstevel@tonic-gate 			break;
8157c478bd9Sstevel@tonic-gate 		(void) snprintf(opp->oprom_array, MAXVALSIZE,
8167c478bd9Sstevel@tonic-gate 		    "%s:q", cp + 1);
8177c478bd9Sstevel@tonic-gate 		opp->oprom_size = MAXVALSIZE;
8187c478bd9Sstevel@tonic-gate 		ret = 0;
8197c478bd9Sstevel@tonic-gate 		break;
8207c478bd9Sstevel@tonic-gate 	}
8217c478bd9Sstevel@tonic-gate 	(void) fclose(file);
8227c478bd9Sstevel@tonic-gate 	return (ret);
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate #endif /* ndef __sparc */
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate /*
8277c478bd9Sstevel@tonic-gate  * retrieve the list of entries in the boot-device configuration
8287c478bd9Sstevel@tonic-gate  * variable.  An array of boot_dev structs will be created, one entry
8297c478bd9Sstevel@tonic-gate  * for each device name in the boot-device variable.  Each entry
8307c478bd9Sstevel@tonic-gate  * in the array will contain the logical device representation of the
8317c478bd9Sstevel@tonic-gate  * boot-device entry, if any.
8327c478bd9Sstevel@tonic-gate  *
8337c478bd9Sstevel@tonic-gate  * default_root. if set, is used to locate logical device entries in
8347c478bd9Sstevel@tonic-gate  * directories other than /dev
8357c478bd9Sstevel@tonic-gate  */
8367c478bd9Sstevel@tonic-gate int
devfs_bootdev_get_list(const char * default_root,struct boot_dev *** bootdev_list)8377c478bd9Sstevel@tonic-gate devfs_bootdev_get_list(const char *default_root,
838*f00128d8SToomas Soome     struct boot_dev ***bootdev_list)
8397c478bd9Sstevel@tonic-gate {
8407c478bd9Sstevel@tonic-gate 	Oppbuf  oppbuf;
8417c478bd9Sstevel@tonic-gate 	struct openpromio *opp = &(oppbuf.opp);
8427c478bd9Sstevel@tonic-gate 	int i;
8437c478bd9Sstevel@tonic-gate 	struct boot_dev **tmp_list;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if (default_root == NULL) {
8467c478bd9Sstevel@tonic-gate 		default_root = "";
8477c478bd9Sstevel@tonic-gate 	} else if (*default_root != '/') {
8487c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	if (bootdev_list == NULL) {
8527c478bd9Sstevel@tonic-gate 		return (DEVFS_INVAL);
8537c478bd9Sstevel@tonic-gate 	}
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	/* get the boot-device variable */
8567c478bd9Sstevel@tonic-gate #if defined(sparc)
8577c478bd9Sstevel@tonic-gate 	i = get_boot_dev_var(opp);
8587c478bd9Sstevel@tonic-gate #else
8597c478bd9Sstevel@tonic-gate 	i = find_x86_boot_device(opp);
8607c478bd9Sstevel@tonic-gate #endif
8617c478bd9Sstevel@tonic-gate 	if (i < 0) {
8627c478bd9Sstevel@tonic-gate 		return (i);
8637c478bd9Sstevel@tonic-gate 	}
8647c478bd9Sstevel@tonic-gate 	/* now try to translate each entry to a logical device. */
8657c478bd9Sstevel@tonic-gate 	i = process_bootdev(opp->oprom_array, default_root, &tmp_list);
8667c478bd9Sstevel@tonic-gate 	if (i == 0) {
8677c478bd9Sstevel@tonic-gate 		*bootdev_list = tmp_list;
8687c478bd9Sstevel@tonic-gate 		return (0);
8697c478bd9Sstevel@tonic-gate 	} else {
8707c478bd9Sstevel@tonic-gate 		return (i);
8717c478bd9Sstevel@tonic-gate 	}
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate /*
8757c478bd9Sstevel@tonic-gate  * loop thru the list of entries in a boot-device configuration
8767c478bd9Sstevel@tonic-gate  * variable.
8777c478bd9Sstevel@tonic-gate  */
8787c478bd9Sstevel@tonic-gate static int
process_bootdev(const char * bootdevice,const char * default_root,struct boot_dev *** list)8797c478bd9Sstevel@tonic-gate process_bootdev(const char *bootdevice, const char *default_root,
880*f00128d8SToomas Soome     struct boot_dev ***list)
8817c478bd9Sstevel@tonic-gate {
8827c478bd9Sstevel@tonic-gate 	int i;
8837c478bd9Sstevel@tonic-gate 	char *entry, *ptr;
8847c478bd9Sstevel@tonic-gate 	char prom_path[MAXPATHLEN];
8857c478bd9Sstevel@tonic-gate 	char ret_buf[MAXPATHLEN];
8867c478bd9Sstevel@tonic-gate 	struct boot_dev **bootdev_array;
8877c478bd9Sstevel@tonic-gate 	int num_entries = 0;
8887c478bd9Sstevel@tonic-gate 	int found = 0;
8897c478bd9Sstevel@tonic-gate 	int vers;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	if ((entry = (char *)malloc(strlen(bootdevice) + 1)) == NULL) {
8927c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 	/* count the number of entries */
8957c478bd9Sstevel@tonic-gate 	(void) strcpy(entry, bootdevice);
8967c478bd9Sstevel@tonic-gate 	for (ptr = strtok(entry, " "); ptr != NULL;
8977c478bd9Sstevel@tonic-gate 	    ptr = strtok(NULL, " ")) {
8987c478bd9Sstevel@tonic-gate 		num_entries++;
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 	(void) strcpy(entry, bootdevice);
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	bootdev_array = (struct boot_dev **)
9037c478bd9Sstevel@tonic-gate 	    calloc((size_t)num_entries + 1, sizeof (struct boot_dev *));
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	if (bootdev_array == NULL) {
9067c478bd9Sstevel@tonic-gate 		free(entry);
9077c478bd9Sstevel@tonic-gate 		return (DEVFS_NOMEM);
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	vers = prom_obp_vers();
9117c478bd9Sstevel@tonic-gate 	if (vers < 0) {
9127c478bd9Sstevel@tonic-gate 		free(entry);
9137c478bd9Sstevel@tonic-gate 		return (vers);
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	/* for each entry in boot-device, do... */
9177c478bd9Sstevel@tonic-gate 	for (ptr = strtok(entry, " "), i = 0; ptr != NULL;
9187c478bd9Sstevel@tonic-gate 	    ptr = strtok(NULL, " "), i++) {
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 		if ((bootdev_array[i] = alloc_bootdev(ptr)) == NULL) {
9217c478bd9Sstevel@tonic-gate 			devfs_bootdev_free_list(bootdev_array);
9227c478bd9Sstevel@tonic-gate 			free(entry);
9237c478bd9Sstevel@tonic-gate 			return (DEVFS_NOMEM);
9247c478bd9Sstevel@tonic-gate 		}
9257c478bd9Sstevel@tonic-gate 
926b6f77fefSas 		/*
927b6f77fefSas 		 * prom boot-device may be aliased, so we need to do
928b6f77fefSas 		 * the necessary prom alias to dev translation.
929b6f77fefSas 		 */
930b6f77fefSas 		if (*ptr != '/') {
931b6f77fefSas 			if (alias_to_prom_dev(ptr, prom_path) < 0) {
932b6f77fefSas 				continue;
933b6f77fefSas 			}
934b6f77fefSas 		} else {
935b6f77fefSas 			(void) strcpy(prom_path, ptr);
936b6f77fefSas 		}
937b6f77fefSas 
9387c478bd9Sstevel@tonic-gate 		/* now we have a prom device path - convert to a devfs name */
9397c478bd9Sstevel@tonic-gate 		if (devfs_prom_to_dev_name(prom_path, ret_buf) < 0) {
940c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 			continue;
9417c478bd9Sstevel@tonic-gate 		}
942b6f77fefSas 
9437c478bd9Sstevel@tonic-gate 		/* append any default minor names necessary */
9447c478bd9Sstevel@tonic-gate 		if (process_minor_name(ret_buf, default_root) < 0) {
945c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 			continue;
9467c478bd9Sstevel@tonic-gate 		}
9477c478bd9Sstevel@tonic-gate 		found = 1;
948b6f77fefSas 
9497c478bd9Sstevel@tonic-gate 		/*
9507c478bd9Sstevel@tonic-gate 		 * store the physical device path for now - when
9517c478bd9Sstevel@tonic-gate 		 * we are all done with the entries, we will convert
9527c478bd9Sstevel@tonic-gate 		 * these to their logical device name equivalents
9537c478bd9Sstevel@tonic-gate 		 */
9547c478bd9Sstevel@tonic-gate 		bootdev_array[i]->bootdev_trans[0] = strdup(ret_buf);
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 	/*
9577c478bd9Sstevel@tonic-gate 	 * Convert all of the boot-device entries that translated to a
9587c478bd9Sstevel@tonic-gate 	 * physical device path in /devices to a logical device path
9597c478bd9Sstevel@tonic-gate 	 * in /dev (note that there may be several logical device paths
9607c478bd9Sstevel@tonic-gate 	 * associated with a single physical device path - return them all
9617c478bd9Sstevel@tonic-gate 	 */
9627c478bd9Sstevel@tonic-gate 	if (found) {
9637c478bd9Sstevel@tonic-gate 		if (devfs_phys_to_logical(bootdev_array, num_entries,
9647c478bd9Sstevel@tonic-gate 		    default_root) < 0) {
9657c478bd9Sstevel@tonic-gate 			devfs_bootdev_free_list(bootdev_array);
9667c478bd9Sstevel@tonic-gate 			bootdev_array = NULL;
9677c478bd9Sstevel@tonic-gate 		}
9687c478bd9Sstevel@tonic-gate 	}
9697c478bd9Sstevel@tonic-gate 	free(entry);
9707c478bd9Sstevel@tonic-gate 	*list = bootdev_array;
9717c478bd9Sstevel@tonic-gate 	return (0);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate /*
9757c478bd9Sstevel@tonic-gate  * We may get a device path from the prom that has no minor name
9767c478bd9Sstevel@tonic-gate  * information included in it.  Since this device name will not
9777c478bd9Sstevel@tonic-gate  * correspond directly to a physical device in /devices, we do our
9787c478bd9Sstevel@tonic-gate  * best to append what the default minor name should be and try this.
9797c478bd9Sstevel@tonic-gate  *
9807c478bd9Sstevel@tonic-gate  * For sparc: we append slice 0 (:a).
9817c478bd9Sstevel@tonic-gate  * For x86: we append fdisk partition 0 (:q).
9827c478bd9Sstevel@tonic-gate  */
9837c478bd9Sstevel@tonic-gate static int
process_minor_name(char * dev_path,const char * root)9847c478bd9Sstevel@tonic-gate process_minor_name(char *dev_path, const char *root)
9857c478bd9Sstevel@tonic-gate {
9867c478bd9Sstevel@tonic-gate 	char *cp;
9877c478bd9Sstevel@tonic-gate #if defined(sparc)
9887c478bd9Sstevel@tonic-gate 	const char *default_minor_name = "a";
9897c478bd9Sstevel@tonic-gate #else
9907c478bd9Sstevel@tonic-gate 	const char *default_minor_name = "q";
9917c478bd9Sstevel@tonic-gate #endif
9927c478bd9Sstevel@tonic-gate 	int n;
9937c478bd9Sstevel@tonic-gate 	struct stat stat_buf;
9947c478bd9Sstevel@tonic-gate 	char path[MAXPATHLEN];
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
9977c478bd9Sstevel@tonic-gate 	/*
9987c478bd9Sstevel@tonic-gate 	 * if the device file already exists as given to us, there
9997c478bd9Sstevel@tonic-gate 	 * is nothing to do but return.
10007c478bd9Sstevel@tonic-gate 	 */
10017c478bd9Sstevel@tonic-gate 	if (stat(path, &stat_buf) == 0) {
10027c478bd9Sstevel@tonic-gate 		return (0);
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 	/*
10057c478bd9Sstevel@tonic-gate 	 * if there is no ':' after the last '/' character, or if there is
10067c478bd9Sstevel@tonic-gate 	 * a ':' with no specifier, append the default segment specifier
10077c478bd9Sstevel@tonic-gate 	 * ; if there is a ':' followed by a digit, this indicates
10087c478bd9Sstevel@tonic-gate 	 * a partition number (which does not map into the /devices name
10097c478bd9Sstevel@tonic-gate 	 * space), so strip the number and replace it with the letter
10107c478bd9Sstevel@tonic-gate 	 * that represents the partition index
10117c478bd9Sstevel@tonic-gate 	 */
10127c478bd9Sstevel@tonic-gate 	if ((cp = strrchr(dev_path, '/')) != NULL) {
10137c478bd9Sstevel@tonic-gate 		if ((cp = strchr(cp, ':')) == NULL) {
10147c478bd9Sstevel@tonic-gate 			(void) strcat(dev_path, ":");
10157c478bd9Sstevel@tonic-gate 			(void) strcat(dev_path, default_minor_name);
10167c478bd9Sstevel@tonic-gate 		} else if (*++cp == '\0') {
10177c478bd9Sstevel@tonic-gate 			(void) strcat(dev_path, default_minor_name);
10187c478bd9Sstevel@tonic-gate 		} else if (isdigit(*cp)) {
10197c478bd9Sstevel@tonic-gate 			n = atoi(cp);
10207c478bd9Sstevel@tonic-gate 			/* make sure to squash the digit */
10217c478bd9Sstevel@tonic-gate 			*cp = '\0';
10227c478bd9Sstevel@tonic-gate 			switch (n) {
1023c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 			case 0:	(void) strcat(dev_path, "q");
10247c478bd9Sstevel@tonic-gate 					break;
1025c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 			case 1:	(void) strcat(dev_path, "r");
10267c478bd9Sstevel@tonic-gate 					break;
1027c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 			case 2:	(void) strcat(dev_path, "s");
10287c478bd9Sstevel@tonic-gate 					break;
1029c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 			case 3:	(void) strcat(dev_path, "t");
10307c478bd9Sstevel@tonic-gate 					break;
1031c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 			case 4:	(void) strcat(dev_path, "u");
10327c478bd9Sstevel@tonic-gate 					break;
1033c279fc79Ssriman bhavanam - Sun Microsystems - Bangalore India 			default: (void) strcat(dev_path, "a");
10347c478bd9Sstevel@tonic-gate 					break;
10357c478bd9Sstevel@tonic-gate 			}
10367c478bd9Sstevel@tonic-gate 		}
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 	/*
10397c478bd9Sstevel@tonic-gate 	 * see if we can find something now.
10407c478bd9Sstevel@tonic-gate 	 */
10417c478bd9Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s%s%s", root, DEVICES, dev_path);
10427c478bd9Sstevel@tonic-gate 
10437c478bd9Sstevel@tonic-gate 	if (stat(path, &stat_buf) == 0) {
10447c478bd9Sstevel@tonic-gate 		return (0);
10457c478bd9Sstevel@tonic-gate 	} else {
10467c478bd9Sstevel@tonic-gate 		return (-1);
10477c478bd9Sstevel@tonic-gate 	}
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate /*
10517c478bd9Sstevel@tonic-gate  * for each entry in bootdev_array, convert the physical device
10527c478bd9Sstevel@tonic-gate  * representation of the boot-device entry to one or more logical device
10537c478bd9Sstevel@tonic-gate  * entries.  We use the hammer method - walk through the logical device
10547c478bd9Sstevel@tonic-gate  * name space looking for matches (/dev).  We use nftw to do this.
10557c478bd9Sstevel@tonic-gate  */
10567c478bd9Sstevel@tonic-gate static int
devfs_phys_to_logical(struct boot_dev ** bootdev_array,const int array_size,const char * default_root)10577c478bd9Sstevel@tonic-gate devfs_phys_to_logical(struct boot_dev **bootdev_array, const int array_size,
10587c478bd9Sstevel@tonic-gate     const char *default_root)
10597c478bd9Sstevel@tonic-gate {
10607c478bd9Sstevel@tonic-gate 	int walk_flags = FTW_PHYS | FTW_MOUNT;
10617c478bd9Sstevel@tonic-gate 	char *full_path;
10627c478bd9Sstevel@tonic-gate 	struct name_list *list;
10637c478bd9Sstevel@tonic-gate 	int count, i;
10647c478bd9Sstevel@tonic-gate 	char **dev_name_array;
10657c478bd9Sstevel@tonic-gate 	size_t default_root_len;
10667c478bd9Sstevel@tonic-gate 	char *dev_dir = DEV;
10677c478bd9Sstevel@tonic-gate 	int len;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	if (array_size < 0) {
10707c478bd9Sstevel@tonic-gate 		return (-1);
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	if (bootdev_array == NULL) {
10747c478bd9Sstevel@tonic-gate 		return (-1);
10757c478bd9Sstevel@tonic-gate 	}
10767c478bd9Sstevel@tonic-gate 	if (default_root == NULL) {
10777c478bd9Sstevel@tonic-gate 		return (-1);
10787c478bd9Sstevel@tonic-gate 	}
10797c478bd9Sstevel@tonic-gate 	default_root_len = strlen(default_root);
10807c478bd9Sstevel@tonic-gate 	if ((default_root_len != 0) && (*default_root != '/')) {
10817c478bd9Sstevel@tonic-gate 		return (-1);
10827c478bd9Sstevel@tonic-gate 	}
1083b6f77fefSas 
10847c478bd9Sstevel@tonic-gate 	/* short cut for an empty array */
10857c478bd9Sstevel@tonic-gate 	if (*bootdev_array == NULL) {
10867c478bd9Sstevel@tonic-gate 		return (0);
10877c478bd9Sstevel@tonic-gate 	}
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	/* tell nftw where to start (default: /dev) */
10907c478bd9Sstevel@tonic-gate 	len = default_root_len + strlen(dev_dir) + 1;
10917c478bd9Sstevel@tonic-gate 	if ((full_path = (char *)malloc(len)) == NULL) {
10927c478bd9Sstevel@tonic-gate 		return (-1);
10937c478bd9Sstevel@tonic-gate 	}
1094b6f77fefSas 
10957c478bd9Sstevel@tonic-gate 	/*
10967c478bd9Sstevel@tonic-gate 	 * if the default root path is terminated with a /, we have to
10977c478bd9Sstevel@tonic-gate 	 * make sure we don't end up with one too many slashes in the
10987c478bd9Sstevel@tonic-gate 	 * path we are building.
10997c478bd9Sstevel@tonic-gate 	 */
11007c478bd9Sstevel@tonic-gate 	if ((default_root_len > (size_t)0) &&
11017c478bd9Sstevel@tonic-gate 	    (default_root[default_root_len - 1] == '/')) {
11027c478bd9Sstevel@tonic-gate 		(void) snprintf(full_path, len, "%s%s", default_root,
11037c478bd9Sstevel@tonic-gate 		    &dev_dir[1]);
11047c478bd9Sstevel@tonic-gate 	} else {
11057c478bd9Sstevel@tonic-gate 		(void) snprintf(full_path, len, "%s%s", default_root, dev_dir);
11067c478bd9Sstevel@tonic-gate 	}
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	/*
11097c478bd9Sstevel@tonic-gate 	 * we need to muck with global data to make nftw work
11107c478bd9Sstevel@tonic-gate 	 * so single thread access
11117c478bd9Sstevel@tonic-gate 	 */
11127c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&dev_lists_lk);
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	/*
11157c478bd9Sstevel@tonic-gate 	 * set the global vars bootdev_list and dev_list for use by nftw
11167c478bd9Sstevel@tonic-gate 	 * dev_list is an array of lists - one for each boot-device
11177c478bd9Sstevel@tonic-gate 	 * entry.  The nftw function will create a list of logical device
11187c478bd9Sstevel@tonic-gate 	 * entries for each boot-device and put all of the lists in
11197c478bd9Sstevel@tonic-gate 	 * dev_list.
11207c478bd9Sstevel@tonic-gate 	 */
11217c478bd9Sstevel@tonic-gate 	dev_list = (struct name_list **)
11227c478bd9Sstevel@tonic-gate 	    calloc(array_size, sizeof (struct name_list *));
11237c478bd9Sstevel@tonic-gate 	if (dev_list == NULL) {
11247c478bd9Sstevel@tonic-gate 		free(full_path);
11257c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&dev_lists_lk);
11267c478bd9Sstevel@tonic-gate 		return (-1);
11277c478bd9Sstevel@tonic-gate 	}
11287c478bd9Sstevel@tonic-gate 	bootdev_list = bootdev_array;
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	if (nftw(full_path, check_logical_dev, FT_DEPTH, walk_flags) == -1) {
11317c478bd9Sstevel@tonic-gate 		bootdev_list = NULL;
11327c478bd9Sstevel@tonic-gate 		free(full_path);
11337c478bd9Sstevel@tonic-gate 		for (i = 0; i < array_size; i++) {
11347c478bd9Sstevel@tonic-gate 			free_name_list(dev_list[i], 1);
11357c478bd9Sstevel@tonic-gate 		}
11367c478bd9Sstevel@tonic-gate 		/* don't free dev_list here because it's been handed off */
11377c478bd9Sstevel@tonic-gate 		dev_list = NULL;
11387c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&dev_lists_lk);
11397c478bd9Sstevel@tonic-gate 		return (-1);
11407c478bd9Sstevel@tonic-gate 	}
1141b6f77fefSas 
11427c478bd9Sstevel@tonic-gate 	/*
11437c478bd9Sstevel@tonic-gate 	 * now we have a filled in dev_list.  So for each logical device
11447c478bd9Sstevel@tonic-gate 	 * list in dev_list, count the number of entries in the list,
11457c478bd9Sstevel@tonic-gate 	 * create an array of strings of logical devices, and save in the
11467c478bd9Sstevel@tonic-gate 	 * corresponding boot_dev structure.
11477c478bd9Sstevel@tonic-gate 	 */
11487c478bd9Sstevel@tonic-gate 	for (i = 0; i < array_size; i++) {
11497c478bd9Sstevel@tonic-gate 		/* get the next list */
11507c478bd9Sstevel@tonic-gate 		list = dev_list[i];
11517c478bd9Sstevel@tonic-gate 		count = 0;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 		/* count the number of entries in the list */
11547c478bd9Sstevel@tonic-gate 		while (list != NULL) {
11557c478bd9Sstevel@tonic-gate 			count++;
11567c478bd9Sstevel@tonic-gate 			list = list->next;
11577c478bd9Sstevel@tonic-gate 		}
11587c478bd9Sstevel@tonic-gate 		if ((dev_name_array =
11597c478bd9Sstevel@tonic-gate 		    (char **)malloc((count + 1) * sizeof (char *)))
11607c478bd9Sstevel@tonic-gate 		    == NULL) {
11617c478bd9Sstevel@tonic-gate 			continue;
11627c478bd9Sstevel@tonic-gate 		}
11637c478bd9Sstevel@tonic-gate 		list = dev_list[i];
11647c478bd9Sstevel@tonic-gate 		count = 0;
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 		/* fill in the array */
11677c478bd9Sstevel@tonic-gate 		while (list != NULL) {
11687c478bd9Sstevel@tonic-gate 			dev_name_array[count] = list->name;
11697c478bd9Sstevel@tonic-gate 			count++;
11707c478bd9Sstevel@tonic-gate 			list = list->next;
11717c478bd9Sstevel@tonic-gate 		}
1172b6f77fefSas 
11737c478bd9Sstevel@tonic-gate 		/*
11747c478bd9Sstevel@tonic-gate 		 * null terminate the array
11757c478bd9Sstevel@tonic-gate 		 */
11767c478bd9Sstevel@tonic-gate 		dev_name_array[count] = NULL;
1177b6f77fefSas 		if ((bootdev_array[i] != NULL) && (bootdev_array[i]->
1178b6f77fefSas 		    bootdev_trans[0] != NULL)) {
11797c478bd9Sstevel@tonic-gate 			free(bootdev_array[i]->bootdev_trans[0]);
11807c478bd9Sstevel@tonic-gate 		}
1181b6f77fefSas 		if (bootdev_array[i] != NULL) {
1182b6f77fefSas 			free(bootdev_array[i]->bootdev_trans);
1183b6f77fefSas 			bootdev_array[i]->bootdev_trans = dev_name_array;
1184b6f77fefSas 		}
11857c478bd9Sstevel@tonic-gate 	}
11867c478bd9Sstevel@tonic-gate 	bootdev_list = NULL;
11877c478bd9Sstevel@tonic-gate 	free(full_path);
11887c478bd9Sstevel@tonic-gate 	for (i = 0; i < array_size; i++) {
11897c478bd9Sstevel@tonic-gate 		free_name_list(dev_list[i], 0);
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate 	free(dev_list);
11927c478bd9Sstevel@tonic-gate 	dev_list = NULL;
11937c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&dev_lists_lk);
11947c478bd9Sstevel@tonic-gate 	return (0);
11957c478bd9Sstevel@tonic-gate }
11967c478bd9Sstevel@tonic-gate /*
11977c478bd9Sstevel@tonic-gate  * nftw function
11987c478bd9Sstevel@tonic-gate  * for a logical dev entry, it walks the list of boot-devices and
11997c478bd9Sstevel@tonic-gate  * sees if there are any matches.  If so, it saves the logical device
12007c478bd9Sstevel@tonic-gate  * name off in the appropriate list in dev_list
12017c478bd9Sstevel@tonic-gate  */
1202