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