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